From ab8e6b319b095978cc8cabf47fca1eeb08229337 Mon Sep 17 00:00:00 2001 From: Sosuke Suzuki Date: Thu, 20 Aug 2026 14:25:31 +0900 Subject: [PATCH] [JSC] Cap the per-thread cached AssemblerBuffer size takeBufferIfLarger() only ever grows the ThreadSpecific slot, so one huge Baseline compile pins its scratch buffer to the thread for the life of the process. Add Options::maximumCachedAssemblerBufferSize (default 1 MB, 0 = unbounded) and free anything larger instead of caching it. Same for BranchCompactionLinkBuffer on ARM64. --- Source/JavaScriptCore/assembler/AssemblerBuffer.h | 14 +++++++++----- Source/JavaScriptCore/assembler/LinkBuffer.cpp | 7 +++++-- Source/JavaScriptCore/runtime/OptionsList.h | 1 + 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/Source/JavaScriptCore/assembler/AssemblerBuffer.h b/Source/JavaScriptCore/assembler/AssemblerBuffer.h index 349972a705dcf..2ba8682bd633c 100644 --- a/Source/JavaScriptCore/assembler/AssemblerBuffer.h +++ b/Source/JavaScriptCore/assembler/AssemblerBuffer.h @@ -185,14 +185,18 @@ namespace JSC { ~AssemblerDataImpl() { - if constexpr (type == AssemblerDataType::Code) - threadSpecificAssemblerData()->takeBufferIfLarger(*this); + // A one-off huge compile would otherwise pin its scratch buffer to this thread forever. + unsigned cacheLimit = Options::maximumCachedAssemblerBufferSize(); + if (!cacheLimit || m_capacity <= cacheLimit) { + if constexpr (type == AssemblerDataType::Code) + threadSpecificAssemblerData()->takeBufferIfLarger(*this); #if ENABLE(JIT_SIGN_ASSEMBLER_BUFFER) - if constexpr (type == AssemblerDataType::Hashes) - threadSpecificAssemblerHashes()->takeBufferIfLarger(*this); + if constexpr (type == AssemblerDataType::Hashes) + threadSpecificAssemblerHashes()->takeBufferIfLarger(*this); #else - static_assert(type != AssemblerDataType::Hashes); + static_assert(type != AssemblerDataType::Hashes); #endif + } clear(); } diff --git a/Source/JavaScriptCore/assembler/LinkBuffer.cpp b/Source/JavaScriptCore/assembler/LinkBuffer.cpp index 42b781b919072..af83d9d828a0d 100644 --- a/Source/JavaScriptCore/assembler/LinkBuffer.cpp +++ b/Source/JavaScriptCore/assembler/LinkBuffer.cpp @@ -235,8 +235,11 @@ class BranchCompactionLinkBuffer { if (m_bufferProvided) return; - auto& threadSpecific = threadSpecificBranchCompactionLinkBuffer(); - threadSpecific->takeBufferIfLarger(*this); + size_t cacheLimit = Options::maximumCachedAssemblerBufferSize(); + if (!cacheLimit || m_size <= cacheLimit) { + auto& threadSpecific = threadSpecificBranchCompactionLinkBuffer(); + threadSpecific->takeBufferIfLarger(*this); + } if (m_data) BranchCompactionLinkBufferMalloc::free(m_data); diff --git a/Source/JavaScriptCore/runtime/OptionsList.h b/Source/JavaScriptCore/runtime/OptionsList.h index f7b49fa805da8..d5a3903bff6ba 100644 --- a/Source/JavaScriptCore/runtime/OptionsList.h +++ b/Source/JavaScriptCore/runtime/OptionsList.h @@ -335,6 +335,7 @@ bool hasCapacityToUseLargeGigacage(); v(Bool, breakOnThrow, false, Normal, nullptr) \ \ v(Unsigned, maximumOptimizationCandidateBytecodeCost, 100000, Normal, nullptr) \ + v(Unsigned, maximumCachedAssemblerBufferSize, 1 * MB, Normal, "Assembler scratch buffers larger than this are freed after compilation instead of being cached per thread (0 = cache any size)"_s) \ \ v(Unsigned, maximumFunctionForCallInlineCandidateBytecodeCostForDFG, 80, Normal, nullptr) \ v(Unsigned, maximumFunctionForClosureCallInlineCandidateBytecodeCostForDFG, 80, Normal, nullptr) \