Diff
Modified: trunk/Source/_javascript_Core/ChangeLog (280577 => 280578)
--- trunk/Source/_javascript_Core/ChangeLog 2021-08-03 01:11:27 UTC (rev 280577)
+++ trunk/Source/_javascript_Core/ChangeLog 2021-08-03 01:45:11 UTC (rev 280578)
@@ -1,5 +1,43 @@
2021-08-02 Yusuke Suzuki <ysuz...@apple.com>
+ [JSC] Use loadPair / storePair in YarrJIT
+ https://bugs.webkit.org/show_bug.cgi?id=228687
+
+ Reviewed by Mark Lam.
+
+ Use loadPair / storePair if possible in YarrJIT. Currently, we are not
+ deploying Spooler in YarrJIT, but we should do that in the future too.
+
+ In this patch, we also add appropriate fallback code in loadPair / storePair:
+ the offset of these functions are small enough so that we should consider
+ overflowing case. If it overflows, we use two loads or stores.
+
+ This patch also adds loadPair32 and storePair32 to all macro assembler so that
+ we can call it without CPU(ARM64). Internally, two loads or stores are combined.
+
+ * assembler/MacroAssemblerARM64.h:
+ (JSC::MacroAssemblerARM64::loadPair32):
+ (JSC::MacroAssemblerARM64::loadPair64):
+ (JSC::MacroAssemblerARM64::loadPair64WithNonTemporalAccess):
+ (JSC::MacroAssemblerARM64::storePair32):
+ (JSC::MacroAssemblerARM64::storePair64):
+ (JSC::MacroAssemblerARM64::storePair64WithNonTemporalAccess):
+ * assembler/MacroAssemblerARMv7.h:
+ (JSC::MacroAssemblerARMv7::loadPair32):
+ (JSC::MacroAssemblerARMv7::storePair32):
+ * assembler/MacroAssemblerMIPS.h:
+ (JSC::MacroAssemblerMIPS::loadPair32):
+ (JSC::MacroAssemblerMIPS::storePair32):
+ * assembler/MacroAssemblerX86Common.h:
+ (JSC::MacroAssemblerX86Common::loadPair32):
+ (JSC::MacroAssemblerX86Common::storePair32):
+ * assembler/testmasm.cpp:
+ (JSC::testLoadStorePair32):
+ (JSC::testLoadStorePair64Int64):
+ * yarr/YarrJIT.cpp:
+
+2021-08-02 Yusuke Suzuki <ysuz...@apple.com>
+
Unreviewed, fix accidental narrowing
https://bugs.webkit.org/show_bug.cgi?id=228613
Modified: trunk/Source/_javascript_Core/assembler/MacroAssemblerARM64.h (280577 => 280578)
--- trunk/Source/_javascript_Core/assembler/MacroAssemblerARM64.h 2021-08-03 01:11:27 UTC (rev 280577)
+++ trunk/Source/_javascript_Core/assembler/MacroAssemblerARM64.h 2021-08-03 01:45:11 UTC (rev 280578)
@@ -1473,6 +1473,27 @@
return label;
}
+ void loadPair32(RegisterID src, RegisterID dest1, RegisterID dest2)
+ {
+ loadPair32(src, TrustedImm32(0), dest1, dest2);
+ }
+
+ void loadPair32(RegisterID src, TrustedImm32 offset, RegisterID dest1, RegisterID dest2)
+ {
+ ASSERT(dest1 != dest2); // If it is the same, ldp becomes illegal instruction.
+ if (ARM64Assembler::isValidLDPImm<32>(offset.m_value)) {
+ m_assembler.ldp<32>(dest1, dest2, src, offset.m_value);
+ return;
+ }
+ if (src == dest1) {
+ load32(Address(src, offset.m_value + 4), dest2);
+ load32(Address(src, offset.m_value), dest1);
+ } else {
+ load32(Address(src, offset.m_value), dest1);
+ load32(Address(src, offset.m_value + 4), dest2);
+ }
+ }
+
void loadPair64(RegisterID src, RegisterID dest1, RegisterID dest2)
{
loadPair64(src, TrustedImm32(0), dest1, dest2);
@@ -1480,7 +1501,18 @@
void loadPair64(RegisterID src, TrustedImm32 offset, RegisterID dest1, RegisterID dest2)
{
- m_assembler.ldp<64>(dest1, dest2, src, offset.m_value);
+ ASSERT(dest1 != dest2); // If it is the same, ldp becomes illegal instruction.
+ if (ARM64Assembler::isValidLDPImm<64>(offset.m_value)) {
+ m_assembler.ldp<64>(dest1, dest2, src, offset.m_value);
+ return;
+ }
+ if (src == dest1) {
+ load64(Address(src, offset.m_value + 8), dest2);
+ load64(Address(src, offset.m_value), dest1);
+ } else {
+ load64(Address(src, offset.m_value), dest1);
+ load64(Address(src, offset.m_value + 8), dest2);
+ }
}
void loadPair64WithNonTemporalAccess(RegisterID src, RegisterID dest1, RegisterID dest2)
@@ -1490,7 +1522,18 @@
void loadPair64WithNonTemporalAccess(RegisterID src, TrustedImm32 offset, RegisterID dest1, RegisterID dest2)
{
- m_assembler.ldnp<64>(dest1, dest2, src, offset.m_value);
+ ASSERT(dest1 != dest2); // If it is the same, ldp becomes illegal instruction.
+ if (ARM64Assembler::isValidLDPImm<64>(offset.m_value)) {
+ m_assembler.ldnp<64>(dest1, dest2, src, offset.m_value);
+ return;
+ }
+ if (src == dest1) {
+ load64(Address(src, offset.m_value + 8), dest2);
+ load64(Address(src, offset.m_value), dest1);
+ } else {
+ load64(Address(src, offset.m_value), dest1);
+ load64(Address(src, offset.m_value + 8), dest2);
+ }
}
void loadPair64(RegisterID src, FPRegisterID dest1, FPRegisterID dest2)
@@ -1500,7 +1543,13 @@
void loadPair64(RegisterID src, TrustedImm32 offset, FPRegisterID dest1, FPRegisterID dest2)
{
- m_assembler.ldp<64>(dest1, dest2, src, offset.m_value);
+ ASSERT(dest1 != dest2); // If it is the same, ldp becomes illegal instruction.
+ if (ARM64Assembler::isValidLDPFPImm<64>(offset.m_value)) {
+ m_assembler.ldp<64>(dest1, dest2, src, offset.m_value);
+ return;
+ }
+ loadDouble(Address(src, offset.m_value), dest1);
+ loadDouble(Address(src, offset.m_value + 8), dest2);
}
void abortWithReason(AbortReason reason)
@@ -1824,6 +1873,21 @@
return label;
}
+ void storePair32(RegisterID src1, RegisterID src2, RegisterID dest)
+ {
+ storePair32(src1, src2, dest, TrustedImm32(0));
+ }
+
+ void storePair32(RegisterID src1, RegisterID src2, RegisterID dest, TrustedImm32 offset)
+ {
+ if (ARM64Assembler::isValidSTPImm<32>(offset.m_value)) {
+ m_assembler.stp<32>(src1, src2, dest, offset.m_value);
+ return;
+ }
+ store32(src1, Address(dest, offset.m_value));
+ store32(src2, Address(dest, offset.m_value + 4));
+ }
+
void storePair64(RegisterID src1, RegisterID src2, RegisterID dest)
{
storePair64(src1, src2, dest, TrustedImm32(0));
@@ -1831,7 +1895,12 @@
void storePair64(RegisterID src1, RegisterID src2, RegisterID dest, TrustedImm32 offset)
{
- m_assembler.stp<64>(src1, src2, dest, offset.m_value);
+ if (ARM64Assembler::isValidSTPImm<64>(offset.m_value)) {
+ m_assembler.stp<64>(src1, src2, dest, offset.m_value);
+ return;
+ }
+ store64(src1, Address(dest, offset.m_value));
+ store64(src2, Address(dest, offset.m_value + 8));
}
void storePair64WithNonTemporalAccess(RegisterID src1, RegisterID src2, RegisterID dest)
@@ -1841,7 +1910,12 @@
void storePair64WithNonTemporalAccess(RegisterID src1, RegisterID src2, RegisterID dest, TrustedImm32 offset)
{
- m_assembler.stnp<64>(src1, src2, dest, offset.m_value);
+ if (ARM64Assembler::isValidSTPImm<64>(offset.m_value)) {
+ m_assembler.stnp<64>(src1, src2, dest, offset.m_value);
+ return;
+ }
+ store64(src1, Address(dest, offset.m_value));
+ store64(src2, Address(dest, offset.m_value + 8));
}
void storePair64(FPRegisterID src1, FPRegisterID src2, RegisterID dest)
@@ -1851,7 +1925,12 @@
void storePair64(FPRegisterID src1, FPRegisterID src2, RegisterID dest, TrustedImm32 offset)
{
- m_assembler.stp<64>(src1, src2, dest, offset.m_value);
+ if (ARM64Assembler::isValidSTPFPImm<64>(offset.m_value)) {
+ m_assembler.stp<64>(src1, src2, dest, offset.m_value);
+ return;
+ }
+ storeDouble(src1, Address(dest, offset.m_value));
+ storeDouble(src2, Address(dest, offset.m_value + 8));
}
void store32(RegisterID src, ImplicitAddress address)
Modified: trunk/Source/_javascript_Core/assembler/MacroAssemblerARMv7.h (280577 => 280578)
--- trunk/Source/_javascript_Core/assembler/MacroAssemblerARMv7.h 2021-08-03 01:11:27 UTC (rev 280577)
+++ trunk/Source/_javascript_Core/assembler/MacroAssemblerARMv7.h 2021-08-03 01:45:11 UTC (rev 280578)
@@ -867,6 +867,24 @@
UNREACHABLE_FOR_PLATFORM();
}
+ void loadPair32(RegisterID src, RegisterID dest1, RegisterID dest2)
+ {
+ loadPair32(src, TrustedImm32(0), dest1, dest2);
+ }
+
+ void loadPair32(RegisterID src, TrustedImm32 offset, RegisterID dest1, RegisterID dest2)
+ {
+ // FIXME: ldrd/ldm can be used if dest1 and dest2 are consecutive pair of registers.
+ ASSERT(dest1 != dest2); // If it is the same, ldp becomes illegal instruction.
+ if (src == dest1) {
+ load32(Address(src, offset.m_value + 4), dest2);
+ load32(Address(src, offset.m_value), dest1);
+ } else {
+ load32(Address(src, offset.m_value), dest1);
+ load32(Address(src, offset.m_value + 4), dest2);
+ }
+ }
+
DataLabel32 store32WithAddressOffsetPatch(RegisterID src, Address address)
{
DataLabel32 label = moveWithPatch(TrustedImm32(address.offset), dataTempRegister);
@@ -965,6 +983,18 @@
store16(dataTempRegister, address);
}
+ void storePair32(RegisterID src1, RegisterID src2, RegisterID dest)
+ {
+ storePair32(src1, src2, dest, TrustedImm32(0));
+ }
+
+ void storePair32(RegisterID src1, RegisterID src2, RegisterID dest, TrustedImm32 offset)
+ {
+ // FIXME: strd/stm can be used if src1 and src2 are consecutive pair of registers.
+ store32(src1, Address(dest, offset.m_value));
+ store32(src2, Address(dest, offset.m_value + 4));
+ }
+
// Possibly clobbers src, but not on this architecture.
void moveDoubleToInts(FPRegisterID src, RegisterID dest1, RegisterID dest2)
{
Modified: trunk/Source/_javascript_Core/assembler/MacroAssemblerMIPS.h (280577 => 280578)
--- trunk/Source/_javascript_Core/assembler/MacroAssemblerMIPS.h 2021-08-03 01:11:27 UTC (rev 280577)
+++ trunk/Source/_javascript_Core/assembler/MacroAssemblerMIPS.h 2021-08-03 01:45:11 UTC (rev 280578)
@@ -1293,6 +1293,23 @@
}
}
+ void loadPair32(RegisterID src, RegisterID dest1, RegisterID dest2)
+ {
+ loadPair32(src, TrustedImm32(0), dest1, dest2);
+ }
+
+ void loadPair32(RegisterID src, TrustedImm32 offset, RegisterID dest1, RegisterID dest2)
+ {
+ ASSERT(dest1 != dest2); // If it is the same, ldp becomes illegal instruction.
+ if (src == dest1) {
+ load32(Address(src, offset.m_value + 4), dest2);
+ load32(Address(src, offset.m_value), dest1);
+ } else {
+ load32(Address(src, offset.m_value), dest1);
+ load32(Address(src, offset.m_value + 4), dest2);
+ }
+ }
+
DataLabel32 store32WithAddressOffsetPatch(RegisterID src, Address address)
{
m_fixedWidth = true;
@@ -1586,6 +1603,17 @@
}
}
+ void storePair32(RegisterID src1, RegisterID src2, RegisterID dest)
+ {
+ storePair32(src1, src2, dest, TrustedImm32(0));
+ }
+
+ void storePair32(RegisterID src1, RegisterID src2, RegisterID dest, TrustedImm32 offset)
+ {
+ store32(src1, Address(dest, offset.m_value));
+ store32(src2, Address(dest, offset.m_value + 4));
+ }
+
// Floating-point operations:
static bool supportsFloatingPoint()
Modified: trunk/Source/_javascript_Core/assembler/MacroAssemblerX86Common.h (280577 => 280578)
--- trunk/Source/_javascript_Core/assembler/MacroAssemblerX86Common.h 2021-08-03 01:11:27 UTC (rev 280577)
+++ trunk/Source/_javascript_Core/assembler/MacroAssemblerX86Common.h 2021-08-03 01:45:11 UTC (rev 280578)
@@ -1300,6 +1300,23 @@
m_assembler.movswl_mr(address.offset, address.base, dest);
}
+ void loadPair32(RegisterID src, RegisterID dest1, RegisterID dest2)
+ {
+ loadPair32(src, TrustedImm32(0), dest1, dest2);
+ }
+
+ void loadPair32(RegisterID src, TrustedImm32 offset, RegisterID dest1, RegisterID dest2)
+ {
+ ASSERT(dest1 != dest2); // If it is the same, ldp becomes illegal instruction.
+ if (src == dest1) {
+ load32(Address(src, offset.m_value + 4), dest2);
+ load32(Address(src, offset.m_value), dest1);
+ } else {
+ load32(Address(src, offset.m_value), dest1);
+ load32(Address(src, offset.m_value + 4), dest2);
+ }
+ }
+
void zeroExtend16To32(RegisterID src, RegisterID dest)
{
m_assembler.movzwl_rr(src, dest);
@@ -1349,6 +1366,17 @@
m_assembler.movb_i8m(imm8.m_value, address.offset, address.base, address.index, address.scale);
}
+ void storePair32(RegisterID src1, RegisterID src2, RegisterID dest)
+ {
+ storePair32(src1, src2, dest, TrustedImm32(0));
+ }
+
+ void storePair32(RegisterID src1, RegisterID src2, RegisterID dest, TrustedImm32 offset)
+ {
+ store32(src1, Address(dest, offset.m_value));
+ store32(src2, Address(dest, offset.m_value + 4));
+ }
+
static ALWAYS_INLINE RegisterID getUnusedRegister(BaseIndex address)
{
if (address.base != X86Registers::eax && address.index != X86Registers::eax)
Modified: trunk/Source/_javascript_Core/assembler/testmasm.cpp (280577 => 280578)
--- trunk/Source/_javascript_Core/assembler/testmasm.cpp 2021-08-03 01:11:27 UTC (rev 280577)
+++ trunk/Source/_javascript_Core/assembler/testmasm.cpp 2021-08-03 01:45:11 UTC (rev 280578)
@@ -3236,6 +3236,245 @@
#endif // CPU(ARM64)
+void testLoadStorePair32()
+{
+ constexpr uint32_t initialValue = 0x55aabb80u;
+ constexpr uint32_t value1 = 42;
+ constexpr uint32_t value2 = 0xcfbb1357u;
+
+ uint32_t buffer[10];
+
+ auto initBuffer = [&] {
+ for (unsigned i = 0; i < 10; ++i)
+ buffer[i] = initialValue + i;
+ };
+
+ struct Pair {
+ uint32_t value1;
+ uint32_t value2;
+ };
+
+ Pair pair;
+ auto initPair = [&] {
+ pair = { 0, 0 };
+ };
+
+ // Test loadPair32.
+ auto testLoadPair = [] (CCallHelpers& jit, int offset) {
+ emitFunctionPrologue(jit);
+
+ constexpr GPRReg bufferGPR = GPRInfo::argumentGPR0;
+ constexpr GPRReg pairGPR = GPRInfo::argumentGPR1;
+ jit.loadPair32(bufferGPR, CCallHelpers::TrustedImm32(offset * sizeof(uint32_t)), GPRInfo::regT2, GPRInfo::regT3);
+
+ jit.store32(GPRInfo::regT2, CCallHelpers::Address(pairGPR, 0));
+ jit.store32(GPRInfo::regT3, CCallHelpers::Address(pairGPR, sizeof(uint32_t)));
+
+ emitFunctionEpilogue(jit);
+ jit.ret();
+ };
+
+ auto testLoadPair0 = compile([&] (CCallHelpers& jit) {
+ testLoadPair(jit, 0);
+ });
+
+ initBuffer();
+
+ initPair();
+ invoke<void>(testLoadPair0, &buffer[4], &pair);
+ CHECK_EQ(pair.value1, initialValue + 4);
+ CHECK_EQ(pair.value2, initialValue + 5);
+
+ initPair();
+ buffer[4] = value1;
+ buffer[5] = value2;
+ invoke<void>(testLoadPair0, &buffer[4], &pair);
+ CHECK_EQ(pair.value1, value1);
+ CHECK_EQ(pair.value2, value2);
+
+ auto testLoadPairMinus2 = compile([&] (CCallHelpers& jit) {
+ testLoadPair(jit, -2);
+ });
+
+ initPair();
+ invoke<void>(testLoadPairMinus2, &buffer[4], &pair);
+ CHECK_EQ(pair.value1, initialValue + 4 - 2);
+ CHECK_EQ(pair.value2, initialValue + 5 - 2);
+
+ initPair();
+ buffer[4 - 2] = value2;
+ buffer[5 - 2] = value1;
+ invoke<void>(testLoadPairMinus2, &buffer[4], &pair);
+ CHECK_EQ(pair.value1, value2);
+ CHECK_EQ(pair.value2, value1);
+
+ auto testLoadPairPlus3 = compile([&] (CCallHelpers& jit) {
+ testLoadPair(jit, 3);
+ });
+
+ initPair();
+ invoke<void>(testLoadPairPlus3, &buffer[4], &pair);
+ CHECK_EQ(pair.value1, initialValue + 4 + 3);
+ CHECK_EQ(pair.value2, initialValue + 5 + 3);
+
+ initPair();
+ buffer[4 + 3] = value1;
+ buffer[5 + 3] = value2;
+ invoke<void>(testLoadPairPlus3, &buffer[4], &pair);
+ CHECK_EQ(pair.value1, value1);
+ CHECK_EQ(pair.value2, value2);
+
+ // Test loadPair32 using a buffer register as a destination.
+ auto testLoadPairUsingBufferRegisterAsDestination = [] (CCallHelpers& jit, int offset) {
+ emitFunctionPrologue(jit);
+
+ constexpr GPRReg bufferGPR = GPRInfo::argumentGPR0;
+ constexpr GPRReg pairGPR = GPRInfo::argumentGPR1;
+ jit.loadPair32(bufferGPR, CCallHelpers::TrustedImm32(offset * sizeof(uint32_t)), GPRInfo::argumentGPR0, GPRInfo::regT2);
+
+ jit.store32(GPRInfo::argumentGPR0, CCallHelpers::Address(pairGPR, 0));
+ jit.store32(GPRInfo::regT2, CCallHelpers::Address(pairGPR, sizeof(uint32_t)));
+
+ emitFunctionEpilogue(jit);
+ jit.ret();
+ };
+
+ auto testLoadPairUsingBufferRegisterAsDestination0 = compile([&] (CCallHelpers& jit) {
+ testLoadPairUsingBufferRegisterAsDestination(jit, 0);
+ });
+
+ initBuffer();
+
+ initPair();
+ invoke<void>(testLoadPairUsingBufferRegisterAsDestination0, &buffer[4], &pair);
+ CHECK_EQ(pair.value1, initialValue + 4);
+ CHECK_EQ(pair.value2, initialValue + 5);
+
+ // Test storePair32.
+ auto testStorePair = [] (CCallHelpers& jit, int offset) {
+ emitFunctionPrologue(jit);
+
+ constexpr GPRReg bufferGPR = GPRInfo::argumentGPR2;
+ jit.storePair32(GPRInfo::argumentGPR0, GPRInfo::argumentGPR1, bufferGPR, CCallHelpers::TrustedImm32(offset * sizeof(unsigned)));
+
+ emitFunctionEpilogue(jit);
+ jit.ret();
+ };
+
+ auto testStorePair0 = compile([&] (CCallHelpers& jit) {
+ testStorePair(jit, 0);
+ });
+
+ initBuffer();
+ invoke<void>(testStorePair0, value1, value2, &buffer[4]);
+ CHECK_EQ(buffer[0], initialValue + 0);
+ CHECK_EQ(buffer[1], initialValue + 1);
+ CHECK_EQ(buffer[2], initialValue + 2);
+ CHECK_EQ(buffer[3], initialValue + 3);
+ CHECK_EQ(buffer[4], value1);
+ CHECK_EQ(buffer[5], value2);
+ CHECK_EQ(buffer[6], initialValue + 6);
+ CHECK_EQ(buffer[7], initialValue + 7);
+ CHECK_EQ(buffer[8], initialValue + 8);
+ CHECK_EQ(buffer[9], initialValue + 9);
+
+ auto testStorePairMinus2 = compile([&] (CCallHelpers& jit) {
+ testStorePair(jit, -2);
+ });
+
+ initBuffer();
+ invoke<void>(testStorePairMinus2, value1, value2, &buffer[4]);
+ CHECK_EQ(buffer[0], initialValue + 0);
+ CHECK_EQ(buffer[1], initialValue + 1);
+ CHECK_EQ(buffer[2], value1);
+ CHECK_EQ(buffer[3], value2);
+ CHECK_EQ(buffer[4], initialValue + 4);
+ CHECK_EQ(buffer[5], initialValue + 5);
+ CHECK_EQ(buffer[6], initialValue + 6);
+ CHECK_EQ(buffer[7], initialValue + 7);
+ CHECK_EQ(buffer[8], initialValue + 8);
+ CHECK_EQ(buffer[9], initialValue + 9);
+
+ auto testStorePairPlus3 = compile([&] (CCallHelpers& jit) {
+ testStorePair(jit, 3);
+ });
+
+ initBuffer();
+ invoke<void>(testStorePairPlus3, value1, value2, &buffer[4]);
+ CHECK_EQ(buffer[0], initialValue + 0);
+ CHECK_EQ(buffer[1], initialValue + 1);
+ CHECK_EQ(buffer[2], initialValue + 2);
+ CHECK_EQ(buffer[3], initialValue + 3);
+ CHECK_EQ(buffer[4], initialValue + 4);
+ CHECK_EQ(buffer[5], initialValue + 5);
+ CHECK_EQ(buffer[6], initialValue + 6);
+ CHECK_EQ(buffer[7], value1);
+ CHECK_EQ(buffer[8], value2);
+ CHECK_EQ(buffer[9], initialValue + 9);
+
+ // Test storePair32 from 1 register.
+ auto testStorePairFromOneReg = [] (CCallHelpers& jit, int offset) {
+ emitFunctionPrologue(jit);
+
+ constexpr GPRReg bufferGPR = GPRInfo::argumentGPR1;
+ jit.storePair32(GPRInfo::argumentGPR0, GPRInfo::argumentGPR0, bufferGPR, CCallHelpers::TrustedImm32(offset * sizeof(unsigned)));
+
+ emitFunctionEpilogue(jit);
+ jit.ret();
+ };
+
+ auto testStorePairFromOneReg0 = compile([&] (CCallHelpers& jit) {
+ testStorePairFromOneReg(jit, 0);
+ });
+
+ initBuffer();
+ invoke<void>(testStorePairFromOneReg0, value2, &buffer[4]);
+ CHECK_EQ(buffer[0], initialValue + 0);
+ CHECK_EQ(buffer[1], initialValue + 1);
+ CHECK_EQ(buffer[2], initialValue + 2);
+ CHECK_EQ(buffer[3], initialValue + 3);
+ CHECK_EQ(buffer[4], value2);
+ CHECK_EQ(buffer[5], value2);
+ CHECK_EQ(buffer[6], initialValue + 6);
+ CHECK_EQ(buffer[7], initialValue + 7);
+ CHECK_EQ(buffer[8], initialValue + 8);
+ CHECK_EQ(buffer[9], initialValue + 9);
+
+ auto testStorePairFromOneRegMinus2 = compile([&] (CCallHelpers& jit) {
+ testStorePairFromOneReg(jit, -2);
+ });
+
+ initBuffer();
+ invoke<void>(testStorePairFromOneRegMinus2, value1, &buffer[4]);
+ CHECK_EQ(buffer[0], initialValue + 0);
+ CHECK_EQ(buffer[1], initialValue + 1);
+ CHECK_EQ(buffer[2], value1);
+ CHECK_EQ(buffer[3], value1);
+ CHECK_EQ(buffer[4], initialValue + 4);
+ CHECK_EQ(buffer[5], initialValue + 5);
+ CHECK_EQ(buffer[6], initialValue + 6);
+ CHECK_EQ(buffer[7], initialValue + 7);
+ CHECK_EQ(buffer[8], initialValue + 8);
+ CHECK_EQ(buffer[9], initialValue + 9);
+
+ auto testStorePairFromOneRegPlus3 = compile([&] (CCallHelpers& jit) {
+ testStorePairFromOneReg(jit, 3);
+ });
+
+ initBuffer();
+ invoke<void>(testStorePairFromOneRegPlus3, value2, &buffer[4]);
+ CHECK_EQ(buffer[0], initialValue + 0);
+ CHECK_EQ(buffer[1], initialValue + 1);
+ CHECK_EQ(buffer[2], initialValue + 2);
+ CHECK_EQ(buffer[3], initialValue + 3);
+ CHECK_EQ(buffer[4], initialValue + 4);
+ CHECK_EQ(buffer[5], initialValue + 5);
+ CHECK_EQ(buffer[6], initialValue + 6);
+ CHECK_EQ(buffer[7], value2);
+ CHECK_EQ(buffer[8], value2);
+ CHECK_EQ(buffer[9], initialValue + 9);
+}
+
#if CPU(ARM64)
void testLoadStorePair64Int64()
{
@@ -3325,6 +3564,32 @@
CHECK_EQ(pair.value1, value1);
CHECK_EQ(pair.value2, value2);
+ // Test loadPair64 using a buffer register as a destination.
+ auto testLoadPairUsingBufferRegisterAsDestination = [] (CCallHelpers& jit, int offset) {
+ emitFunctionPrologue(jit);
+
+ constexpr GPRReg bufferGPR = GPRInfo::argumentGPR0;
+ constexpr GPRReg pairGPR = GPRInfo::argumentGPR1;
+ jit.loadPair64(bufferGPR, CCallHelpers::TrustedImm32(offset * sizeof(CPURegister)), GPRInfo::argumentGPR0, GPRInfo::regT2);
+
+ jit.store64(GPRInfo::argumentGPR0, CCallHelpers::Address(pairGPR, 0));
+ jit.store64(GPRInfo::regT2, CCallHelpers::Address(pairGPR, sizeof(uint64_t)));
+
+ emitFunctionEpilogue(jit);
+ jit.ret();
+ };
+
+ auto testLoadPairUsingBufferRegisterAsDestination0 = compile([&] (CCallHelpers& jit) {
+ testLoadPairUsingBufferRegisterAsDestination(jit, 0);
+ });
+
+ initBuffer();
+
+ initPair();
+ invoke<void>(testLoadPairUsingBufferRegisterAsDestination0, &buffer[4], &pair);
+ CHECK_EQ(pair.value1, initialValue + 4);
+ CHECK_EQ(pair.value2, initialValue + 5);
+
// Test storePair64.
auto testStorePair = [] (CCallHelpers& jit, int offset) {
emitFunctionPrologue(jit);
@@ -4891,6 +5156,7 @@
FOR_EACH_DOUBLE_CONDITION_RUN(testCompareDoubleSameArg);
RUN(testMul32WithImmediates());
+ RUN(testLoadStorePair32());
#if CPU(X86_64)
RUN(testBranchTestBit32RegReg());
Modified: trunk/Source/_javascript_Core/yarr/YarrJIT.cpp (280577 => 280578)
--- trunk/Source/_javascript_Core/yarr/YarrJIT.cpp 2021-08-03 01:11:27 UTC (rev 280577)
+++ trunk/Source/_javascript_Core/yarr/YarrJIT.cpp 2021-08-03 01:45:11 UTC (rev 280578)
@@ -299,8 +299,10 @@
struct ParenContext {
struct ParenContext* next;
- uint32_t begin;
- uint32_t matchAmount;
+ struct BeginAndMatchAmount {
+ uint32_t begin;
+ uint32_t matchAmount;
+ } beginAndMatchAmount;
uintptr_t returnAddress;
struct Subpatterns {
unsigned start;
@@ -313,27 +315,27 @@
return sizeof(ParenContext) + sizeof(Subpatterns) * parenContextSizes.numSubpatterns() + sizeof(uintptr_t) * parenContextSizes.frameSlots();
}
- static ptrdiff_t nextOffset()
+ static constexpr ptrdiff_t nextOffset()
{
return offsetof(ParenContext, next);
}
- static ptrdiff_t beginOffset()
+ static constexpr ptrdiff_t beginOffset()
{
- return offsetof(ParenContext, begin);
+ return offsetof(ParenContext, beginAndMatchAmount) + offsetof(BeginAndMatchAmount, begin);
}
- static ptrdiff_t matchAmountOffset()
+ static constexpr ptrdiff_t matchAmountOffset()
{
- return offsetof(ParenContext, matchAmount);
+ return offsetof(ParenContext, beginAndMatchAmount) + offsetof(BeginAndMatchAmount, matchAmount);
}
- static ptrdiff_t returnAddressOffset()
+ static constexpr ptrdiff_t returnAddressOffset()
{
return offsetof(ParenContext, returnAddress);
}
- static ptrdiff_t subpatternOffset(size_t subpattern)
+ static constexpr ptrdiff_t subpatternOffset(size_t subpattern)
{
return offsetof(ParenContext, subpatterns) + (subpattern - 1) * sizeof(Subpatterns);
}
@@ -395,17 +397,30 @@
move(headPtrRegister, freelistRegister);
}
+
+ void storeBeginAndMatchAmountToParenContext(RegisterID beginGPR, RegisterID matchAmountGPR, RegisterID parenContextGPR)
+ {
+ static_assert(ParenContext::beginOffset() + 4 == ParenContext::matchAmountOffset());
+ storePair32(beginGPR, matchAmountGPR, parenContextGPR, TrustedImm32(ParenContext::beginOffset()));
+ }
+
+ void loadBeginAndMatchAmountFromParenContext(RegisterID parenContextGPR, RegisterID beginGPR, RegisterID matchAmountGPR)
+ {
+ static_assert(ParenContext::beginOffset() + 4 == ParenContext::matchAmountOffset());
+ loadPair32(parenContextGPR, TrustedImm32(ParenContext::beginOffset()), beginGPR, matchAmountGPR);
+ }
+
void saveParenContext(RegisterID parenContextReg, RegisterID tempReg, unsigned firstSubpattern, unsigned lastSubpattern, unsigned subpatternBaseFrameLocation)
{
- store32(index, Address(parenContextReg, ParenContext::beginOffset()));
loadFromFrame(subpatternBaseFrameLocation + BackTrackInfoParentheses::matchAmountIndex(), tempReg);
- store32(tempReg, Address(parenContextReg, ParenContext::matchAmountOffset()));
+ storeBeginAndMatchAmountToParenContext(index, tempReg, parenContextReg);
loadFromFrame(subpatternBaseFrameLocation + BackTrackInfoParentheses::returnAddressIndex(), tempReg);
storePtr(tempReg, Address(parenContextReg, ParenContext::returnAddressOffset()));
if (m_compileMode == JITCompileMode::IncludeSubpatterns) {
for (unsigned subpattern = firstSubpattern; subpattern <= lastSubpattern; subpattern++) {
- loadPtr(Address(output, (subpattern << 1) * sizeof(unsigned)), tempReg);
- storePtr(tempReg, Address(parenContextReg, ParenContext::subpatternOffset(subpattern)));
+ static_assert(is64Bit());
+ load64(Address(output, (subpattern << 1) * sizeof(unsigned)), tempReg);
+ store64(tempReg, Address(parenContextReg, ParenContext::subpatternOffset(subpattern)));
clearSubpatternStart(subpattern);
}
}
@@ -418,16 +433,16 @@
void restoreParenContext(RegisterID parenContextReg, RegisterID tempReg, unsigned firstSubpattern, unsigned lastSubpattern, unsigned subpatternBaseFrameLocation)
{
- load32(Address(parenContextReg, ParenContext::beginOffset()), index);
+ loadBeginAndMatchAmountFromParenContext(parenContextReg, index, tempReg);
storeToFrame(index, subpatternBaseFrameLocation + BackTrackInfoParentheses::beginIndex());
- load32(Address(parenContextReg, ParenContext::matchAmountOffset()), tempReg);
storeToFrame(tempReg, subpatternBaseFrameLocation + BackTrackInfoParentheses::matchAmountIndex());
loadPtr(Address(parenContextReg, ParenContext::returnAddressOffset()), tempReg);
storeToFrame(tempReg, subpatternBaseFrameLocation + BackTrackInfoParentheses::returnAddressIndex());
if (m_compileMode == JITCompileMode::IncludeSubpatterns) {
for (unsigned subpattern = firstSubpattern; subpattern <= lastSubpattern; subpattern++) {
- loadPtr(Address(parenContextReg, ParenContext::subpatternOffset(subpattern)), tempReg);
- storePtr(tempReg, Address(output, (subpattern << 1) * sizeof(unsigned)));
+ static_assert(is64Bit());
+ load64(Address(parenContextReg, ParenContext::subpatternOffset(subpattern)), tempReg);
+ store64(tempReg, Address(output, (subpattern << 1) * sizeof(unsigned)));
}
}
subpatternBaseFrameLocation += YarrStackSpaceForBackTrackInfoParentheses;
@@ -1296,8 +1311,7 @@
JumpList matches;
if (term->quantityType != QuantifierType::NonGreedy) {
- load32(Address(output, (subpatternId << 1) * sizeof(int)), patternIndex);
- load32(Address(output, ((subpatternId << 1) + 1) * sizeof(int)), patternTemp);
+ loadSubPattern(output, subpatternId, patternIndex, patternTemp);
// An empty match is successful without consuming characters
if (term->quantityType != QuantifierType::FixedCount || term->quantityMaxCount != 1) {
@@ -1328,8 +1342,7 @@
add32(TrustedImm32(1), characterOrTemp);
storeToFrame(characterOrTemp, parenthesesFrameLocation + BackTrackInfoBackReference::matchAmountIndex());
matches.append(branch32(Equal, Imm32(term->quantityMaxCount), characterOrTemp));
- load32(Address(output, (subpatternId << 1) * sizeof(int)), patternIndex);
- load32(Address(output, ((subpatternId << 1) + 1) * sizeof(int)), patternTemp);
+ loadSubPattern(output, subpatternId, patternIndex, patternTemp);
jump(outerLoop);
}
matches.link(this);
@@ -1352,8 +1365,7 @@
storeToFrame(characterOrTemp, parenthesesFrameLocation + BackTrackInfoBackReference::matchAmountIndex());
if (term->quantityMaxCount != quantifyInfinite)
matches.append(branch32(Equal, Imm32(term->quantityMaxCount), characterOrTemp));
- load32(Address(output, (subpatternId << 1) * sizeof(int)), patternIndex);
- load32(Address(output, ((subpatternId << 1) + 1) * sizeof(int)), patternTemp);
+ loadSubPattern(output, subpatternId, patternIndex, patternTemp);
// Store current index in frame for restoring after a partial match
storeToFrame(index, parenthesesFrameLocation + BackTrackInfoBackReference::beginIndex());
@@ -1374,8 +1386,7 @@
op.m_reentry = label();
- load32(Address(output, (subpatternId << 1) * sizeof(int)), patternIndex);
- load32(Address(output, ((subpatternId << 1) + 1) * sizeof(int)), patternTemp);
+ loadSubPattern(output, subpatternId, patternIndex, patternTemp);
// An empty match is successful without consuming characters
Jump zeroLengthMatch = branch32(Equal, TrustedImm32(-1), patternIndex);
@@ -1429,8 +1440,7 @@
loadFromFrame(parenthesesFrameLocation + BackTrackInfoBackReference::matchAmountIndex(), matchAmount);
failures.append(branchTest32(Zero, matchAmount));
- load32(Address(output, (subpatternId << 1) * sizeof(int)), patternStartIndex);
- load32(Address(output, ((subpatternId << 1) + 1) * sizeof(int)), patternEndIndexOrLen);
+ loadSubPattern(output, subpatternId, patternStartIndex, patternEndIndexOrLen);
sub32(patternStartIndex, patternEndIndexOrLen);
sub32(patternEndIndexOrLen, index);
@@ -2515,11 +2525,12 @@
if (priorAlternative->m_minimumSize)
sub32(Imm32(priorAlternative->m_minimumSize), returnRegister);
if (m_compileMode == JITCompileMode::IncludeSubpatterns)
- store32(returnRegister, output);
- } else
+ storePair32(returnRegister, index, output, TrustedImm32(0));
+ } else {
getMatchStart(returnRegister);
- if (m_compileMode == JITCompileMode::IncludeSubpatterns)
- store32(index, Address(output, 4));
+ if (m_compileMode == JITCompileMode::IncludeSubpatterns)
+ store32(index, Address(output, 4));
+ }
move(index, returnRegister2);
generateReturn();
@@ -4143,6 +4154,11 @@
#endif
}
+ void loadSubPattern(RegisterID outputGPR, unsigned subpatternId, RegisterID startIndexGPR, RegisterID endIndexOrLenGPR)
+ {
+ loadPair32(outputGPR, TrustedImm32((subpatternId << 1) * sizeof(int)), startIndexGPR, endIndexOrLenGPR);
+ }
+
public:
YarrGenerator(VM* vm, YarrPattern& pattern, String& patternString, YarrCodeBlock& codeBlock, CharSize charSize, JITCompileMode compileMode)
: m_vm(vm)
@@ -4241,14 +4257,22 @@
move(TrustedImm32(matchLimit), remainingMatchCount);
#endif
+ // Initialize subpatterns' starts. And initialize matchStart if `!m_pattern.m_body->m_hasFixedSize`.
+ // If the mode is JITCompileMode::IncludeSubpatterns, then matchStart is subpatterns[0]'s start.
if (m_compileMode == JITCompileMode::IncludeSubpatterns) {
- for (unsigned i = 0; i < m_pattern.m_numSubpatterns + 1; ++i)
- store32(TrustedImm32(-1), Address(output, (i << 1) * sizeof(int)));
+ unsigned subpatternId = 0;
+ // First subpatternId's start is configured to `index` if !m_pattern.m_body->m_hasFixedSize.
+ if (!m_pattern.m_body->m_hasFixedSize) {
+ setMatchStart(index);
+ ++subpatternId;
+ }
+ for (; subpatternId < m_pattern.m_numSubpatterns + 1; ++subpatternId)
+ store32(TrustedImm32(-1), Address(output, (subpatternId << 1) * sizeof(int)));
+ } else {
+ if (!m_pattern.m_body->m_hasFixedSize)
+ setMatchStart(index);
}
- if (!m_pattern.m_body->m_hasFixedSize)
- setMatchStart(index);
-
#if ENABLE(YARR_JIT_ALL_PARENS_EXPRESSIONS)
if (m_containsNestedSubpatterns) {
initParenContextFreeList();