Title: [276427] trunk
Revision
276427
Author
[email protected]
Date
2021-04-22 01:27:42 -0700 (Thu, 22 Apr 2021)

Log Message

[JSC] DFG / FTL should inline switch_string
https://bugs.webkit.org/show_bug.cgi?id=224578

Reviewed by Mark Lam.

JSTests:

* microbenchmarks/switch-inlining.js: Added.
(inner):
(outer):
* stress/switch-inlining-nested.js: Added.
(shouldBe):
(inner):
(outer):

Source/_javascript_Core:

Because of r275840 change, we no longer copy StringJumpTable when compiling DFG / FTL code.
Instead we are using a pointer to UnlinkedStringTable stored in UnlinkedCodeBlock.
This allows DFG / FTL to inline CodeBlock which includes op_switch_string. We were previously not able
to do that because we cannot copy StringImpl in DFG / FTL concurrent compiler thread.

1. We handle StringJumpTable / UnlinkedStringJumpTable in the same way as SimpleJumpTable / UnlinkedSimpleJumpTable.
2. We put m_ctiDefault of StringJumpTable in the last element of m_ctiOffsets vector of StringJumpTable to make
   sizeof(StringJumpTable) small.
3. We use m_indexInTable instead of m_branchOffset in FTL switch generation to make switch table dense.

The microbenchmark shows 30% improvement because of unlocking inlining feature.

                                ToT                     Patched

    switch-inlining       27.1238+-0.2708     ^     20.2630+-0.1477        ^ definitely 1.3386x faster

    <geometric>           27.1238+-0.2708     ^     20.2630+-0.1477        ^ definitely 1.3386x faster

* bytecode/JumpTable.h:
(JSC::StringJumpTable::ensureCTITable):
(JSC::StringJumpTable::ctiForValue const):
(JSC::StringJumpTable::ctiDefault const):
(JSC::StringJumpTable::isEmpty const):
* bytecode/UnlinkedCodeBlock.h:
(JSC::UnlinkedStringJumpTable::indexForValue const):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::parseBlock):
(JSC::DFG::ByteCodeParser::InlineStackEntry::InlineStackEntry):
* dfg/DFGCapabilities.cpp:
(JSC::DFG::capabilityLevel):
* dfg/DFGGraph.h:
* dfg/DFGJITCompiler.cpp:
(JSC::DFG::JITCompiler::link):
* dfg/DFGOperations.cpp:
(JSC::DFG::JSC_DEFINE_JIT_OPERATION):
* dfg/DFGOperations.h:
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::emitSwitchStringOnString):
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::switchStringSlow):
* ftl/FTLOperations.cpp:
(JSC::FTL::JSC_DEFINE_JIT_OPERATION):
* ftl/FTLOperations.h:
* jit/JIT.cpp:
(JSC::JIT::link):
* jit/JITOpcodes.cpp:
(JSC::JIT::emit_op_switch_string):
* jit/JITOpcodes32_64.cpp:
(JSC::JIT::emit_op_switch_string):
* jit/JITOperations.cpp:
(JSC::JSC_DEFINE_JIT_OPERATION):

Modified Paths

Added Paths

Diff

Modified: trunk/JSTests/ChangeLog (276426 => 276427)


--- trunk/JSTests/ChangeLog	2021-04-22 07:50:02 UTC (rev 276426)
+++ trunk/JSTests/ChangeLog	2021-04-22 08:27:42 UTC (rev 276427)
@@ -1,3 +1,18 @@
+2021-04-21  Yusuke Suzuki  <[email protected]>
+
+        [JSC] DFG / FTL should inline switch_string
+        https://bugs.webkit.org/show_bug.cgi?id=224578
+
+        Reviewed by Mark Lam.
+
+        * microbenchmarks/switch-inlining.js: Added.
+        (inner):
+        (outer):
+        * stress/switch-inlining-nested.js: Added.
+        (shouldBe):
+        (inner):
+        (outer):
+
 2021-04-21  Caio Lima  <[email protected]>
 
         [JSC] Unskip some tests for ARMv7 and MIPS

Added: trunk/JSTests/microbenchmarks/switch-inlining.js (0 => 276427)


--- trunk/JSTests/microbenchmarks/switch-inlining.js	                        (rev 0)
+++ trunk/JSTests/microbenchmarks/switch-inlining.js	2021-04-22 08:27:42 UTC (rev 276427)
@@ -0,0 +1,31 @@
+function inner(value)
+{
+    switch (value) {
+    case "ExpressionStatement":
+        return 0;
+    case "BreakStatement":
+        return 1;
+    case "ThrowStatement":
+        return 2;
+    case "IfStatement":
+        return 3;
+    case "WhileStatement":
+        return 4;
+    case "DoWhileStatement":
+        return 5;
+    case "ForStatement":
+        return 6;
+    }
+}
+
+function outer(value)
+{
+    return inner(value);
+}
+noInline(outer);
+
+for (var i = 0; i < 1e6; ++i) {
+    outer("DoWhile" + "Statement");
+    outer("For" + "Statement");
+    outer("");
+}

Added: trunk/JSTests/stress/switch-inlining-nested.js (0 => 276427)


--- trunk/JSTests/stress/switch-inlining-nested.js	                        (rev 0)
+++ trunk/JSTests/stress/switch-inlining-nested.js	2021-04-22 08:27:42 UTC (rev 276427)
@@ -0,0 +1,56 @@
+
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+
+function inner(value) {
+    switch (value + "Statement") {
+    case "ExpressionStatement":
+        return 0;
+    case "BreakStatement":
+        return 1;
+    case "ThrowStatement":
+        return 2;
+    case "IfStatement":
+        return 3;
+    case "WhileStatement":
+        return 4;
+    case "DoWhileStatement":
+        return 5;
+    case "ForStatement":
+        return 6;
+    default:
+        return 7;
+    }
+}
+
+function outer(value) {
+    switch (value) {
+    case "_expression_":
+        return 0 + inner(value);
+    case "Break":
+        return 1 + inner(value);
+    case "Throw":
+        return 2 + inner(value);
+    case "If":
+        return 3 + inner(value);
+    case "While":
+        return 4 + inner(value);
+    case "DoWhile":
+        return 5 + inner(value);
+    case "For":
+        return 6 + inner(value);
+    default:
+        return 7 + inner(value);
+    }
+}
+noInline(outer);
+
+for (var i = 0; i < 3e5; ++i) {
+    shouldBe(outer("Do" + "While"), 10);
+    shouldBe(outer("F" + "or"), 12);
+    shouldBe(outer(""), 14);
+    shouldBe(outer("TEST"), 14);
+}

Modified: trunk/Source/_javascript_Core/ChangeLog (276426 => 276427)


--- trunk/Source/_javascript_Core/ChangeLog	2021-04-22 07:50:02 UTC (rev 276426)
+++ trunk/Source/_javascript_Core/ChangeLog	2021-04-22 08:27:42 UTC (rev 276427)
@@ -1,3 +1,62 @@
+2021-04-21  Yusuke Suzuki  <[email protected]>
+
+        [JSC] DFG / FTL should inline switch_string
+        https://bugs.webkit.org/show_bug.cgi?id=224578
+
+        Reviewed by Mark Lam.
+
+        Because of r275840 change, we no longer copy StringJumpTable when compiling DFG / FTL code.
+        Instead we are using a pointer to UnlinkedStringTable stored in UnlinkedCodeBlock.
+        This allows DFG / FTL to inline CodeBlock which includes op_switch_string. We were previously not able
+        to do that because we cannot copy StringImpl in DFG / FTL concurrent compiler thread.
+
+        1. We handle StringJumpTable / UnlinkedStringJumpTable in the same way as SimpleJumpTable / UnlinkedSimpleJumpTable.
+        2. We put m_ctiDefault of StringJumpTable in the last element of m_ctiOffsets vector of StringJumpTable to make
+           sizeof(StringJumpTable) small.
+        3. We use m_indexInTable instead of m_branchOffset in FTL switch generation to make switch table dense.
+
+        The microbenchmark shows 30% improvement because of unlocking inlining feature.
+
+                                        ToT                     Patched
+
+            switch-inlining       27.1238+-0.2708     ^     20.2630+-0.1477        ^ definitely 1.3386x faster
+
+            <geometric>           27.1238+-0.2708     ^     20.2630+-0.1477        ^ definitely 1.3386x faster
+
+        * bytecode/JumpTable.h:
+        (JSC::StringJumpTable::ensureCTITable):
+        (JSC::StringJumpTable::ctiForValue const):
+        (JSC::StringJumpTable::ctiDefault const):
+        (JSC::StringJumpTable::isEmpty const):
+        * bytecode/UnlinkedCodeBlock.h:
+        (JSC::UnlinkedStringJumpTable::indexForValue const):
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::parseBlock):
+        (JSC::DFG::ByteCodeParser::InlineStackEntry::InlineStackEntry):
+        * dfg/DFGCapabilities.cpp:
+        (JSC::DFG::capabilityLevel):
+        * dfg/DFGGraph.h:
+        * dfg/DFGJITCompiler.cpp:
+        (JSC::DFG::JITCompiler::link):
+        * dfg/DFGOperations.cpp:
+        (JSC::DFG::JSC_DEFINE_JIT_OPERATION):
+        * dfg/DFGOperations.h:
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::emitSwitchStringOnString):
+        * ftl/FTLLowerDFGToB3.cpp:
+        (JSC::FTL::DFG::LowerDFGToB3::switchStringSlow):
+        * ftl/FTLOperations.cpp:
+        (JSC::FTL::JSC_DEFINE_JIT_OPERATION):
+        * ftl/FTLOperations.h:
+        * jit/JIT.cpp:
+        (JSC::JIT::link):
+        * jit/JITOpcodes.cpp:
+        (JSC::JIT::emit_op_switch_string):
+        * jit/JITOpcodes32_64.cpp:
+        (JSC::JIT::emit_op_switch_string):
+        * jit/JITOperations.cpp:
+        (JSC::JSC_DEFINE_JIT_OPERATION):
+
 2021-04-21  Adrian Perez de Castro  <[email protected]>
 
         Non-unified build fixes, mid April 2021 edition

Modified: trunk/Source/_javascript_Core/bytecode/JumpTable.h (276426 => 276427)


--- trunk/Source/_javascript_Core/bytecode/JumpTable.h	2021-04-22 07:50:02 UTC (rev 276426)
+++ trunk/Source/_javascript_Core/bytecode/JumpTable.h	2021-04-22 08:27:42 UTC (rev 276427)
@@ -42,19 +42,27 @@
 #if ENABLE(JIT)
     struct StringJumpTable {
         FixedVector<CodeLocationLabel<JSSwitchPtrTag>> m_ctiOffsets;
-        CodeLocationLabel<JSSwitchPtrTag> m_ctiDefault; // FIXME: it should not be necessary to store this.
 
+        void ensureCTITable(const UnlinkedStringJumpTable& unlinkedTable)
+        {
+            if (!isEmpty())
+                return;
+            m_ctiOffsets = FixedVector<CodeLocationLabel<JSSwitchPtrTag>>(unlinkedTable.m_offsetTable.size() + 1);
+        }
+
         inline CodeLocationLabel<JSSwitchPtrTag> ctiForValue(const UnlinkedStringJumpTable& unlinkedTable, StringImpl* value) const
         {
             auto loc = unlinkedTable.m_offsetTable.find(value);
             if (loc == unlinkedTable.m_offsetTable.end())
-                return m_ctiDefault;
+                return m_ctiOffsets[unlinkedTable.m_offsetTable.size()];
             return m_ctiOffsets[loc->value.m_indexInTable];
         }
+
+        CodeLocationLabel<JSSwitchPtrTag> ctiDefault() const { return m_ctiOffsets.last(); }
+
+        bool isEmpty() const { return m_ctiOffsets.isEmpty(); }
     };
-#endif
 
-#if ENABLE(JIT)
     struct SimpleJumpTable {
         FixedVector<CodeLocationLabel<JSSwitchPtrTag>> m_ctiOffsets;
         CodeLocationLabel<JSSwitchPtrTag> m_ctiDefault;

Modified: trunk/Source/_javascript_Core/bytecode/UnlinkedCodeBlock.h (276426 => 276427)


--- trunk/Source/_javascript_Core/bytecode/UnlinkedCodeBlock.h	2021-04-22 07:50:02 UTC (rev 276426)
+++ trunk/Source/_javascript_Core/bytecode/UnlinkedCodeBlock.h	2021-04-22 08:27:42 UTC (rev 276427)
@@ -92,6 +92,13 @@
         return loc->value.m_branchOffset;
     }
 
+    inline unsigned indexForValue(StringImpl* value, unsigned defaultIndex) const
+    {
+        auto loc = m_offsetTable.find(value);
+        if (loc == m_offsetTable.end())
+            return defaultIndex;
+        return loc->value.m_indexInTable;
+    }
 };
 
 struct UnlinkedSimpleJumpTable {

Modified: trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp (276426 => 276427)


--- trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2021-04-22 07:50:02 UTC (rev 276426)
+++ trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2021-04-22 08:27:42 UTC (rev 276427)
@@ -1185,6 +1185,7 @@
         // direct, caller).
         Vector<unsigned> m_identifierRemap;
         Vector<unsigned> m_switchRemap;
+        Vector<unsigned> m_stringSwitchRemap;
         
         // These are blocks whose terminal is a Jump, Branch or Switch, and whose target has not yet been linked.
         // Their terminal instead refers to a bytecode index, and the right BB can be found in m_blockLinkingTargets.
@@ -6911,10 +6912,10 @@
             auto bytecode = currentInstruction->as<OpSwitchString>();
             SwitchData& data = ""
             data.kind = SwitchString;
-            data.switchTableIndex = bytecode.m_tableIndex;
+            data.switchTableIndex = m_inlineStackTop->m_stringSwitchRemap[bytecode.m_tableIndex];
             data.fallThrough.setBytecodeIndex(m_currentIndex.offset() + jumpTarget(bytecode.m_defaultOffset));
-            const UnlinkedStringJumpTable& table = m_codeBlock->unlinkedStringSwitchJumpTable(data.switchTableIndex);
-            for (const auto& entry : table.m_offsetTable) {
+            const UnlinkedStringJumpTable& unlinkedTable = m_graph.unlinkedStringSwitchJumpTable(data.switchTableIndex);
+            for (const auto& entry : unlinkedTable.m_offsetTable) {
                 unsigned target = m_currentIndex.offset() + entry.value.m_branchOffset;
                 if (target == data.fallThrough.bytecodeIndex())
                     continue;
@@ -8551,6 +8552,13 @@
         m_switchRemap[i] = byteCodeParser->m_graph.m_unlinkedSwitchJumpTables.size();
         byteCodeParser->m_graph.m_unlinkedSwitchJumpTables.append(&codeBlock->unlinkedSwitchJumpTable(i));
     }
+
+    m_stringSwitchRemap.resize(codeBlock->numberOfUnlinkedStringSwitchJumpTables());
+    byteCodeParser->m_graph.m_stringSwitchJumpTables.resize(byteCodeParser->m_graph.m_stringSwitchJumpTables.size() + codeBlock->numberOfUnlinkedStringSwitchJumpTables());
+    for (unsigned i = 0; i < codeBlock->numberOfUnlinkedStringSwitchJumpTables(); ++i) {
+        m_stringSwitchRemap[i] = byteCodeParser->m_graph.m_unlinkedStringSwitchJumpTables.size();
+        byteCodeParser->m_graph.m_unlinkedStringSwitchJumpTables.append(&codeBlock->unlinkedStringSwitchJumpTable(i));
+    }
     
     m_argumentPositions.resize(argumentCountIncludingThisWithFixup);
     for (int i = 0; i < argumentCountIncludingThisWithFixup; ++i) {

Modified: trunk/Source/_javascript_Core/dfg/DFGCapabilities.cpp (276426 => 276427)


--- trunk/Source/_javascript_Core/dfg/DFGCapabilities.cpp	2021-04-22 07:50:02 UTC (rev 276426)
+++ trunk/Source/_javascript_Core/dfg/DFGCapabilities.cpp	2021-04-22 08:27:42 UTC (rev 276427)
@@ -296,9 +296,9 @@
     case op_put_private_name:
     case op_set_private_brand:
     case op_check_private_brand:
+    case op_switch_string:
         return CanCompileAndInline;
 
-    case op_switch_string: // Don't inline because we don't want to copy string tables in the concurrent JIT.
     case op_call_eval:
         return CanCompile;
 

Modified: trunk/Source/_javascript_Core/dfg/DFGGraph.h (276426 => 276427)


--- trunk/Source/_javascript_Core/dfg/DFGGraph.h	2021-04-22 07:50:02 UTC (rev 276426)
+++ trunk/Source/_javascript_Core/dfg/DFGGraph.h	2021-04-22 08:27:42 UTC (rev 276427)
@@ -1066,6 +1066,9 @@
     const UnlinkedSimpleJumpTable& unlinkedSwitchJumpTable(unsigned index) const { return *m_unlinkedSwitchJumpTables[index]; }
     SimpleJumpTable& switchJumpTable(unsigned index) { return m_switchJumpTables[index]; }
 
+    const UnlinkedStringJumpTable& unlinkedStringSwitchJumpTable(unsigned index) const { return *m_unlinkedStringSwitchJumpTables[index]; }
+    StringJumpTable& stringSwitchJumpTable(unsigned index) { return m_stringSwitchJumpTables[index]; }
+
     void appendCatchEntrypoint(BytecodeIndex bytecodeIndex, MacroAssemblerCodePtr<ExceptionHandlerPtrTag> machineCode, Vector<FlushFormat>&& argumentFormats)
     {
         m_catchEntrypoints.append(CatchEntrypointData { machineCode, FixedVector<FlushFormat>(WTFMove(argumentFormats)), bytecodeIndex });
@@ -1081,8 +1084,11 @@
     Vector<BasicBlock*, 1> m_roots;
     Vector<Edge, 16> m_varArgChildren;
 
-    Vector<const UnlinkedSimpleJumpTable*> m_unlinkedSwitchJumpTables; // UnlinkedSimpleJumpTable is kept by UnlinkedCodeBlocks retained by baseline CodeBlocks handled by DFG / FTL.
+    // UnlinkedSimpleJumpTable/UnlinkedStringJumpTable are kept by UnlinkedCodeBlocks retained by baseline CodeBlocks handled by DFG / FTL.
+    Vector<const UnlinkedSimpleJumpTable*> m_unlinkedSwitchJumpTables;
     Vector<SimpleJumpTable> m_switchJumpTables;
+    Vector<const UnlinkedStringJumpTable*> m_unlinkedStringSwitchJumpTables;
+    Vector<StringJumpTable> m_stringSwitchJumpTables;
 
     HashMap<EncodedJSValue, FrozenValue*, EncodedJSValueHash, EncodedJSValueHashTraits> m_frozenValueMap;
     Bag<FrozenValue> m_frozenValues;

Modified: trunk/Source/_javascript_Core/dfg/DFGJITCompiler.cpp (276426 => 276427)


--- trunk/Source/_javascript_Core/dfg/DFGJITCompiler.cpp	2021-04-22 07:50:02 UTC (rev 276426)
+++ trunk/Source/_javascript_Core/dfg/DFGJITCompiler.cpp	2021-04-22 08:27:42 UTC (rev 276427)
@@ -176,10 +176,10 @@
     
     m_graph.registerFrozenValues();
 
-    if (m_codeBlock->numberOfUnlinkedStringSwitchJumpTables() || !m_graph.m_switchJumpTables.isEmpty()) {
+    if (!m_graph.m_stringSwitchJumpTables.isEmpty() || !m_graph.m_switchJumpTables.isEmpty()) {
         ConcurrentJSLocker locker(m_codeBlock->m_lock);
-        if (m_codeBlock->numberOfUnlinkedStringSwitchJumpTables())
-            m_codeBlock->ensureJITData(locker).m_stringSwitchJumpTables = FixedVector<StringJumpTable>(m_codeBlock->numberOfUnlinkedStringSwitchJumpTables());
+        if (!m_graph.m_stringSwitchJumpTables.isEmpty())
+            m_codeBlock->ensureJITData(locker).m_stringSwitchJumpTables = WTFMove(m_graph.m_stringSwitchJumpTables);
         if (!m_graph.m_switchJumpTables.isEmpty())
             m_codeBlock->ensureJITData(locker).m_switchJumpTables = WTFMove(m_graph.m_switchJumpTables);
     }
@@ -186,52 +186,52 @@
 
     for (Bag<SwitchData>::iterator iter = m_graph.m_switchData.begin(); !!iter; ++iter) {
         SwitchData& data = ""
-        if (!data.didUseJumpTable) {
-            ASSERT(data.kind == SwitchString || m_codeBlock->switchJumpTable(data.switchTableIndex).isEmpty());
-            continue;
+        switch (data.kind) {
+        case SwitchChar:
+        case SwitchImm: {
+            if (!data.didUseJumpTable) {
+                ASSERT(m_codeBlock->switchJumpTable(data.switchTableIndex).isEmpty());
+                continue;
+            }
+
+            const UnlinkedSimpleJumpTable& unlinkedTable = m_graph.unlinkedSwitchJumpTable(data.switchTableIndex);
+            SimpleJumpTable& linkedTable = m_codeBlock->switchJumpTable(data.switchTableIndex);
+            linkedTable.m_ctiDefault = linkBuffer.locationOf<JSSwitchPtrTag>(m_blockHeads[data.fallThrough.block->index]);
+            RELEASE_ASSERT(linkedTable.m_ctiOffsets.size() == unlinkedTable.m_branchOffsets.size());
+            for (unsigned j = linkedTable.m_ctiOffsets.size(); j--;)
+                linkedTable.m_ctiOffsets[j] = linkedTable.m_ctiDefault;
+            for (unsigned j = data.cases.size(); j--;) {
+                SwitchCase& myCase = data.cases[j];
+                linkedTable.m_ctiOffsets[myCase.value.switchLookupValue(data.kind) - unlinkedTable.m_min] =
+                    linkBuffer.locationOf<JSSwitchPtrTag>(m_blockHeads[myCase.target.block->index]);
+            }
+            break;
         }
-        
-        if (data.kind == SwitchString)
-            continue;
-        
-        RELEASE_ASSERT(data.kind == SwitchImm || data.kind == SwitchChar);
-        
-        const UnlinkedSimpleJumpTable& unlinkedTable = m_graph.unlinkedSwitchJumpTable(data.switchTableIndex);
-        SimpleJumpTable& linkedTable = m_codeBlock->switchJumpTable(data.switchTableIndex);
-        linkedTable.m_ctiDefault = linkBuffer.locationOf<JSSwitchPtrTag>(m_blockHeads[data.fallThrough.block->index]);
-        RELEASE_ASSERT(linkedTable.m_ctiOffsets.size() == unlinkedTable.m_branchOffsets.size());
-        for (unsigned j = linkedTable.m_ctiOffsets.size(); j--;)
-            linkedTable.m_ctiOffsets[j] = linkedTable.m_ctiDefault;
-        for (unsigned j = data.cases.size(); j--;) {
-            SwitchCase& myCase = data.cases[j];
-            linkedTable.m_ctiOffsets[myCase.value.switchLookupValue(data.kind) - unlinkedTable.m_min] =
-                linkBuffer.locationOf<JSSwitchPtrTag>(m_blockHeads[myCase.target.block->index]);
+
+        case SwitchString: {
+            if (!data.didUseJumpTable) {
+                ASSERT(m_codeBlock->stringSwitchJumpTable(data.switchTableIndex).isEmpty());
+                continue;
+            }
+
+            const UnlinkedStringJumpTable& unlinkedTable = m_graph.unlinkedStringSwitchJumpTable(data.switchTableIndex);
+            StringJumpTable& linkedTable = m_codeBlock->stringSwitchJumpTable(data.switchTableIndex);
+            auto ctiDefault = linkBuffer.locationOf<JSSwitchPtrTag>(m_blockHeads[data.fallThrough.block->index]);
+            RELEASE_ASSERT(linkedTable.m_ctiOffsets.size() == unlinkedTable.m_offsetTable.size() + 1);
+            for (auto& entry : linkedTable.m_ctiOffsets)
+                entry = ctiDefault;
+            for (unsigned j = data.cases.size(); j--;) {
+                SwitchCase& myCase = data.cases[j];
+                auto iter = unlinkedTable.m_offsetTable.find(myCase.value.stringImpl());
+                RELEASE_ASSERT(iter != unlinkedTable.m_offsetTable.end());
+                linkedTable.m_ctiOffsets[iter->value.m_indexInTable] = linkBuffer.locationOf<JSSwitchPtrTag>(m_blockHeads[myCase.target.block->index]);
+            }
+            break;
         }
-    }
-    
-    // NOTE: we cannot clear string switch tables because (1) we're running concurrently
-    // and we cannot deref StringImpl's and (2) it would be weird to deref those
-    // StringImpl's since we refer to them.
-    for (Bag<SwitchData>::iterator switchDataIter = m_graph.m_switchData.begin(); !!switchDataIter; ++switchDataIter) {
-        SwitchData& data = ""
-        if (!data.didUseJumpTable)
-            continue;
-        
-        if (data.kind != SwitchString)
-            continue;
-        
-        const UnlinkedStringJumpTable& unlinkedTable = m_codeBlock->unlinkedStringSwitchJumpTable(data.switchTableIndex);
-        StringJumpTable& linkedTable = m_codeBlock->stringSwitchJumpTable(data.switchTableIndex);
-        linkedTable.m_ctiDefault = linkBuffer.locationOf<JSSwitchPtrTag>(m_blockHeads[data.fallThrough.block->index]);
-        linkedTable.m_ctiOffsets = FixedVector<CodeLocationLabel<JSSwitchPtrTag>>(unlinkedTable.m_offsetTable.size());
 
-        for (auto& entry : linkedTable.m_ctiOffsets)
-            entry = linkedTable.m_ctiDefault;
-        for (unsigned j = data.cases.size(); j--;) {
-            SwitchCase& myCase = data.cases[j];
-            auto iter = unlinkedTable.m_offsetTable.find(myCase.value.stringImpl());
-            RELEASE_ASSERT(iter != unlinkedTable.m_offsetTable.end());
-            linkedTable.m_ctiOffsets[iter->value.m_indexInTable] = linkBuffer.locationOf<JSSwitchPtrTag>(m_blockHeads[myCase.target.block->index]);
+        case SwitchCell:
+            RELEASE_ASSERT_NOT_REACHED();
+            break;
         }
     }
 

Modified: trunk/Source/_javascript_Core/dfg/DFGOperations.cpp (276426 => 276427)


--- trunk/Source/_javascript_Core/dfg/DFGOperations.cpp	2021-04-22 07:50:02 UTC (rev 276426)
+++ trunk/Source/_javascript_Core/dfg/DFGOperations.cpp	2021-04-22 08:27:42 UTC (rev 276427)
@@ -2706,7 +2706,7 @@
     return linkedTable.m_ctiDefault.executableAddress<char*>();
 }
 
-JSC_DEFINE_JIT_OPERATION(operationSwitchString, char*, (JSGlobalObject* globalObject, size_t tableIndex, JSString* string))
+JSC_DEFINE_JIT_OPERATION(operationSwitchString, char*, (JSGlobalObject* globalObject, size_t tableIndex, const UnlinkedStringJumpTable* unlinkedTable, JSString* string))
 {
     VM& vm = globalObject->vm();
     CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
@@ -2718,8 +2718,7 @@
     RETURN_IF_EXCEPTION(throwScope, nullptr);
     CodeBlock* codeBlock = callFrame->codeBlock();
     const StringJumpTable& linkedTable = codeBlock->stringSwitchJumpTable(tableIndex);
-    const UnlinkedStringJumpTable& unlinkedTable = codeBlock->unlinkedStringSwitchJumpTable(tableIndex);
-    return linkedTable.ctiForValue(unlinkedTable, strImpl).executableAddress<char*>();
+    return linkedTable.ctiForValue(*unlinkedTable, strImpl).executableAddress<char*>();
 }
 
 JSC_DEFINE_JIT_OPERATION(operationCompareStringImplLess, uintptr_t, (StringImpl* a, StringImpl* b))

Modified: trunk/Source/_javascript_Core/dfg/DFGOperations.h (276426 => 276427)


--- trunk/Source/_javascript_Core/dfg/DFGOperations.h	2021-04-22 07:50:02 UTC (rev 276426)
+++ trunk/Source/_javascript_Core/dfg/DFGOperations.h	2021-04-22 08:27:42 UTC (rev 276427)
@@ -35,6 +35,7 @@
 
 class DateInstance;
 class JSBigInt;
+struct UnlinkedStringJumpTable;
 
 namespace DFG {
 
@@ -269,7 +270,7 @@
 JSC_DECLARE_JIT_OPERATION(operationStrCat2, JSString*, (JSGlobalObject*, EncodedJSValue, EncodedJSValue));
 JSC_DECLARE_JIT_OPERATION(operationStrCat3, JSString*, (JSGlobalObject*, EncodedJSValue, EncodedJSValue, EncodedJSValue));
 JSC_DECLARE_JIT_OPERATION(operationFindSwitchImmTargetForDouble, char*, (VM*, EncodedJSValue, size_t tableIndex, int32_t));
-JSC_DECLARE_JIT_OPERATION(operationSwitchString, char*, (JSGlobalObject*, size_t tableIndex, JSString*));
+JSC_DECLARE_JIT_OPERATION(operationSwitchString, char*, (JSGlobalObject*, size_t tableIndex, const UnlinkedStringJumpTable*, JSString*));
 JSC_DECLARE_JIT_OPERATION(operationCompareStringImplLess, uintptr_t, (StringImpl*, StringImpl*));
 JSC_DECLARE_JIT_OPERATION(operationCompareStringImplLessEq, uintptr_t, (StringImpl*, StringImpl*));
 JSC_DECLARE_JIT_OPERATION(operationCompareStringImplGreater, uintptr_t, (StringImpl*, StringImpl*));

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp (276426 => 276427)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp	2021-04-22 07:50:02 UTC (rev 276426)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp	2021-04-22 08:27:42 UTC (rev 276427)
@@ -11782,7 +11782,11 @@
 void SpeculativeJIT::emitSwitchStringOnString(Node* node, SwitchData* data, GPRReg string)
 {
     data->didUseJumpTable = true;
-    
+
+    const UnlinkedStringJumpTable& unlinkedTable = m_graph.unlinkedStringSwitchJumpTable(data->switchTableIndex);
+    StringJumpTable& linkedTable = m_jit.graph().stringSwitchJumpTable(data->switchTableIndex);
+    linkedTable.ensureCTITable(unlinkedTable);
+
     bool canDoBinarySwitch = true;
     unsigned totalLength = 0;
     
@@ -11801,8 +11805,7 @@
 
     if (!canDoBinarySwitch || totalLength > Options::maximumBinaryStringSwitchTotalLength()) {
         flushRegisters();
-        callOperation(
-            operationSwitchString, string, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), static_cast<size_t>(data->switchTableIndex), string);
+        callOperation(operationSwitchString, string, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), static_cast<size_t>(data->switchTableIndex), &unlinkedTable, string);
         m_jit.exceptionCheck();
         m_jit.farJump(string, JSSwitchPtrTag);
         return;
@@ -11839,7 +11842,7 @@
     
     slowCases.link(&m_jit);
     silentSpillAllRegisters(string);
-    callOperation(operationSwitchString, string, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), static_cast<size_t>(data->switchTableIndex), string);
+    callOperation(operationSwitchString, string, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), static_cast<size_t>(data->switchTableIndex), &unlinkedTable, string);
     silentFillAllRegisters();
     m_jit.exceptionCheck();
     m_jit.farJump(string, JSSwitchPtrTag);

Modified: trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp (276426 => 276427)


--- trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp	2021-04-22 07:50:02 UTC (rev 276426)
+++ trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp	2021-04-22 08:27:42 UTC (rev 276427)
@@ -16742,13 +16742,13 @@
         // https://bugs.webkit.org/show_bug.cgi?id=144369
 
         JSGlobalObject* globalObject = m_graph.globalObjectFor(m_origin.semantic);
+
+        const UnlinkedStringJumpTable& unlinkedTable = m_graph.unlinkedStringSwitchJumpTable(data->switchTableIndex);
         
-        LValue branchOffset = vmCall(
-            Int32, operationSwitchStringAndGetBranchOffset,
-            weakPointer(globalObject), m_out.constIntPtr(data->switchTableIndex), string);
+        LValue branchIndex = vmCall(
+            Int32, operationSwitchStringAndGetIndex,
+            weakPointer(globalObject), m_out.constIntPtr(&unlinkedTable), string);
         
-        const UnlinkedStringJumpTable& table = codeBlock()->unlinkedStringSwitchJumpTable(data->switchTableIndex);
-        
         Vector<SwitchCase> cases;
         // These may be negative, or zero, or probably other stuff, too. We don't want to mess with HashSet's corner cases and we don't really care about throughput here.
         StdUnorderedSet<int32_t> alreadyHandled;
@@ -16785,19 +16785,20 @@
             // https://bugs.webkit.org/show_bug.cgi?id=144635
             
             DFG::SwitchCase myCase = data->cases[i];
-            auto iter = table.m_offsetTable.find(myCase.value.stringImpl());
-            DFG_ASSERT(m_graph, m_node, iter != table.m_offsetTable.end());
+            auto iter = unlinkedTable.m_offsetTable.find(myCase.value.stringImpl());
+            DFG_ASSERT(m_graph, m_node, iter != unlinkedTable.m_offsetTable.end());
             
-            if (!alreadyHandled.insert(iter->value.m_branchOffset).second)
+            // Use m_indexInTable instead of m_branchOffset to make Switch table dense.
+            if (!alreadyHandled.insert(iter->value.m_indexInTable).second)
                 continue;
 
             cases.append(SwitchCase(
-                m_out.constInt32(iter->value.m_branchOffset),
+                m_out.constInt32(iter->value.m_indexInTable),
                 lowBlock(myCase.target.block), Weight(myCase.target.count)));
         }
         
         m_out.switchInstruction(
-            branchOffset, cases, lowBlock(data->fallThrough.block),
+            branchIndex, cases, lowBlock(data->fallThrough.block),
             Weight(data->fallThrough.count));
     }
     

Modified: trunk/Source/_javascript_Core/ftl/FTLOperations.cpp (276426 => 276427)


--- trunk/Source/_javascript_Core/ftl/FTLOperations.cpp	2021-04-22 07:50:02 UTC (rev 276426)
+++ trunk/Source/_javascript_Core/ftl/FTLOperations.cpp	2021-04-22 08:27:42 UTC (rev 276427)
@@ -698,7 +698,7 @@
     }
 }
 
-JSC_DEFINE_JIT_OPERATION(operationSwitchStringAndGetBranchOffset, int32_t, (JSGlobalObject* globalObject, size_t tableIndex, JSString* string))
+JSC_DEFINE_JIT_OPERATION(operationSwitchStringAndGetIndex, unsigned, (JSGlobalObject* globalObject, const UnlinkedStringJumpTable* unlinkedTable, JSString* string))
 {
     VM& vm = globalObject->vm();
     CallFrame* callFrame = DECLARE_CALL_FRAME(vm);
@@ -709,7 +709,7 @@
 
     RETURN_IF_EXCEPTION(throwScope, 0);
 
-    return callFrame->codeBlock()->unlinkedStringSwitchJumpTable(tableIndex).offsetForValue(strImpl, std::numeric_limits<int32_t>::min());
+    return unlinkedTable->indexForValue(strImpl, std::numeric_limits<unsigned>::max());
 }
 
 JSC_DEFINE_JIT_OPERATION(operationTypeOfObjectAsTypeofType, int32_t, (JSGlobalObject* globalObject, JSCell* object))

Modified: trunk/Source/_javascript_Core/ftl/FTLOperations.h (276426 => 276427)


--- trunk/Source/_javascript_Core/ftl/FTLOperations.h	2021-04-22 07:50:02 UTC (rev 276426)
+++ trunk/Source/_javascript_Core/ftl/FTLOperations.h	2021-04-22 08:27:42 UTC (rev 276427)
@@ -30,8 +30,12 @@
 #include "DFGOperations.h"
 #include "FTLExitTimeObjectMaterialization.h"
 
-namespace JSC { namespace FTL {
+namespace JSC {
 
+struct UnlinkedStringJumpTable;
+
+namespace FTL {
+
 class LazySlowPath;
 
 JSC_DECLARE_JIT_OPERATION(operationMaterializeObjectInOSR, JSCell*, (JSGlobalObject*, ExitTimeObjectMaterialization*, EncodedJSValue*));
@@ -40,7 +44,7 @@
 
 JSC_DECLARE_JIT_OPERATION(operationCompileFTLLazySlowPath, void*, (CallFrame*, unsigned));
 
-JSC_DECLARE_JIT_OPERATION(operationSwitchStringAndGetBranchOffset, int32_t, (JSGlobalObject*, size_t tableIndex, JSString*));
+JSC_DECLARE_JIT_OPERATION(operationSwitchStringAndGetIndex, unsigned, (JSGlobalObject*, const UnlinkedStringJumpTable*, JSString*));
 JSC_DECLARE_JIT_OPERATION(operationTypeOfObjectAsTypeofType, int32_t, (JSGlobalObject*, JSCell*));
 
 JSC_DECLARE_JIT_OPERATION(operationReportBoundsCheckEliminationErrorAndCrash, void, (intptr_t codeBlockAsIntPtr, int32_t, int32_t, int32_t, int32_t, int32_t));

Modified: trunk/Source/_javascript_Core/jit/JIT.cpp (276426 => 276427)


--- trunk/Source/_javascript_Core/jit/JIT.cpp	2021-04-22 07:50:02 UTC (rev 276426)
+++ trunk/Source/_javascript_Core/jit/JIT.cpp	2021-04-22 08:27:42 UTC (rev 276427)
@@ -868,15 +868,14 @@
     // Translate vPC offsets into addresses in JIT generated code, for switch tables.
     for (auto& record : m_switches) {
         unsigned bytecodeOffset = record.bytecodeIndex.offset();
+        unsigned tableIndex = record.tableIndex;
 
-        if (record.type != SwitchRecord::String) {
-            ASSERT(record.type == SwitchRecord::Immediate || record.type == SwitchRecord::Character); 
-
-            unsigned tableIndex = record.tableIndex;
+        switch (record.type) {
+        case SwitchRecord::Immediate:
+        case SwitchRecord::Character: {
             const UnlinkedSimpleJumpTable& unlinkedTable = m_codeBlock->unlinkedSwitchJumpTable(tableIndex);
             SimpleJumpTable& linkedTable = m_codeBlock->switchJumpTable(tableIndex);
             linkedTable.m_ctiDefault = patchBuffer.locationOf<JSSwitchPtrTag>(m_labels[bytecodeOffset + record.defaultOffset]);
-
             for (unsigned j = 0; j < unlinkedTable.m_branchOffsets.size(); ++j) {
                 unsigned offset = unlinkedTable.m_branchOffsets[j];
                 linkedTable.m_ctiOffsets[j] = offset
@@ -883,22 +882,23 @@
                     ? patchBuffer.locationOf<JSSwitchPtrTag>(m_labels[bytecodeOffset + offset])
                     : linkedTable.m_ctiDefault;
             }
-        } else {
-            ASSERT(record.type == SwitchRecord::String);
+            break;
+        }
 
-            unsigned tableIndex = record.tableIndex;
+        case SwitchRecord::String: {
             const UnlinkedStringJumpTable& unlinkedTable = m_codeBlock->unlinkedStringSwitchJumpTable(tableIndex);
             StringJumpTable& linkedTable = m_codeBlock->stringSwitchJumpTable(tableIndex);
-            linkedTable.m_ctiDefault = patchBuffer.locationOf<JSSwitchPtrTag>(m_labels[bytecodeOffset + record.defaultOffset]);
-            linkedTable.m_ctiOffsets = FixedVector<CodeLocationLabel<JSSwitchPtrTag>>(unlinkedTable.m_offsetTable.size());
-
+            auto ctiDefault = patchBuffer.locationOf<JSSwitchPtrTag>(m_labels[bytecodeOffset + record.defaultOffset]);
             for (auto& location : unlinkedTable.m_offsetTable.values()) {
                 unsigned offset = location.m_branchOffset;
                 linkedTable.m_ctiOffsets[location.m_indexInTable] = offset
                     ? patchBuffer.locationOf<JSSwitchPtrTag>(m_labels[bytecodeOffset + offset])
-                    : linkedTable.m_ctiDefault;
+                    : ctiDefault;
             }
+            linkedTable.m_ctiOffsets[unlinkedTable.m_offsetTable.size()] = ctiDefault;
+            break;
         }
+        }
     }
 
     for (size_t i = 0; i < m_codeBlock->numberOfExceptionHandlers(); ++i) {

Modified: trunk/Source/_javascript_Core/jit/JITOpcodes.cpp (276426 => 276427)


--- trunk/Source/_javascript_Core/jit/JITOpcodes.cpp	2021-04-22 07:50:02 UTC (rev 276426)
+++ trunk/Source/_javascript_Core/jit/JITOpcodes.cpp	2021-04-22 08:27:42 UTC (rev 276427)
@@ -940,7 +940,10 @@
     VirtualRegister scrutinee = bytecode.m_scrutinee;
 
     // create jump table for switch destinations, track this switch statement.
+    const UnlinkedStringJumpTable& unlinkedTable = m_codeBlock->unlinkedStringSwitchJumpTable(tableIndex);
+    StringJumpTable& linkedTable = m_codeBlock->stringSwitchJumpTable(tableIndex);
     m_switches.append(SwitchRecord(tableIndex, m_bytecodeIndex, defaultOffset, SwitchRecord::String));
+    linkedTable.ensureCTITable(unlinkedTable);
 
     emitGetVirtualRegister(scrutinee, regT0);
     callOperation(operationSwitchStringWithUnknownKeyType, TrustedImmPtr(m_codeBlock->globalObject()), regT0, tableIndex);

Modified: trunk/Source/_javascript_Core/jit/JITOpcodes32_64.cpp (276426 => 276427)


--- trunk/Source/_javascript_Core/jit/JITOpcodes32_64.cpp	2021-04-22 07:50:02 UTC (rev 276426)
+++ trunk/Source/_javascript_Core/jit/JITOpcodes32_64.cpp	2021-04-22 08:27:42 UTC (rev 276427)
@@ -1030,7 +1030,10 @@
     VirtualRegister scrutinee = bytecode.m_scrutinee;
 
     // create jump table for switch destinations, track this switch statement.
+    const UnlinkedStringJumpTable& unlinkedTable = m_codeBlock->unlinkedStringSwitchJumpTable(tableIndex);
+    StringJumpTable& linkedTable = m_codeBlock->stringSwitchJumpTable(tableIndex);
     m_switches.append(SwitchRecord(tableIndex, m_bytecodeIndex, defaultOffset, SwitchRecord::String));
+    linkedTable.ensureCTITable(unlinkedTable);
 
     emitLoad(scrutinee, regT1, regT0);
     callOperation(operationSwitchStringWithUnknownKeyType, m_codeBlock->globalObject(), JSValueRegs(regT1, regT0), tableIndex);

Modified: trunk/Source/_javascript_Core/jit/JITOperations.cpp (276426 => 276427)


--- trunk/Source/_javascript_Core/jit/JITOperations.cpp	2021-04-22 07:50:02 UTC (rev 276426)
+++ trunk/Source/_javascript_Core/jit/JITOperations.cpp	2021-04-22 08:27:42 UTC (rev 276427)
@@ -2859,7 +2859,7 @@
         const UnlinkedStringJumpTable& unlinkedTable = codeBlock->unlinkedStringSwitchJumpTable(tableIndex);
         result = linkedTable.ctiForValue(unlinkedTable, value).executableAddress();
     } else
-        result = linkedTable.m_ctiDefault.executableAddress();
+        result = linkedTable.ctiDefault().executableAddress();
 
     assertIsTaggedWith<JSSwitchPtrTag>(result);
     return reinterpret_cast<char*>(result);
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to