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);