WebKit Bugzilla
Attachment 362383 Details for
Bug 194810
: Lazily decode cached bytecode
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch
bug-194810-20190219155535.patch (text/plain), 15.59 KB, created by
Tadeu Zagallo
on 2019-02-19 06:56:13 PST
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Tadeu Zagallo
Created:
2019-02-19 06:56:13 PST
Size:
15.59 KB
patch
obsolete
>Subversion Revision: 241760 >diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog >index 6c2f02508f0426495ee4591332883cb4c6ba02d3..4c1082a0df373a8f6e4affd11fa8ca225923c6ac 100644 >--- a/Source/JavaScriptCore/ChangeLog >+++ b/Source/JavaScriptCore/ChangeLog >@@ -1,3 +1,44 @@ >+2019-02-19 Tadeu Zagallo <tzagallo@apple.com> >+ >+ Lazily decode cached bytecode >+ https://bugs.webkit.org/show_bug.cgi?id=194810 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Like lazy parsing, we should pause at code block boundaries. Instead >+ of decoding UnlinkedFunctionExecutable's CodeBlocks, we store their >+ offsets in the executable and lazily decode them on the next call to >+ `unlinkedCodeBlockFor`. >+ >+ * bytecode/UnlinkedFunctionExecutable.cpp: >+ (JSC::UnlinkedFunctionExecutable::UnlinkedFunctionExecutable): >+ (JSC::UnlinkedFunctionExecutable::~UnlinkedFunctionExecutable): >+ (JSC::UnlinkedFunctionExecutable::visitChildren): >+ (JSC::UnlinkedFunctionExecutable::unlinkedCodeBlockFor): >+ (JSC::UnlinkedFunctionExecutable::decodeCachedCodeBlocks): >+ * bytecode/UnlinkedFunctionExecutable.h: >+ * runtime/CachedTypes.cpp: >+ (JSC::CachedPtr::isEmpty const): >+ (JSC::CachedWriteBarrier::isEmpty const): >+ (JSC::CachedFunctionExecutable::decode const): >+ (JSC::UnlinkedFunctionExecutable::UnlinkedFunctionExecutable): >+ (JSC::decodeCodeBlockImpl): >+ (JSC::decodeFunctionCodeBlock): >+ (JSC::Decoder::Decoder): Deleted. >+ (JSC::Decoder::~Decoder): Deleted. >+ (JSC::Decoder::vm): Deleted. >+ (JSC::Decoder::offsetOf): Deleted. >+ (JSC::Decoder::cacheOffset): Deleted. >+ (JSC::Decoder::addFinalizer): Deleted. >+ * runtime/CachedTypes.h: >+ (JSC::Decoder::Decoder): >+ (JSC::Decoder::~Decoder): >+ (JSC::Decoder::vm): >+ (JSC::Decoder::offsetOf): >+ (JSC::Decoder::cacheOffset): >+ (JSC::Decoder::ptrForOffsetFromBase): >+ (JSC::Decoder::addFinalizer): >+ > 2019-02-19 Tadeu Zagallo <tzagallo@apple.com> > > Move bytecode cache-related filesystem code out of CodeCache >diff --git a/Source/JavaScriptCore/bytecode/UnlinkedFunctionExecutable.cpp b/Source/JavaScriptCore/bytecode/UnlinkedFunctionExecutable.cpp >index a142c24055e9b3be412e361428dc1fccc16391d8..2420e784fb85124bd1851b8287291eb464092bd7 100644 >--- a/Source/JavaScriptCore/bytecode/UnlinkedFunctionExecutable.cpp >+++ b/Source/JavaScriptCore/bytecode/UnlinkedFunctionExecutable.cpp >@@ -28,6 +28,7 @@ > > #include "BuiltinExecutables.h" > #include "BytecodeGenerator.h" >+#include "CachedTypes.h" > #include "ClassInfo.h" > #include "CodeCache.h" > #include "Debugger.h" >@@ -103,6 +104,9 @@ UnlinkedFunctionExecutable::UnlinkedFunctionExecutable(VM* vm, Structure* struct > , m_scriptMode(static_cast<unsigned>(scriptMode)) > , m_superBinding(static_cast<unsigned>(node->superBinding())) > , m_derivedContextType(static_cast<unsigned>(derivedContextType)) >+ , m_isCached(false) >+ , m_unlinkedCodeBlockForCall() >+ , m_unlinkedCodeBlockForConstruct() > , m_name(node->ident()) > , m_ecmaName(node->ecmaName()) > , m_inferredName(node->inferredName()) >@@ -120,6 +124,12 @@ UnlinkedFunctionExecutable::UnlinkedFunctionExecutable(VM* vm, Structure* struct > setClassSource(node->classSource()); > } > >+UnlinkedFunctionExecutable::~UnlinkedFunctionExecutable() >+{ >+ if (m_isCached) >+ m_decoder.~RefPtr(); >+} >+ > void UnlinkedFunctionExecutable::destroy(JSCell* cell) > { > static_cast<UnlinkedFunctionExecutable*>(cell)->~UnlinkedFunctionExecutable(); >@@ -130,8 +140,10 @@ void UnlinkedFunctionExecutable::visitChildren(JSCell* cell, SlotVisitor& visito > UnlinkedFunctionExecutable* thisObject = jsCast<UnlinkedFunctionExecutable*>(cell); > ASSERT_GC_OBJECT_INHERITS(thisObject, info()); > Base::visitChildren(thisObject, visitor); >- visitor.append(thisObject->m_unlinkedCodeBlockForCall); >- visitor.append(thisObject->m_unlinkedCodeBlockForConstruct); >+ if (!thisObject->m_isCached) { >+ visitor.append(thisObject->m_unlinkedCodeBlockForCall); >+ visitor.append(thisObject->m_unlinkedCodeBlockForConstruct); >+ } > } > > SourceCode UnlinkedFunctionExecutable::linkedSourceCode(const SourceCode& passedParentSource) const >@@ -213,6 +225,8 @@ UnlinkedFunctionCodeBlock* UnlinkedFunctionExecutable::unlinkedCodeBlockFor( > VM& vm, const SourceCode& source, CodeSpecializationKind specializationKind, > DebuggerMode debuggerMode, ParserError& error, SourceParseMode parseMode) > { >+ if (m_isCached) >+ decodeCachedCodeBlocks(); > switch (specializationKind) { > case CodeForCall: > if (UnlinkedFunctionCodeBlock* codeBlock = m_unlinkedCodeBlockForCall.get()) >@@ -244,6 +258,29 @@ UnlinkedFunctionCodeBlock* UnlinkedFunctionExecutable::unlinkedCodeBlockFor( > return result; > } > >+void UnlinkedFunctionExecutable::decodeCachedCodeBlocks() >+{ >+ ASSERT(m_isCached); >+ ASSERT(m_decoder); >+ ASSERT(m_cachedCodeBlockForCallOffset || m_cachedCodeBlockForConstructOffset); >+ >+ RefPtr<Decoder> decoder = WTFMove(m_decoder); >+ int32_t cachedCodeBlockForCallOffset = m_cachedCodeBlockForCallOffset; >+ int32_t cachedCodeBlockForConstructOffset = m_cachedCodeBlockForConstructOffset; >+ >+ DeferGC deferGC(decoder->vm().heap); >+ >+ // No need to clear m_unlinkedCodeBlockForCall here, since we moved the decoder out of the same slot >+ if (cachedCodeBlockForCallOffset) >+ decodeFunctionCodeBlock(*decoder, cachedCodeBlockForCallOffset, m_unlinkedCodeBlockForCall, this); >+ if (cachedCodeBlockForConstructOffset) >+ decodeFunctionCodeBlock(*decoder, cachedCodeBlockForConstructOffset, m_unlinkedCodeBlockForConstruct, this); >+ else >+ m_unlinkedCodeBlockForConstruct.clear(); >+ >+ m_isCached = false; >+} >+ > UnlinkedFunctionExecutable::RareData& UnlinkedFunctionExecutable::ensureRareDataSlow() > { > ASSERT(!m_rareData); >diff --git a/Source/JavaScriptCore/bytecode/UnlinkedFunctionExecutable.h b/Source/JavaScriptCore/bytecode/UnlinkedFunctionExecutable.h >index defd2f08b87181e6b7f4ff60156907fdb6eb397f..3fa19e42d55e9840fb41f511770788d48bd0aaed 100644 >--- a/Source/JavaScriptCore/bytecode/UnlinkedFunctionExecutable.h >+++ b/Source/JavaScriptCore/bytecode/UnlinkedFunctionExecutable.h >@@ -75,6 +75,8 @@ public: > return instance; > } > >+ ~UnlinkedFunctionExecutable(); >+ > const Identifier& name() const { return m_name; } > const Identifier& ecmaName() const { return m_ecmaName; } > void setEcmaName(const Identifier& name) { m_ecmaName = name; } >@@ -193,6 +195,8 @@ private: > UnlinkedFunctionExecutable(VM*, Structure*, const SourceCode&, FunctionMetadataNode*, UnlinkedFunctionKind, ConstructAbility, JSParserScriptMode, CompactVariableMap::Handle, JSC::DerivedContextType, bool isBuiltinDefaultClassConstructor); > UnlinkedFunctionExecutable(Decoder&, VariableEnvironment&, const CachedFunctionExecutable&); > >+ void decodeCachedCodeBlocks(); >+ > unsigned m_firstLineOffset; > unsigned m_lineCount; > unsigned m_unlinkedFunctionNameStart; >@@ -216,9 +220,20 @@ private: > unsigned m_scriptMode: 1; // JSParserScriptMode > unsigned m_superBinding : 1; > unsigned m_derivedContextType: 2; >- >- WriteBarrier<UnlinkedFunctionCodeBlock> m_unlinkedCodeBlockForCall; >- WriteBarrier<UnlinkedFunctionCodeBlock> m_unlinkedCodeBlockForConstruct; >+ bool m_isCached : 1; >+ >+ union { >+ struct { >+ WriteBarrier<UnlinkedFunctionCodeBlock> m_unlinkedCodeBlockForCall; >+ WriteBarrier<UnlinkedFunctionCodeBlock> m_unlinkedCodeBlockForConstruct; >+ }; >+ >+ struct { >+ RefPtr<Decoder> m_decoder; >+ int32_t m_cachedCodeBlockForCallOffset; >+ int32_t m_cachedCodeBlockForConstructOffset; >+ }; >+ }; > > Identifier m_name; > Identifier m_ecmaName; >diff --git a/Source/JavaScriptCore/runtime/CachedTypes.cpp b/Source/JavaScriptCore/runtime/CachedTypes.cpp >index acd95dfa9650ed01346215da43799285cf4662f8..94742ba64c009438339a349be7cc1ee08d381bd6 100644 >--- a/Source/JavaScriptCore/runtime/CachedTypes.cpp >+++ b/Source/JavaScriptCore/runtime/CachedTypes.cpp >@@ -210,65 +210,6 @@ private: > HashMap<const void*, ptrdiff_t> m_ptrToOffsetMap; > }; > >-class Decoder { >- WTF_MAKE_NONCOPYABLE(Decoder); >- WTF_FORBID_HEAP_ALLOCATION; >- >-public: >- Decoder(VM& vm, const void* baseAddress, size_t size) >- : m_vm(vm) >- , m_baseAddress(reinterpret_cast<const uint8_t*>(baseAddress)) >-#ifndef NDEBUG >- , m_size(size) >-#endif >- { >- UNUSED_PARAM(size); >- } >- >- ~Decoder() >- { >- for (auto& pair : m_finalizers) >- pair.value(); >- } >- >- VM& vm() { return m_vm; } >- >- ptrdiff_t offsetOf(const void* ptr) >- { >- const uint8_t* addr = static_cast<const uint8_t*>(ptr); >- ASSERT(addr >= m_baseAddress && addr < m_baseAddress + m_size); >- return addr - m_baseAddress; >- } >- >- void cacheOffset(ptrdiff_t offset, void* ptr) >- { >- m_offsetToPtrMap.add(offset, ptr); >- } >- >- WTF::Optional<void*> ptrForOffset(ptrdiff_t offset) >- { >- auto it = m_offsetToPtrMap.find(offset); >- if (it == m_offsetToPtrMap.end()) >- return WTF::nullopt; >- return { it->value }; >- } >- >- template<typename Functor> >- void addFinalizer(ptrdiff_t offset, const Functor& fn) >- { >- m_finalizers.add(offset, fn); >- } >- >-private: >- VM& m_vm; >- const uint8_t* m_baseAddress; >-#ifndef NDEBUG >- size_t m_size; >-#endif >- HashMap<ptrdiff_t, void*> m_offsetToPtrMap; >- HashMap<ptrdiff_t, std::function<void()>> m_finalizers; >-}; >- > template<typename T> > static std::enable_if_t<std::is_same<T, SourceType<T>>::value> encode(Encoder&, T& dst, const SourceType<T>& src) > { >@@ -371,6 +312,8 @@ class CachedPtr : public VariableLengthObject<Source*> { > friend struct CachedRefPtr; > > public: >+ bool isEmpty() const { return m_isEmpty; } >+ > void encode(Encoder& encoder, const Source* src) > { > m_isEmpty = !src; >@@ -451,6 +394,8 @@ private: > template<typename T, typename Source = SourceType<T>> > class CachedWriteBarrier : public CachedObject<WriteBarrier<Source>> { > public: >+ bool isEmpty() const { return m_ptr.isEmpty(); } >+ > void encode(Encoder& encoder, const WriteBarrier<Source> src) > { > m_ptr.encode(encoder, src.get()); >@@ -1866,8 +1811,14 @@ ALWAYS_INLINE UnlinkedFunctionExecutable* CachedFunctionExecutable::decode(Decod > UnlinkedFunctionExecutable* executable = new (NotNull, allocateCell<UnlinkedFunctionExecutable>(decoder.vm().heap)) UnlinkedFunctionExecutable(decoder, env, *this); > executable->finishCreation(decoder.vm()); > >- m_unlinkedCodeBlockForCall.decode(decoder, executable->m_unlinkedCodeBlockForCall, executable); >- m_unlinkedCodeBlockForConstruct.decode(decoder, executable->m_unlinkedCodeBlockForConstruct, executable); >+ if (!m_unlinkedCodeBlockForCall.isEmpty() || !m_unlinkedCodeBlockForConstruct.isEmpty()) { >+ executable->m_isCached = true; >+ executable->m_decoder = &decoder; >+ if (!m_unlinkedCodeBlockForCall.isEmpty()) >+ executable->m_cachedCodeBlockForCallOffset = decoder.offsetOf(&m_unlinkedCodeBlockForCall); >+ if (!m_unlinkedCodeBlockForConstruct.isEmpty()) >+ executable->m_cachedCodeBlockForConstructOffset = decoder.offsetOf(&m_unlinkedCodeBlockForConstruct); >+ } > > return executable; > } >@@ -1897,6 +1848,9 @@ ALWAYS_INLINE UnlinkedFunctionExecutable::UnlinkedFunctionExecutable(Decoder& de > , m_scriptMode(cachedExecutable.scriptMode()) > , m_superBinding(cachedExecutable.superBinding()) > , m_derivedContextType(cachedExecutable.derivedContextType()) >+ , m_isCached(false) >+ , m_unlinkedCodeBlockForCall() >+ , m_unlinkedCodeBlockForConstruct() > > , m_name(cachedExecutable.name(decoder)) > , m_ecmaName(cachedExecutable.ecmaName(decoder)) >@@ -2083,11 +2037,11 @@ std::pair<MallocPtr<uint8_t>, size_t> encodeCodeBlock(VM& vm, const SourceCodeKe > UnlinkedCodeBlock* decodeCodeBlockImpl(VM& vm, const SourceCodeKey& key, const void* buffer, size_t size) > { > const auto* cachedEntry = reinterpret_cast<const GenericCacheEntry*>(buffer); >- Decoder decoder(vm, buffer, size); >+ RefPtr<Decoder> decoder = adoptRef(new Decoder(vm, buffer, size)); > std::pair<SourceCodeKey, UnlinkedCodeBlock*> entry; > { > DeferGC deferGC(vm.heap); >- if (!cachedEntry->decode(decoder, entry)) >+ if (!cachedEntry->decode(*decoder, entry)) > return nullptr; > } > >@@ -2096,4 +2050,11 @@ UnlinkedCodeBlock* decodeCodeBlockImpl(VM& vm, const SourceCodeKey& key, const v > return entry.second; > } > >+void decodeFunctionCodeBlock(Decoder& decoder, int32_t cachedFunctionCodeBlockOffset, WriteBarrier<UnlinkedFunctionCodeBlock>& codeBlock, const JSCell* owner) >+{ >+ ASSERT(decoder.vm().heap.isDeferred()); >+ auto* cachedCodeBlock = static_cast<const CachedWriteBarrier<CachedFunctionCodeBlock, UnlinkedFunctionCodeBlock>*>(decoder.ptrForOffsetFromBase(cachedFunctionCodeBlockOffset)); >+ cachedCodeBlock->decode(decoder, codeBlock, owner); >+} >+ > } // namespace JSC >diff --git a/Source/JavaScriptCore/runtime/CachedTypes.h b/Source/JavaScriptCore/runtime/CachedTypes.h >index bcb8acb6ce570e9726389c26d70bcba21da8d4ad..33bfafd53910029269ecbaab7e4d42182b12f797 100644 >--- a/Source/JavaScriptCore/runtime/CachedTypes.h >+++ b/Source/JavaScriptCore/runtime/CachedTypes.h >@@ -32,10 +32,82 @@ namespace JSC { > > class SourceCodeKey; > class UnlinkedCodeBlock; >+class UnlinkedFunctionCodeBlock; >+ >+template<typename T, typename Source> >+class CachedWriteBarrier; >+ >+class Decoder : public RefCounted<Decoder> { >+ WTF_MAKE_NONCOPYABLE(Decoder); >+ >+public: >+ Decoder(VM& vm, const void* baseAddress, size_t size) >+ : m_vm(vm) >+ , m_baseAddress(reinterpret_cast<const uint8_t*>(baseAddress)) >+#ifndef NDEBUG >+ , m_size(size) >+#endif >+ { >+ UNUSED_PARAM(size); >+ } >+ >+ ~Decoder() >+ { >+ for (auto& pair : m_finalizers) >+ pair.value(); >+ } >+ >+ VM& vm() { return m_vm; } >+ >+ ptrdiff_t offsetOf(const void* ptr) >+ { >+ const uint8_t* addr = static_cast<const uint8_t*>(ptr); >+ ASSERT(addr >= m_baseAddress && addr < m_baseAddress + m_size); >+ return addr - m_baseAddress; >+ } >+ >+ void cacheOffset(ptrdiff_t offset, void* ptr) >+ { >+ m_offsetToPtrMap.add(offset, ptr); >+ } >+ >+ WTF::Optional<void*> ptrForOffset(ptrdiff_t offset) >+ { >+ auto it = m_offsetToPtrMap.find(offset); >+ if (it == m_offsetToPtrMap.end()) >+ return WTF::nullopt; >+ return { it->value }; >+ } >+ >+ const void* ptrForOffsetFromBase(ptrdiff_t offset) >+ { >+#ifndef NDEBUG >+ ASSERT(offset > 0 && static_cast<size_t>(offset) < m_size); >+#endif >+ return m_baseAddress + offset; >+ } >+ >+ template<typename Functor> >+ void addFinalizer(ptrdiff_t offset, const Functor& fn) >+ { >+ m_finalizers.add(offset, fn); >+ } >+ >+private: >+ VM& m_vm; >+ const uint8_t* m_baseAddress; >+#ifndef NDEBUG >+ size_t m_size; >+#endif >+ HashMap<ptrdiff_t, void*> m_offsetToPtrMap; >+ HashMap<ptrdiff_t, std::function<void()>> m_finalizers; >+}; > > std::pair<MallocPtr<uint8_t>, size_t> encodeCodeBlock(VM&, const SourceCodeKey&, const UnlinkedCodeBlock*); >+ > UnlinkedCodeBlock* decodeCodeBlockImpl(VM&, const SourceCodeKey&, const void*, size_t); > >+void decodeFunctionCodeBlock(Decoder&, int32_t cachedFunctionCodeBlockOffset, WriteBarrier<UnlinkedFunctionCodeBlock>&, const JSCell*); > > template<typename UnlinkedCodeBlockType> > UnlinkedCodeBlockType* decodeCodeBlock(VM& vm, const SourceCodeKey& key, const void* buffer, size_t size)
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 194810
:
362383
|
362495
|
363525
|
363558
|
363901