Changeset 284923 in webkit
- Timestamp:
- Oct 27, 2021, 8:34:42 AM (4 years ago)
- Location:
- trunk/Source/JavaScriptCore
- Files:
-
- 14 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/ChangeLog
r284911 r284923 1 2021-10-27 Geza Lore <[email protected]> 2 3 [JSC][32bit] Fix CSR restore on DFG tail calls, add extra register on ARMv7 4 https://bugs.webkit.org/show_bug.cgi?id=230622 5 6 Reviewed by Keith Miller. 7 8 This re-introduces the patch reverted by 9 https://trac.webkit.org/changeset/284911/webkit 10 with the C_LOOP interpreter now fixed. 11 12 The only difference between the original patch and this version is in 13 LowLevelInterpreter32_64.asm and LowLevelInterpreter64.asm, which 14 need the PC base (PB) register restored on C_LOOP on return from a 15 call, as C_LOOP does not seem to handle this as a proper callee save 16 register (CSR). On non C_LOOP builds, the CSR restore mechanism takes 17 care of this, so removed the superfluous instructions. 18 19 --- Original ChangeLog --- 20 21 This patch does two things: 22 23 1. Adds an extra callee save register (CSR) to be available to DFG on 24 ARMv7. To do this properly required the following: 25 26 2. Implements the necessary shuffling in CallFrameShuffler on 32-bit 27 architectures that is required to restore CSRs properly after a tail 28 call on these architectures. This also fixes the remaining failures in 29 the 32-bit build of the unlinked baseline JIT. 30 31 * bytecode/ValueRecovery.cpp: 32 (JSC::ValueRecovery::dumpInContext const): 33 * bytecode/ValueRecovery.h: 34 (JSC::ValueRecovery::calleeSaveRegDisplacedInJSStack): 35 (JSC::ValueRecovery::isInJSStack const): 36 (JSC::ValueRecovery::dataFormat const): 37 (JSC::ValueRecovery::withLocalsOffset const): 38 * dfg/DFGSpeculativeJIT32_64.cpp: 39 (JSC::DFG::SpeculativeJIT::emitCall): 40 * jit/CachedRecovery.cpp: 41 (JSC::CachedRecovery::loadsIntoGPR const): 42 * jit/CallFrameShuffleData.cpp: 43 (JSC::CallFrameShuffleData::setupCalleeSaveRegisters): 44 * jit/CallFrameShuffleData.h: 45 * jit/CallFrameShuffler.cpp: 46 (JSC::CallFrameShuffler::CallFrameShuffler): 47 * jit/CallFrameShuffler.h: 48 (JSC::CallFrameShuffler::snapshot const): 49 (JSC::CallFrameShuffler::addNew): 50 * jit/CallFrameShuffler32_64.cpp: 51 (JSC::CallFrameShuffler::emitLoad): 52 (JSC::CallFrameShuffler::emitDisplace): 53 * jit/GPRInfo.h: 54 (JSC::GPRInfo::toRegister): 55 (JSC::GPRInfo::toIndex): 56 * jit/RegisterSet.cpp: 57 (JSC::RegisterSet::dfgCalleeSaveRegisters): 58 * llint/LowLevelInterpreter32_64.asm: 59 * llint/LowLevelInterpreter64.asm: 60 1 61 2021-10-26 Commit Queue <[email protected]> 2 62 -
trunk/Source/JavaScriptCore/bytecode/ValueRecovery.cpp
r284911 r284923 100 100 out.print("*int32(", virtualRegister(), ")"); 101 101 return; 102 #if USE(JSVALUE32_64) 103 case Int32TagDisplacedInJSStack: 104 out.print("*int32Tag(", virtualRegister(), ")"); 105 return; 106 #endif 102 107 case Int52DisplacedInJSStack: 103 108 out.print("*int52(", virtualRegister(), ")"); -
trunk/Source/JavaScriptCore/bytecode/ValueRecovery.h
r284911 r284923 61 61 // It's in the stack, at a different location, and it's unboxed. 62 62 Int32DisplacedInJSStack, 63 #if USE(JSVALUE32_64) 64 Int32TagDisplacedInJSStack, // int32 stored in tag field 65 #endif 63 66 Int52DisplacedInJSStack, 64 67 StrictInt52DisplacedInJSStack, … … 188 191 return result; 189 192 } 190 193 194 #if USE(JSVALUE32_64) 195 static ValueRecovery calleeSaveRegDisplacedInJSStack(VirtualRegister virtualReg, bool inTag) 196 { 197 ValueRecovery result; 198 UnionType u; 199 u.virtualReg = virtualReg.offset(); 200 result.m_source = WTFMove(u); 201 result.m_technique = inTag ? Int32TagDisplacedInJSStack : Int32DisplacedInJSStack; 202 return result; 203 } 204 #endif 205 191 206 static ValueRecovery constant(JSValue value) 192 207 { … … 259 274 case DisplacedInJSStack: 260 275 case Int32DisplacedInJSStack: 276 #if USE(JSVALUE32_64) 277 case Int32TagDisplacedInJSStack: 278 #endif 261 279 case Int52DisplacedInJSStack: 262 280 case StrictInt52DisplacedInJSStack: … … 283 301 case UnboxedInt32InGPR: 284 302 case Int32DisplacedInJSStack: 303 #if USE(JSVALUE32_64) 304 case Int32TagDisplacedInJSStack: 305 #endif 285 306 return DataFormatInt32; 286 307 case UnboxedInt52InGPR: … … 359 380 case DisplacedInJSStack: 360 381 case Int32DisplacedInJSStack: 382 #if USE(JSVALUE32_64) 383 case Int32TagDisplacedInJSStack: 384 #endif 361 385 case DoubleDisplacedInJSStack: 362 386 case CellDisplacedInJSStack: -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
r284911 r284923 743 743 for (unsigned i = numPassedArgs; i < numAllocatedArgs; ++i) 744 744 shuffleData.args[i] = ValueRecovery::constant(jsUndefined()); 745 746 shuffleData.setupCalleeSaveRegisters(m_jit.codeBlock()); 745 747 } else { 746 748 m_jit.store32(MacroAssembler::TrustedImm32(numPassedArgs), m_jit.calleeFramePayloadSlot(CallFrameSlot::argumentCountIncludingThis)); -
trunk/Source/JavaScriptCore/jit/CachedRecovery.cpp
r284911 r284923 53 53 switch (recovery().technique()) { 54 54 case Int32DisplacedInJSStack: 55 #if USE(JSVALUE64) 55 #if USE(JSVALUE32_64) 56 case Int32TagDisplacedInJSStack: 57 #elif USE(JSVALUE64) 56 58 case Int52DisplacedInJSStack: 57 59 case StrictInt52DisplacedInJSStack: -
trunk/Source/JavaScriptCore/jit/CallFrameShuffleData.cpp
r284911 r284923 34 34 namespace JSC { 35 35 36 #if USE(JSVALUE64)37 38 36 void CallFrameShuffleData::setupCalleeSaveRegisters(CodeBlock* codeBlock) 39 37 { … … 50 48 continue; 51 49 52 VirtualRegister saveSlot { entry.offsetAsIndex() }; 50 int saveSlotIndexInCPURegisters = entry.offsetAsIndex(); 51 52 #if USE(JSVALUE64) 53 // CPU registers are the same size as virtual registers 54 VirtualRegister saveSlot { saveSlotIndexInCPURegisters }; 53 55 registers[entry.reg()] 54 56 = ValueRecovery::displacedInJSStack(saveSlot, DataFormatJS); 57 #elif USE(JSVALUE32_64) 58 // On 32-bit architectures, 2 callee saved registers may be packed into the same slot 59 static_assert(!PayloadOffset || !TagOffset); 60 static_assert(PayloadOffset == 4 || TagOffset == 4); 61 bool inTag = (saveSlotIndexInCPURegisters & 1) == !!TagOffset; 62 if (saveSlotIndexInCPURegisters < 0) 63 saveSlotIndexInCPURegisters -= 1; // Round towards -inf 64 VirtualRegister saveSlot { saveSlotIndexInCPURegisters / 2 }; 65 registers[entry.reg()] 66 = ValueRecovery::calleeSaveRegDisplacedInJSStack(saveSlot, inTag); 67 #endif 55 68 } 56 69 … … 62 75 continue; 63 76 77 #if USE(JSVALUE64) 64 78 registers[reg] = ValueRecovery::inRegister(reg, DataFormatJS); 79 #elif USE(JSVALUE32_64) 80 registers[reg] = ValueRecovery::inRegister(reg, DataFormatInt32); 81 #endif 65 82 } 66 83 } 67 68 #endif // USE(JSVALUE64)69 84 70 85 } // namespace JSC -
trunk/Source/JavaScriptCore/jit/CallFrameShuffleData.h
r284911 r284923 45 45 unsigned numPassedArgs { UINT_MAX }; 46 46 unsigned numParameters { UINT_MAX }; // On our machine frame. 47 RegisterMap<ValueRecovery> registers; 47 48 #if USE(JSVALUE64) 48 RegisterMap<ValueRecovery> registers;49 49 GPRReg numberTagRegister { InvalidGPRReg }; 50 #endif 50 51 51 52 void setupCalleeSaveRegisters(CodeBlock*); 52 53 void setupCalleeSaveRegisters(const RegisterAtOffsetList*); 53 #endif54 54 ValueRecovery callee; 55 55 }; -
trunk/Source/JavaScriptCore/jit/CallFrameShuffler.cpp
r284911 r284923 53 53 m_lockedRegisters.clear(FPRInfo::toRegister(i)); 54 54 55 #if USE(JSVALUE64) 56 // ... as well as the runtime registers on 64-bit architectures. 57 // However do not use these registers on 32-bit architectures since 58 // saving and restoring callee-saved registers in CallFrameShuffler isn't supported 59 // on 32-bit architectures yet. 55 // ... as well as the callee saved registers 60 56 m_lockedRegisters.exclude(RegisterSet::vmCalleeSaveRegisters()); 61 #endif62 57 63 58 ASSERT(!data.callee.isInJSStack() || data.callee.virtualRegister().isLocal()); … … 69 64 } 70 65 71 #if USE(JSVALUE64)72 66 for (Reg reg = Reg::first(); reg <= Reg::last(); reg = reg.next()) { 73 67 if (!data.registers[reg].isSet()) 74 68 continue; 75 69 76 if (reg.isGPR()) 70 if (reg.isGPR()) { 71 #if USE(JSVALUE64) 77 72 addNew(JSValueRegs(reg.gpr()), data.registers[reg]); 78 else 73 #elif USE(JSVALUE32_64) 74 addNew(reg.gpr(), data.registers[reg]); 75 #endif 76 } else 79 77 addNew(reg.fpr(), data.registers[reg]); 80 78 } 81 79 80 #if USE(JSVALUE64) 82 81 m_numberTagRegister = data.numberTagRegister; 83 82 if (m_numberTagRegister != InvalidGPRReg) -
trunk/Source/JavaScriptCore/jit/CallFrameShuffler.h
r284911 r284923 118 118 #if USE(JSVALUE64) 119 119 data.registers[reg] = cachedRecovery->recovery(); 120 #elif USE(JSVALUE32_64) 121 ValueRecovery recovery = cachedRecovery->recovery(); 122 if (recovery.technique() == DisplacedInJSStack) { 123 JSValueRegs wantedJSValueReg = cachedRecovery->wantedJSValueRegs(); 124 ASSERT(reg == wantedJSValueReg.payloadGPR() || reg == wantedJSValueReg.tagGPR()); 125 bool inTag = reg == wantedJSValueReg.tagGPR(); 126 data.registers[reg] = ValueRecovery::calleeSaveRegDisplacedInJSStack(recovery.virtualRegister(), inTag); 127 } else 128 data.registers[reg] = recovery; 120 129 #else 121 130 RELEASE_ASSERT_NOT_REACHED(); … … 665 674 } 666 675 676 #if USE(JSVALUE32_64) 677 void addNew(GPRReg gpr, ValueRecovery recovery) 678 { 679 ASSERT(gpr != InvalidGPRReg && !m_newRegisters[gpr]); 680 ASSERT(recovery.technique() == Int32DisplacedInJSStack 681 || recovery.technique() == Int32TagDisplacedInJSStack); 682 CachedRecovery* cachedRecovery = addCachedRecovery(recovery); 683 if (JSValueRegs oldRegs { cachedRecovery->wantedJSValueRegs() }) { 684 // Combine with the other CSR in the same virtual register slot 685 ASSERT(oldRegs.tagGPR() == InvalidGPRReg); 686 ASSERT(oldRegs.payloadGPR() != InvalidGPRReg && oldRegs.payloadGPR() != gpr); 687 if (recovery.technique() == Int32DisplacedInJSStack) { 688 ASSERT(cachedRecovery->recovery().technique() == Int32TagDisplacedInJSStack); 689 cachedRecovery->setWantedJSValueRegs(JSValueRegs(oldRegs.payloadGPR(), gpr)); 690 } else { 691 ASSERT(cachedRecovery->recovery().technique() == Int32DisplacedInJSStack); 692 cachedRecovery->setWantedJSValueRegs(JSValueRegs(gpr, oldRegs.payloadGPR())); 693 } 694 cachedRecovery->setRecovery( 695 ValueRecovery::displacedInJSStack(recovery.virtualRegister(), DataFormatJS)); 696 } else 697 cachedRecovery->setWantedJSValueRegs(JSValueRegs::payloadOnly(gpr)); 698 m_newRegisters[gpr] = cachedRecovery; 699 } 700 #endif 701 667 702 void addNew(FPRReg fpr, ValueRecovery recovery) 668 703 { -
trunk/Source/JavaScriptCore/jit/CallFrameShuffler32_64.cpp
r284911 r284923 125 125 resultGPR = getFreeGPR(); 126 126 ASSERT(resultGPR != InvalidGPRReg); 127 m_jit.loadPtr(address.withOffset(PayloadOffset), resultGPR); 128 updateRecovery(location, 127 if (location.recovery().technique() == Int32TagDisplacedInJSStack) 128 m_jit.loadPtr(address.withOffset(TagOffset), resultGPR); 129 else 130 m_jit.loadPtr(address.withOffset(PayloadOffset), resultGPR); 131 updateRecovery(location, 129 132 ValueRecovery::inGPR(resultGPR, location.recovery().dataFormat())); 130 133 if (verbose) … … 191 194 ASSERT(!m_lockedRegisters.get(wantedTagGPR)); 192 195 if (CachedRecovery* currentTag { m_registers[wantedTagGPR] }) { 193 if (currentTag == &location) { 194 if (verbose) 195 dataLog(" + ", wantedTagGPR, " is OK\n"); 196 } else { 197 // This can never happen on 32bit platforms since we 198 // have at most one wanted JSValueRegs, for the 199 // callee, and no callee-save registers. 200 RELEASE_ASSERT_NOT_REACHED(); 201 } 196 RELEASE_ASSERT(currentTag == &location); 197 if (verbose) 198 dataLog(" + ", wantedTagGPR, " is OK\n"); 202 199 } 203 200 } … … 206 203 ASSERT(!m_lockedRegisters.get(wantedPayloadGPR)); 207 204 if (CachedRecovery* currentPayload { m_registers[wantedPayloadGPR] }) { 208 if (currentPayload == &location) { 209 if (verbose) 210 dataLog(" + ", wantedPayloadGPR, " is OK\n"); 211 } else { 212 // See above 213 RELEASE_ASSERT_NOT_REACHED(); 214 } 205 RELEASE_ASSERT(currentPayload == &location); 206 if (verbose) 207 dataLog(" + ", wantedPayloadGPR, " is OK\n"); 215 208 } 216 209 } -
trunk/Source/JavaScriptCore/jit/GPRInfo.h
r284911 r284923 554 554 public: 555 555 typedef GPRReg RegisterType; 556 static constexpr unsigned numberOfRegisters = 9;556 static constexpr unsigned numberOfRegisters = 10; 557 557 static constexpr unsigned numberOfArgumentRegisters = NUMBER_OF_ARGUMENT_REGISTERS; 558 558 … … 583 583 { 584 584 ASSERT(index < numberOfRegisters); 585 static const GPRReg registerForIndex[numberOfRegisters] = { regT0, regT1, regT2, regT3, regT4, regT5, regT6, regT7, regCS 1 };585 static const GPRReg registerForIndex[numberOfRegisters] = { regT0, regT1, regT2, regT3, regT4, regT5, regT6, regT7, regCS0, regCS1 }; 586 586 return registerForIndex[index]; 587 587 } … … 599 599 ASSERT(static_cast<int>(reg) < 16); 600 600 static const unsigned indexForRegister[16] = 601 { 0, 1, 2, 3, 7, 6, InvalidIndex, InvalidIndex, 4, 5, 8, InvalidIndex, InvalidIndex, InvalidIndex, InvalidIndex, InvalidIndex };601 { 0, 1, 2, 3, 7, 6, InvalidIndex, InvalidIndex, 4, 5, 9, 8, InvalidIndex, InvalidIndex, InvalidIndex, InvalidIndex }; 602 602 unsigned result = indexForRegister[reg]; 603 603 return result; -
trunk/Source/JavaScriptCore/jit/RegisterSet.cpp
r284911 r284923 255 255 #endif 256 256 #elif CPU(ARM_THUMB2) 257 result.set(GPRInfo::regCS0); 257 258 result.set(GPRInfo::regCS1); 258 259 #elif CPU(ARM64) -
trunk/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm
r284911 r284923 80 80 macro dispatchAfterCall(size, opcodeStruct, valueProfileName, dstVirtualRegister, dispatch) 81 81 loadi ArgumentCountIncludingThis + TagOffset[cfr], PC 82 loadp CodeBlock[cfr], PB 83 loadp CodeBlock::m_instructionsRawPointer[PB], PB 82 if C_LOOP or C_LOOP_WIN 83 # On non C_LOOP builds, CSR restore takes care of this. 84 loadp CodeBlock[cfr], PB 85 loadp CodeBlock::m_instructionsRawPointer[PB], PB 86 end 84 87 get(size, opcodeStruct, dstVirtualRegister, t3) 85 88 storei r1, TagOffset[cfr, t3, 8] -
trunk/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm
r284330 r284923 83 83 macro dispatchAfterCall(size, opcodeStruct, valueProfileName, dstVirtualRegister, dispatch) 84 84 loadPC() 85 loadp CodeBlock[cfr], PB 86 loadp CodeBlock::m_instructionsRawPointer[PB], PB 85 if C_LOOP or C_LOOP_WIN 86 # On non C_LOOP builds, CSR restore takes care of this. 87 loadp CodeBlock[cfr], PB 88 loadp CodeBlock::m_instructionsRawPointer[PB], PB 89 end 87 90 get(size, opcodeStruct, dstVirtualRegister, t1) 88 91 storeq r0, [cfr, t1, 8]
Note:
See TracChangeset
for help on using the changeset viewer.