Title: [291515] trunk/Source/_javascript_Core
Revision
291515
Author
[email protected]
Date
2022-03-18 17:55:48 -0700 (Fri, 18 Mar 2022)

Log Message

[JSC] Reduce # of registers used in RegExpTestInline to allow using unlinked DFG in x64
https://bugs.webkit.org/show_bug.cgi?id=238092

Reviewed by Michael Saboff.

This patch reduces # of registers used in RegExpTestInline implementation to make it work
well for x64 unlinked DFG since it can reduce # of registers to use one callee-save register
for constants buffer.

We also add YarrJITRegisters::validate to ensure that used registers meet the invariants in YarrJIT.

* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compileRegExpTestInline):
* yarr/YarrJIT.cpp:
(JSC::Yarr::jitCompileInlinedTest):
* yarr/YarrJITRegisters.h:
(JSC::Yarr::YarrJITRegisters::validate):
(JSC::Yarr::YarrJITRegisters::YarrJITRegisters): Deleted.

Modified Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (291514 => 291515)


--- trunk/Source/_javascript_Core/ChangeLog	2022-03-19 00:46:37 UTC (rev 291514)
+++ trunk/Source/_javascript_Core/ChangeLog	2022-03-19 00:55:48 UTC (rev 291515)
@@ -1,3 +1,24 @@
+2022-03-18  Yusuke Suzuki  <[email protected]>
+
+        [JSC] Reduce # of registers used in RegExpTestInline to allow using unlinked DFG in x64
+        https://bugs.webkit.org/show_bug.cgi?id=238092
+
+        Reviewed by Michael Saboff.
+
+        This patch reduces # of registers used in RegExpTestInline implementation to make it work
+        well for x64 unlinked DFG since it can reduce # of registers to use one callee-save register
+        for constants buffer.
+
+        We also add YarrJITRegisters::validate to ensure that used registers meet the invariants in YarrJIT.
+
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compileRegExpTestInline):
+        * yarr/YarrJIT.cpp:
+        (JSC::Yarr::jitCompileInlinedTest):
+        * yarr/YarrJITRegisters.h:
+        (JSC::Yarr::YarrJITRegisters::validate):
+        (JSC::Yarr::YarrJITRegisters::YarrJITRegisters): Deleted.
+
 2022-03-17  Keith Miller  <[email protected]>
 
         Fix crash in Bleacher Report due to bad JSObjectRef passed to API

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp (291514 => 291515)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp	2022-03-19 00:46:37 UTC (rev 291514)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp	2022-03-19 00:55:48 UTC (rev 291515)
@@ -2703,28 +2703,24 @@
 
     SpeculateCellOperand globalObject(this, node->child1());
     SpeculateCellOperand base(this, node->child2());
-    GPRReg globalObjectGPR = globalObject.gpr();
-    GPRReg baseGPR = base.gpr();
-    GPRReg argumentGPR;
-    GPRFlushedCallResult result(this);
-    GPRReg resultGPR = result.gpr();
+
     GPRTemporary stringImpl(this);
     GPRTemporary stringData(this);
     GPRTemporary strLength(this);
     GPRTemporary output(this);
-    GPRTemporary result2(this);
     GPRTemporary temp0(this);
     GPRTemporary temp1(this);
-    GPRTemporary temp2;
+    std::optional<GPRTemporary> temp2;
+
+    GPRReg globalObjectGPR = globalObject.gpr();
+    GPRReg baseGPR = base.gpr();
     GPRReg stringImplGPR = stringImpl.gpr();
     GPRReg stringDataGPR = stringData.gpr();
     GPRReg outputGPR = output.gpr();
     GPRReg strLengthGPR = strLength.gpr();
-    GPRReg result2GPR = result2.gpr();
     GPRReg temp0GPR = temp0.gpr();
     GPRReg temp1GPR = temp1.gpr();
     GPRReg temp2GPR = InvalidGPRReg;
-    GPRReg swapReg = InvalidGPRReg;
 
     auto jitCodeBlock = regExp->getRegExpJITCodeBlock();
     ASSERT(jitCodeBlock);
@@ -2732,44 +2728,31 @@
 
 #if !CPU(X86_64)
     if (inlineCodeStats8Bit.needsTemp2()) {
-        GPRTemporary realTemp2(this);
-        temp2.adopt(realTemp2);
-        temp2GPR = temp2.gpr();
+        temp2.emplace(this);
+        temp2GPR = temp2->gpr();
     }
 #endif
 
     speculateRegExpObject(node->child2(), baseGPR);
 
-    MacroAssembler::JumpList done;
-    MacroAssembler::JumpList operationCases;
+    CCallHelpers::JumpList slowCases;
 
-    auto swapRegIfNeeded = [&] {
-        if (globalObjectGPR == resultGPR) {
-            swapReg = allocate();
-            m_jit.move(globalObjectGPR, swapReg);
-            globalObjectGPR = swapReg;
-        } else if (baseGPR == resultGPR) {
-            swapReg = allocate();
-            m_jit.move(baseGPR, swapReg);
-            baseGPR = swapReg;
-        } else if (argumentGPR == resultGPR) {
-            swapReg = allocate();
-            m_jit.move(argumentGPR, swapReg);
-            argumentGPR = swapReg;
-        }
-    };
+    auto regExpTestInlineCase = [&](GPRReg argumentGPR, CCallHelpers::JumpList& slowCases) {
+        m_jit.loadPtr(MacroAssembler::Address(argumentGPR, JSString::offsetOfValue()), stringImplGPR);
+        // If the string is a rope or 16 bit, we call the operation.
+        slowCases.append(m_jit.branchIfRopeStringImpl(stringImplGPR));
+        slowCases.append(m_jit.branchTest32(
+            MacroAssembler::Zero,
+            MacroAssembler::Address(stringImplGPR, StringImpl::flagsOffset()),
+            TrustedImm32(StringImpl::flagIs8Bit())));
 
-    auto regExpTestInlineCase = [&] {
         m_jit.loadPtr(MacroAssembler::Address(stringImplGPR, StringImpl::dataOffset()), stringDataGPR);
         m_jit.load32(MacroAssembler::Address(stringImplGPR, StringImpl::lengthMemoryOffset()), strLengthGPR);
 
-        GPRReg indexGPR = stringImplGPR;
-
-        m_jit.move(TrustedImm32(0), indexGPR);
-
+        // Clobbering input registers is OK since we already called flushRegisters.
         Yarr::YarrJITRegisters yarrRegisters;
         yarrRegisters.input = stringDataGPR;
-        yarrRegisters.index = indexGPR;
+        yarrRegisters.index = stringImplGPR;
         yarrRegisters.length = strLengthGPR;
         yarrRegisters.output = outputGPR;
         yarrRegisters.regT0 = temp0GPR;
@@ -2780,20 +2763,20 @@
         if (inlineCodeStats8Bit.needsTemp2())
             yarrRegisters.regT2 = temp2GPR;
 
-        yarrRegisters.returnRegister = resultGPR;
-        yarrRegisters.returnRegister2 = result2GPR;
+        yarrRegisters.returnRegister = temp0GPR;
+        yarrRegisters.returnRegister2 = stringDataGPR;
 
         auto commonData = m_jit.jitCode()->dfgCommon();
+        m_jit.move(TrustedImm32(0), yarrRegisters.index);
         Yarr::jitCompileInlinedTest(&m_graph.m_stackChecker, regExp->pattern(), regExp->flags(), Yarr::CharSize::Char8, &vm(), commonData->m_boyerMooreData, m_jit, yarrRegisters);
 
-        auto failedMatch = m_jit.branch32(MacroAssembler::LessThan, resultGPR, TrustedImm32(0));
+        auto failedMatch = m_jit.branch32(MacroAssembler::LessThan, yarrRegisters.returnRegister, TrustedImm32(0));
 
         //  Saved cached result
 #if CPU(X86_64)
         if (inlineCodeStats8Bit.needsTemp2()) {
             // Since we reused globalObjectGPR for temp2, let's restore the global object.
-            JSGlobalObject* globalObjectConst = jsCast<JSGlobalObject*>(node->cellOperand()->value());
-            m_jit.move(CCallHelpers::TrustedImmPtr(globalObjectConst), globalObjectGPR);
+            m_jit.move(TrustedImmPtr::weakPointer(m_graph, jsCast<JSGlobalObject*>(node->cellOperand()->value())), globalObjectGPR);
         }
 #endif
 
@@ -2801,80 +2784,56 @@
 
         m_jit.storePtr(TrustedImmPtr::weakPointer(m_graph, regExp), JITCompiler::Address(globalObjectGPR, offset + RegExpCachedResult::offsetOfLastRegExp()));
         m_jit.storePtr(argumentGPR, JITCompiler::Address(globalObjectGPR, offset + RegExpCachedResult::offsetOfLastInput()));
-        m_jit.store32(resultGPR, JITCompiler::Address(globalObjectGPR, offset + RegExpCachedResult::offsetOfResult() + OBJECT_OFFSETOF(MatchResult, start)));
-        m_jit.store32(result2GPR, JITCompiler::Address(globalObjectGPR, offset + RegExpCachedResult::offsetOfResult() + OBJECT_OFFSETOF(MatchResult, end)));
+        m_jit.store32(yarrRegisters.returnRegister, JITCompiler::Address(globalObjectGPR, offset + RegExpCachedResult::offsetOfResult() + OBJECT_OFFSETOF(MatchResult, start)));
+        m_jit.store32(yarrRegisters.returnRegister2, JITCompiler::Address(globalObjectGPR, offset + RegExpCachedResult::offsetOfResult() + OBJECT_OFFSETOF(MatchResult, end)));
         m_jit.store8(TrustedImm32(0), JITCompiler::Address(globalObjectGPR, offset + RegExpCachedResult::offsetOfReified()));
 
-        if (swapReg != InvalidGPRReg)
-            unlock(swapReg);
+        CCallHelpers::JumpList doneCases;
 
-        m_jit.move(TrustedImm32(1), resultGPR);
-        done.append(m_jit.jump());
+        m_jit.move(TrustedImm32(1), temp0GPR);
+        doneCases.append(m_jit.jump());
 
         failedMatch.link(&m_jit);
-        m_jit.move(TrustedImm32(0), resultGPR);
-        done.append(m_jit.jump());
+        m_jit.move(TrustedImm32(0), temp0GPR);
+        doneCases.append(m_jit.jump());
+
+        return doneCases;
     };
 
     if (node->child3().useKind() == StringUse) {
         SpeculateCellOperand argument(this, node->child3());
-        argumentGPR = argument.gpr();
+        GPRReg argumentGPR = argument.gpr();
         speculateString(node->child3(), argumentGPR);
 
         flushRegisters();
 
-        swapRegIfNeeded();
+        auto doneCases = regExpTestInlineCase(argumentGPR, slowCases);
 
-        m_jit.loadPtr(MacroAssembler::Address(argumentGPR, JSString::offsetOfValue()), stringImplGPR);
-        // If the string is a rope or 16 bit, we call the operation.
-        operationCases.append(m_jit.branchIfRopeStringImpl(stringImplGPR));
-        operationCases.append(m_jit.branchTest32(
-            MacroAssembler::Zero,
-            MacroAssembler::Address(stringImplGPR, StringImpl::flagsOffset()),
-            TrustedImm32(StringImpl::flagIs8Bit())));
-
-        regExpTestInlineCase();
-
-        operationCases.link(&m_jit);
-
-        callOperation(operationRegExpTestString, resultGPR, globalObjectGPR, baseGPR, argumentGPR);
-
+        slowCases.link(&m_jit);
+        callOperation(operationRegExpTestString, temp0GPR, globalObjectGPR, baseGPR, argumentGPR);
         m_jit.exceptionCheck();
 
-        done.link(&m_jit);
-        unblessedBooleanResult(resultGPR, node);
-
+        doneCases.link(&m_jit);
+        unblessedBooleanResult(temp0GPR, node);
         return;
     }
 
     JSValueOperand argument(this, node->child3());
-    argumentGPR = argument.gpr();
+    GPRReg argumentGPR = argument.gpr();
 
     flushRegisters();
 
-    swapRegIfNeeded();
+    slowCases.append(m_jit.branchIfNotCell(argumentGPR));
+    slowCases.append(m_jit.branchIfNotString(argumentGPR));
 
-    operationCases.append(m_jit.branchIfNotCell(argumentGPR));
-    operationCases.append(m_jit.branchIfNotString(argumentGPR));
+    auto doneCases = regExpTestInlineCase(argumentGPR, slowCases);
 
-    m_jit.loadPtr(MacroAssembler::Address(argumentGPR, JSString::offsetOfValue()), stringImplGPR);
-    // If the string is a rope or 16 bit, we call the operation.
-    operationCases.append(m_jit.branchIfRopeStringImpl(stringImplGPR));
-    operationCases.append(m_jit.branchTest32(
-        MacroAssembler::Zero,
-        MacroAssembler::Address(stringImplGPR, StringImpl::flagsOffset()),
-        TrustedImm32(StringImpl::flagIs8Bit())));
-
-    regExpTestInlineCase();
-
-    operationCases.link(&m_jit);
-
-    callOperation(operationRegExpTest, resultGPR, globalObjectGPR, baseGPR, argumentGPR);
-
-    done.link(&m_jit);
+    slowCases.link(&m_jit);
+    callOperation(operationRegExpTest, temp0GPR, globalObjectGPR, baseGPR, argumentGPR);
     m_jit.exceptionCheck();
 
-    unblessedBooleanResult(resultGPR, node);
+    doneCases.link(&m_jit);
+    unblessedBooleanResult(temp0GPR, node);
 }
 #else
 void SpeculativeJIT::compileRegExpTestInline(Node* node)

Modified: trunk/Source/_javascript_Core/yarr/YarrJIT.cpp (291514 => 291515)


--- trunk/Source/_javascript_Core/yarr/YarrJIT.cpp	2022-03-19 00:46:37 UTC (rev 291514)
+++ trunk/Source/_javascript_Core/yarr/YarrJIT.cpp	2022-03-19 00:55:48 UTC (rev 291515)
@@ -2443,6 +2443,7 @@
                 // slot, and return. In the case of pattern with a fixed size, we will
                 // not have yet set the value in the first 
                 ASSERT(m_regs.index != m_regs.returnRegister);
+                ASSERT(m_regs.output != m_regs.returnRegister);
                 if (m_pattern.m_body->m_hasFixedSize) {
                     if (priorAlternative->m_minimumSize)
                         m_jit.sub32(m_regs.index, MacroAssembler::Imm32(priorAlternative->m_minimumSize), m_regs.returnRegister);
@@ -4033,6 +4034,7 @@
 #if CPU(X86_64)
 #if OS(WINDOWS)
         // Store the return value in the allocated space pointed by rcx.
+        ASSERT(noOverlap(X86Registers::ecx, m_regs.returnRegister, m_regs.returnRegister2));
         m_jit.pop(X86Registers::ecx);
         m_jit.store64(m_regs.returnRegister, MacroAssembler::Address(X86Registers::ecx));
         m_jit.store64(m_regs.returnRegister2, MacroAssembler::Address(X86Registers::ecx, sizeof(void*)));
@@ -4750,6 +4752,8 @@
     Yarr::ErrorCode errorCode;
     Yarr::YarrPattern pattern(patternString, flags, errorCode);
 
+    jitRegisters.validate();
+
     YarrGenerator<YarrJITRegisters> yarrGenerator(jit, vm, &boyerMooreData, jitRegisters, pattern, patternString, charSize, JITCompileMode::InlineTest);
     yarrGenerator.setStackChecker(m_compilationThreadStackChecker);
     yarrGenerator.compileInline(boyerMooreData);

Modified: trunk/Source/_javascript_Core/yarr/YarrJITRegisters.h (291514 => 291515)


--- trunk/Source/_javascript_Core/yarr/YarrJITRegisters.h	2022-03-19 00:46:37 UTC (rev 291514)
+++ trunk/Source/_javascript_Core/yarr/YarrJITRegisters.h	2022-03-19 00:55:48 UTC (rev 291515)
@@ -175,8 +175,30 @@
 #if ENABLE(YARR_JIT_REGEXP_TEST_INLINE)
 class YarrJITRegisters {
 public:
-    YarrJITRegisters()
+    YarrJITRegisters() = default;
+
+    void validate()
     {
+#if ASSERT_ENABLED
+        ASSERT(input != InvalidGPRReg);
+        ASSERT(index != InvalidGPRReg);
+        ASSERT(length != InvalidGPRReg);
+        ASSERT(output != InvalidGPRReg);
+
+        ASSERT(returnRegister != InvalidGPRReg);
+        ASSERT(returnRegister2 != InvalidGPRReg);
+
+        ASSERT(regT0 != InvalidGPRReg);
+        ASSERT(regT1 != InvalidGPRReg);
+
+        ASSERT(noOverlap(input, index, length, output, regT0, regT1));
+        ASSERT(noOverlap(returnRegister, returnRegister2));
+        ASSERT(noOverlap(index, output, returnRegister));
+
+#if CPU(X86_64) && OS(WINDOWS)
+        ASSERT(noOverlap(X86Registers::ecx, returnRegister, m_regs.returnRegister2));
+#endif
+#endif
     }
 
     // Argument registers
@@ -184,6 +206,7 @@
     GPRReg index { InvalidGPRReg };
     GPRReg length { InvalidGPRReg };
     GPRReg output { InvalidGPRReg };
+
     GPRReg matchingContext { InvalidGPRReg };
     GPRReg freelistRegister { InvalidGPRReg };
     GPRReg freelistSizeRegister { InvalidGPRReg };
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to