Add support for incremental bytecode cache updates
authortzagallo@apple.com <tzagallo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 10 Apr 2019 19:18:20 +0000 (19:18 +0000)
committertzagallo@apple.com <tzagallo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 10 Apr 2019 19:18:20 +0000 (19:18 +0000)
https://bugs.webkit.org/show_bug.cgi?id=195000

Reviewed by Filip Pizlo.

Source/JavaScriptCore:

Add support for incremental updates to the bytecode cache. The cache
is constructed as follows:
- When the cache is empty, the initial payload can be added to the BytecodeCache
by calling BytecodeCache::addGlobalUpdate. This represents the encoded
top-level UnlinkedCodeBlock.
- Afterwards, updates can be added by calling BytecodeCache::addFunctionUpdate.
The update is applied by appending the encoded UnlinkedFunctionCodeBlock
to the existing cache and updating the CachedFunctionExecutableMetadata
and the offset of the new CachedFunctionCodeBlock in the owner CachedFunctionExecutable.

* API/JSScript.mm:
(-[JSScript readCache]):
(-[JSScript isUsingBytecodeCache]):
(-[JSScript init]):
(-[JSScript cachedBytecode]):
(-[JSScript writeCache:]):
* API/JSScriptInternal.h:
* API/JSScriptSourceProvider.h:
* API/JSScriptSourceProvider.mm:
(JSScriptSourceProvider::cachedBytecode const):
* CMakeLists.txt:
* JavaScriptCore.xcodeproj/project.pbxproj:
* Sources.txt:
* bytecode/UnlinkedFunctionExecutable.cpp:
(JSC::generateUnlinkedFunctionCodeBlock):
* jsc.cpp:
(ShellSourceProvider::~ShellSourceProvider):
(ShellSourceProvider::cachePath const):
(ShellSourceProvider::loadBytecode const):
(ShellSourceProvider::ShellSourceProvider):
(ShellSourceProvider::cacheEnabled):
* parser/SourceProvider.h:
(JSC::SourceProvider::cachedBytecode const):
(JSC::SourceProvider::updateCache const):
(JSC::SourceProvider::commitCachedBytecode const):
* runtime/CachePayload.cpp: Copied from Source/JavaScriptCore/API/JSScriptInternal.h.
(JSC::CachePayload::makeMappedPayload):
(JSC::CachePayload::makeMallocPayload):
(JSC::CachePayload::makeEmptyPayload):
(JSC::CachePayload::CachePayload):
(JSC::CachePayload::~CachePayload):
(JSC::CachePayload::operator=):
(JSC::CachePayload::freeData):
* runtime/CachePayload.h: Copied from Source/JavaScriptCore/API/JSScriptInternal.h.
(JSC::CachePayload::data const):
(JSC::CachePayload::size const):
(JSC::CachePayload::CachePayload):
* runtime/CacheUpdate.cpp: Copied from Source/JavaScriptCore/API/JSScriptInternal.h.
(JSC::CacheUpdate::CacheUpdate):
(JSC::CacheUpdate::operator=):
(JSC::CacheUpdate::isGlobal const):
(JSC::CacheUpdate::asGlobal const):
(JSC::CacheUpdate::asFunction const):
* runtime/CacheUpdate.h: Copied from Source/JavaScriptCore/API/JSScriptInternal.h.
* runtime/CachedBytecode.cpp: Added.
(JSC::CachedBytecode::addGlobalUpdate):
(JSC::CachedBytecode::addFunctionUpdate):
(JSC::CachedBytecode::copyLeafExecutables):
(JSC::CachedBytecode::commitUpdates const):
* runtime/CachedBytecode.h: Added.
(JSC::CachedBytecode::create):
(JSC::CachedBytecode::leafExecutables):
(JSC::CachedBytecode::data const):
(JSC::CachedBytecode::size const):
(JSC::CachedBytecode::hasUpdates const):
(JSC::CachedBytecode::sizeForUpdate const):
(JSC::CachedBytecode::CachedBytecode):
* runtime/CachedTypes.cpp:
(JSC::Encoder::addLeafExecutable):
(JSC::Encoder::release):
(JSC::Decoder::Decoder):
(JSC::Decoder::create):
(JSC::Decoder::size const):
(JSC::Decoder::offsetOf):
(JSC::Decoder::ptrForOffsetFromBase):
(JSC::Decoder::addLeafExecutable):
(JSC::VariableLengthObject::VariableLengthObject):
(JSC::VariableLengthObject::buffer const):
(JSC::CachedPtrOffsets::offsetOffset):
(JSC::CachedWriteBarrierOffsets::ptrOffset):
(JSC::CachedFunctionExecutable::features const):
(JSC::CachedFunctionExecutable::hasCapturedVariables const):
(JSC::CachedFunctionExecutableOffsets::codeBlockForCallOffset):
(JSC::CachedFunctionExecutableOffsets::codeBlockForConstructOffset):
(JSC::CachedFunctionExecutableOffsets::metadataOffset):
(JSC::CachedFunctionExecutable::encode):
(JSC::CachedFunctionExecutable::decode const):
(JSC::UnlinkedFunctionExecutable::UnlinkedFunctionExecutable):
(JSC::encodeCodeBlock):
(JSC::encodeFunctionCodeBlock):
(JSC::decodeCodeBlockImpl):
(JSC::isCachedBytecodeStillValid):
* runtime/CachedTypes.h:
(JSC::VariableLengthObjectBase::VariableLengthObjectBase):
(JSC::decodeCodeBlock):
* runtime/CodeCache.cpp:
(JSC::CodeCache::getUnlinkedGlobalCodeBlock):
(JSC::CodeCache::updateCache):
(JSC::CodeCache::write):
(JSC::writeCodeBlock):
(JSC::serializeBytecode):
* runtime/CodeCache.h:
(JSC::SourceCodeValue::SourceCodeValue):
(JSC::CodeCacheMap::findCacheAndUpdateAge):
(JSC::CodeCacheMap::fetchFromDiskImpl):
* runtime/Completion.cpp:
(JSC::generateProgramBytecode):
(JSC::generateModuleBytecode):
* runtime/Completion.h:
* runtime/LeafExecutable.cpp: Copied from Source/JavaScriptCore/API/JSScriptSourceProvider.mm.
(JSC::LeafExecutable::operator+ const):
* runtime/LeafExecutable.h: Copied from Source/JavaScriptCore/API/JSScriptSourceProvider.mm.
(JSC::LeafExecutable::LeafExecutable):
(JSC::LeafExecutable::base const):

Tools:

Exit when the initial run to generate bytecode fails.

* Scripts/jsc-stress-test-helpers/bytecode-cache-test-helper.sh:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@244143 268f45cc-cd09-0410-ab3c-d52691b4dbfc

27 files changed:
Source/JavaScriptCore/API/JSScript.mm
Source/JavaScriptCore/API/JSScriptInternal.h
Source/JavaScriptCore/API/JSScriptSourceProvider.h
Source/JavaScriptCore/API/JSScriptSourceProvider.mm
Source/JavaScriptCore/CMakeLists.txt
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
Source/JavaScriptCore/Sources.txt
Source/JavaScriptCore/bytecode/UnlinkedFunctionExecutable.cpp
Source/JavaScriptCore/jsc.cpp
Source/JavaScriptCore/parser/SourceProvider.h
Source/JavaScriptCore/runtime/CachePayload.cpp [new file with mode: 0644]
Source/JavaScriptCore/runtime/CachePayload.h [new file with mode: 0644]
Source/JavaScriptCore/runtime/CacheUpdate.cpp [new file with mode: 0644]
Source/JavaScriptCore/runtime/CacheUpdate.h [new file with mode: 0644]
Source/JavaScriptCore/runtime/CachedBytecode.cpp [new file with mode: 0644]
Source/JavaScriptCore/runtime/CachedBytecode.h [new file with mode: 0644]
Source/JavaScriptCore/runtime/CachedTypes.cpp
Source/JavaScriptCore/runtime/CachedTypes.h
Source/JavaScriptCore/runtime/CodeCache.cpp
Source/JavaScriptCore/runtime/CodeCache.h
Source/JavaScriptCore/runtime/Completion.cpp
Source/JavaScriptCore/runtime/Completion.h
Source/JavaScriptCore/runtime/LeafExecutable.cpp [new file with mode: 0644]
Source/JavaScriptCore/runtime/LeafExecutable.h [new file with mode: 0644]
Tools/ChangeLog
Tools/Scripts/jsc-stress-test-helpers/bytecode-cache-test-helper.sh

index 6471277..dd676d8 100644 (file)
@@ -50,7 +50,7 @@
     String m_source;
     RetainPtr<NSURL> m_sourceURL;
     RetainPtr<NSURL> m_cachePath;
-    JSC::CachedBytecode m_cachedBytecode;
+    RefPtr<JSC::CachedBytecode> m_cachedBytecode;
 }
 
 + (instancetype)scriptWithSource:(NSString *)source inVirtualMachine:(JSVirtualMachine *)vm
@@ -169,14 +169,6 @@ static JSScript *createError(NSString *message, NSError** error)
     return result;
 }
 
-- (void)dealloc
-{
-    if (m_cachedBytecode.size() && !m_cachedBytecode.owned())
-        munmap(const_cast<void*>(m_cachedBytecode.data()), m_cachedBytecode.size());
-
-    [super dealloc];
-}
-
 - (void)readCache
 {
     if (!m_cachePath)
@@ -197,12 +189,12 @@ static JSScript *createError(NSString *message, NSError** error)
 
     void* buffer = mmap(nullptr, size, PROT_READ, MAP_PRIVATE, fd, 0);
 
-    JSC::CachedBytecode cachedBytecode { buffer, size };
+    Ref<JSC::CachedBytecode> cachedBytecode = JSC::CachedBytecode::create(buffer, size);
 
     JSC::VM& vm = m_virtualMachine.vm;
     JSC::SourceCode sourceCode = [self sourceCode];
     JSC::SourceCodeKey key = m_type == kJSScriptTypeProgram ? sourceCodeKeyForSerializedProgram(vm, sourceCode) : sourceCodeKeyForSerializedModule(vm, sourceCode);
-    if (isCachedBytecodeStillValid(vm, cachedBytecode, key, m_type == kJSScriptTypeProgram ? JSC::SourceCodeType::ProgramType : JSC::SourceCodeType::ModuleType))
+    if (isCachedBytecodeStillValid(vm, cachedBytecode.copyRef(), key, m_type == kJSScriptTypeProgram ? JSC::SourceCodeType::ProgramType : JSC::SourceCodeType::ModuleType))
         m_cachedBytecode = WTFMove(cachedBytecode);
     else
         ftruncate(fd, 0);
@@ -222,7 +214,7 @@ static JSScript *createError(NSString *message, NSError** error)
 
 - (BOOL)isUsingBytecodeCache
 {
-    return !!m_cachedBytecode.size();
+    return !!m_cachedBytecode->size();
 }
 
 - (NSURL *)sourceURL
@@ -245,6 +237,8 @@ static JSScript *createError(NSString *message, NSError** error)
     if (!self)
         return nil;
 
+    self->m_cachedBytecode = JSC::CachedBytecode::create();
+
     return self;
 }
 
@@ -258,9 +252,9 @@ static JSScript *createError(NSString *message, NSError** error)
     return m_source;
 }
 
-- (const JSC::CachedBytecode*)cachedBytecode
+- (RefPtr<JSC::CachedBytecode>)cachedBytecode
 {
-    return &m_cachedBytecode;
+    return m_cachedBytecode;
 }
 
 - (JSC::SourceCode)sourceCode
@@ -286,7 +280,7 @@ static JSScript *createError(NSString *message, NSError** error)
 
 - (BOOL)writeCache:(String&)error
 {
-    if (m_cachedBytecode.size()) {
+    if (self.isUsingBytecodeCache) {
         error = "Cache for JSScript is already non-empty. Can not override it."_s;
         return NO;
     }
@@ -317,20 +311,20 @@ static JSScript *createError(NSString *message, NSError** error)
     }
 
     if (parserError.isValid()) {
-        m_cachedBytecode = { };
+        m_cachedBytecode = JSC::CachedBytecode::create();
         error = makeString("Unable to generate bytecode for this JSScript because of a parser error: ", parserError.message());
         return NO;
     }
 
-    ssize_t bytesWritten = write(fd, m_cachedBytecode.data(), m_cachedBytecode.size());
+    ssize_t bytesWritten = write(fd, m_cachedBytecode->data(), m_cachedBytecode->size());
     if (bytesWritten == -1) {
         error = makeString("Could not write cache file to disk: ", strerror(errno));
         return NO;
     }
 
-    if (static_cast<size_t>(bytesWritten) != m_cachedBytecode.size()) {
+    if (static_cast<size_t>(bytesWritten) != m_cachedBytecode->size()) {
         ftruncate(fd, 0);
-        error = makeString("Could not write the full cache file to disk. Only wrote ", String::number(bytesWritten), " of the expected ", String::number(m_cachedBytecode.size()), " bytes.");
+        error = makeString("Could not write the full cache file to disk. Only wrote ", String::number(bytesWritten), " of the expected ", String::number(m_cachedBytecode->size()), " bytes.");
         return NO;
     }
 
index ee73573..c8fc285 100644 (file)
@@ -27,6 +27,7 @@
 
 #import "JSScript.h"
 #import "SourceCode.h"
+#import <wtf/RefPtr.h>
 
 #if JSC_OBJC_API_ENABLED
 
@@ -47,7 +48,7 @@ class String;
 - (instancetype)init;
 - (unsigned)hash;
 - (const WTF::String&)source;
-- (nullable const JSC::CachedBytecode*)cachedBytecode;
+- (RefPtr<JSC::CachedBytecode>)cachedBytecode;
 - (JSC::JSSourceCode*)jsSourceCode;
 - (JSC::SourceCode)sourceCode;
 - (BOOL)writeCache:(String&)error;
index 3e8431d..09e4018 100644 (file)
@@ -39,7 +39,7 @@ public:
 
     unsigned hash() const override;
     StringView source() const override;
-    const JSC::CachedBytecode* cachedBytecode() const override;
+    RefPtr<JSC::CachedBytecode> cachedBytecode() const override;
 
 private:
     template<typename... Args>
index 5536a8b..ff86317 100644 (file)
@@ -40,7 +40,7 @@ StringView JSScriptSourceProvider::source() const
     return [m_script.get() source];
 }
 
-const JSC::CachedBytecode* JSScriptSourceProvider::cachedBytecode() const
+RefPtr<JSC::CachedBytecode> JSScriptSourceProvider::cachedBytecode() const
 {
     return [m_script.get() cachedBytecode];
 }
index 6c6ec5a..362aea2 100644 (file)
@@ -761,6 +761,10 @@ set(JavaScriptCore_PRIVATE_FRAMEWORK_HEADERS
     runtime/BooleanPrototype.h
     runtime/Butterfly.h
     runtime/ButterflyInlines.h
+    runtime/CachePayload.h
+    runtime/CacheUpdate.h
+    runtime/CachedBytecode.h
+    runtime/CachedTypes.h
     runtime/CagedBarrierPtr.h
     runtime/CallData.h
     runtime/CatchScope.h
@@ -896,6 +900,7 @@ set(JavaScriptCore_PRIVATE_FRAMEWORK_HEADERS
     runtime/JSWrapperObject.h
     runtime/LazyClassStructure.h
     runtime/LazyProperty.h
+    runtime/LeafExecutable.h
     runtime/Lookup.h
     runtime/MatchResult.h
     runtime/MathCommon.h
index 25ba48f..9ff2b50 100644 (file)
@@ -1,3 +1,125 @@
+2019-04-10  Tadeu Zagallo  <tzagallo@apple.com>
+
+        Add support for incremental bytecode cache updates
+        https://bugs.webkit.org/show_bug.cgi?id=195000
+
+        Reviewed by Filip Pizlo.
+
+        Add support for incremental updates to the bytecode cache. The cache
+        is constructed as follows:
+        - When the cache is empty, the initial payload can be added to the BytecodeCache
+        by calling BytecodeCache::addGlobalUpdate. This represents the encoded
+        top-level UnlinkedCodeBlock.
+        - Afterwards, updates can be added by calling BytecodeCache::addFunctionUpdate.
+        The update is applied by appending the encoded UnlinkedFunctionCodeBlock
+        to the existing cache and updating the CachedFunctionExecutableMetadata
+        and the offset of the new CachedFunctionCodeBlock in the owner CachedFunctionExecutable.
+
+        * API/JSScript.mm:
+        (-[JSScript readCache]):
+        (-[JSScript isUsingBytecodeCache]):
+        (-[JSScript init]):
+        (-[JSScript cachedBytecode]):
+        (-[JSScript writeCache:]):
+        * API/JSScriptInternal.h:
+        * API/JSScriptSourceProvider.h:
+        * API/JSScriptSourceProvider.mm:
+        (JSScriptSourceProvider::cachedBytecode const):
+        * CMakeLists.txt:
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * Sources.txt:
+        * bytecode/UnlinkedFunctionExecutable.cpp:
+        (JSC::generateUnlinkedFunctionCodeBlock):
+        * jsc.cpp:
+        (ShellSourceProvider::~ShellSourceProvider):
+        (ShellSourceProvider::cachePath const):
+        (ShellSourceProvider::loadBytecode const):
+        (ShellSourceProvider::ShellSourceProvider):
+        (ShellSourceProvider::cacheEnabled):
+        * parser/SourceProvider.h:
+        (JSC::SourceProvider::cachedBytecode const):
+        (JSC::SourceProvider::updateCache const):
+        (JSC::SourceProvider::commitCachedBytecode const):
+        * runtime/CachePayload.cpp: Copied from Source/JavaScriptCore/API/JSScriptInternal.h.
+        (JSC::CachePayload::makeMappedPayload):
+        (JSC::CachePayload::makeMallocPayload):
+        (JSC::CachePayload::makeEmptyPayload):
+        (JSC::CachePayload::CachePayload):
+        (JSC::CachePayload::~CachePayload):
+        (JSC::CachePayload::operator=):
+        (JSC::CachePayload::freeData):
+        * runtime/CachePayload.h: Copied from Source/JavaScriptCore/API/JSScriptInternal.h.
+        (JSC::CachePayload::data const):
+        (JSC::CachePayload::size const):
+        (JSC::CachePayload::CachePayload):
+        * runtime/CacheUpdate.cpp: Copied from Source/JavaScriptCore/API/JSScriptInternal.h.
+        (JSC::CacheUpdate::CacheUpdate):
+        (JSC::CacheUpdate::operator=):
+        (JSC::CacheUpdate::isGlobal const):
+        (JSC::CacheUpdate::asGlobal const):
+        (JSC::CacheUpdate::asFunction const):
+        * runtime/CacheUpdate.h: Copied from Source/JavaScriptCore/API/JSScriptInternal.h.
+        * runtime/CachedBytecode.cpp: Added.
+        (JSC::CachedBytecode::addGlobalUpdate):
+        (JSC::CachedBytecode::addFunctionUpdate):
+        (JSC::CachedBytecode::copyLeafExecutables):
+        (JSC::CachedBytecode::commitUpdates const):
+        * runtime/CachedBytecode.h: Added.
+        (JSC::CachedBytecode::create):
+        (JSC::CachedBytecode::leafExecutables):
+        (JSC::CachedBytecode::data const):
+        (JSC::CachedBytecode::size const):
+        (JSC::CachedBytecode::hasUpdates const):
+        (JSC::CachedBytecode::sizeForUpdate const):
+        (JSC::CachedBytecode::CachedBytecode):
+        * runtime/CachedTypes.cpp:
+        (JSC::Encoder::addLeafExecutable):
+        (JSC::Encoder::release):
+        (JSC::Decoder::Decoder):
+        (JSC::Decoder::create):
+        (JSC::Decoder::size const):
+        (JSC::Decoder::offsetOf):
+        (JSC::Decoder::ptrForOffsetFromBase):
+        (JSC::Decoder::addLeafExecutable):
+        (JSC::VariableLengthObject::VariableLengthObject):
+        (JSC::VariableLengthObject::buffer const):
+        (JSC::CachedPtrOffsets::offsetOffset):
+        (JSC::CachedWriteBarrierOffsets::ptrOffset):
+        (JSC::CachedFunctionExecutable::features const):
+        (JSC::CachedFunctionExecutable::hasCapturedVariables const):
+        (JSC::CachedFunctionExecutableOffsets::codeBlockForCallOffset):
+        (JSC::CachedFunctionExecutableOffsets::codeBlockForConstructOffset):
+        (JSC::CachedFunctionExecutableOffsets::metadataOffset):
+        (JSC::CachedFunctionExecutable::encode):
+        (JSC::CachedFunctionExecutable::decode const):
+        (JSC::UnlinkedFunctionExecutable::UnlinkedFunctionExecutable):
+        (JSC::encodeCodeBlock):
+        (JSC::encodeFunctionCodeBlock):
+        (JSC::decodeCodeBlockImpl):
+        (JSC::isCachedBytecodeStillValid):
+        * runtime/CachedTypes.h:
+        (JSC::VariableLengthObjectBase::VariableLengthObjectBase):
+        (JSC::decodeCodeBlock):
+        * runtime/CodeCache.cpp:
+        (JSC::CodeCache::getUnlinkedGlobalCodeBlock):
+        (JSC::CodeCache::updateCache):
+        (JSC::CodeCache::write):
+        (JSC::writeCodeBlock):
+        (JSC::serializeBytecode):
+        * runtime/CodeCache.h:
+        (JSC::SourceCodeValue::SourceCodeValue):
+        (JSC::CodeCacheMap::findCacheAndUpdateAge):
+        (JSC::CodeCacheMap::fetchFromDiskImpl):
+        * runtime/Completion.cpp:
+        (JSC::generateProgramBytecode):
+        (JSC::generateModuleBytecode):
+        * runtime/Completion.h:
+        * runtime/LeafExecutable.cpp: Copied from Source/JavaScriptCore/API/JSScriptSourceProvider.mm.
+        (JSC::LeafExecutable::operator+ const):
+        * runtime/LeafExecutable.h: Copied from Source/JavaScriptCore/API/JSScriptSourceProvider.mm.
+        (JSC::LeafExecutable::LeafExecutable):
+        (JSC::LeafExecutable::base const):
+
 2019-04-10  Michael Catanzaro  <mcatanzaro@igalia.com>
 
         Unreviewed, rolling out r243989.
index 9ab8830..cb38278 100644 (file)
                0FFFC95C14EF90AF00C72532 /* DFGPhase.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FFFC95014EF909500C72532 /* DFGPhase.h */; };
                0FFFC95E14EF90B700C72532 /* DFGPredictionPropagationPhase.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FFFC95214EF909500C72532 /* DFGPredictionPropagationPhase.h */; };
                0FFFC96014EF90BD00C72532 /* DFGVirtualRegisterAllocationPhase.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FFFC95414EF909500C72532 /* DFGVirtualRegisterAllocationPhase.h */; };
+               1409ECBF225E177400BEDD54 /* LeafExecutable.h in Headers */ = {isa = PBXBuildFile; fileRef = 148B1417225DD1D700D6E998 /* LeafExecutable.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               1409ECC0225E178100BEDD54 /* CacheUpdate.h in Headers */ = {isa = PBXBuildFile; fileRef = 148B1418225DD1D700D6E998 /* CacheUpdate.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               1409ECC1225E178C00BEDD54 /* CachePayload.h in Headers */ = {isa = PBXBuildFile; fileRef = 148B1416225DD1D700D6E998 /* CachePayload.h */; settings = {ATTRIBUTES = (Private, ); }; };
                140D17D70E8AD4A9000CD17D /* JSBasePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 140D17D60E8AD4A9000CD17D /* JSBasePrivate.h */; settings = {ATTRIBUTES = (Private, ); }; };
                141211310A48794D00480255 /* JavaScriptCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 932F5BD90822A1C700736975 /* JavaScriptCore.framework */; };
                141211340A48795800480255 /* minidom.c in Sources */ = {isa = PBXBuildFile; fileRef = 141211020A48780900480255 /* minidom.c */; };
                1440F6100A4F85670005F061 /* testapi.c in Sources */ = {isa = PBXBuildFile; fileRef = 14BD5A2D0A3E91F600BAF59C /* testapi.c */; };
                1442566215EDE98D0066A49B /* JSWithScope.h in Headers */ = {isa = PBXBuildFile; fileRef = 1442566015EDE98D0066A49B /* JSWithScope.h */; settings = {ATTRIBUTES = (Private, ); }; };
                144836E7132DA7BE005BE785 /* ConservativeRoots.h in Headers */ = {isa = PBXBuildFile; fileRef = 149DAAF212EB559D0083B12B /* ConservativeRoots.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               144CA3502224180100817789 /* CachedBytecode.h in Headers */ = {isa = PBXBuildFile; fileRef = 144CA34F221F037900817789 /* CachedBytecode.h */; settings = {ATTRIBUTES = (Private, ); }; };
                145722861437E140005FDE26 /* StrongInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = 145722851437E140005FDE26 /* StrongInlines.h */; settings = {ATTRIBUTES = (Private, ); }; };
                146C384B2177ACDF0079F6D9 /* UnlinkedMetadataTable.h in Headers */ = {isa = PBXBuildFile; fileRef = 142D52BE21762958002DB086 /* UnlinkedMetadataTable.h */; settings = {ATTRIBUTES = (Private, ); }; };
                1471483020D323D30090E630 /* JSWrapperMapTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1471482F20D323650090E630 /* JSWrapperMapTests.mm */; };
                14E84F9F14EE1ACC00D6D5D4 /* WeakBlock.h in Headers */ = {isa = PBXBuildFile; fileRef = 14E84F9A14EE1ACC00D6D5D4 /* WeakBlock.h */; settings = {ATTRIBUTES = (Private, ); }; };
                14E84FA114EE1ACC00D6D5D4 /* WeakSet.h in Headers */ = {isa = PBXBuildFile; fileRef = 14E84F9C14EE1ACC00D6D5D4 /* WeakSet.h */; settings = {ATTRIBUTES = (Private, ); }; };
                14E84FA214EE1ACC00D6D5D4 /* WeakImpl.h in Headers */ = {isa = PBXBuildFile; fileRef = 14E84F9D14EE1ACC00D6D5D4 /* WeakImpl.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               14F09C2A2231923100CF88EB /* CachedTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = 143BE26521C857770020CD17 /* CachedTypes.h */; settings = {ATTRIBUTES = (Private, ); }; };
                14F7256614EE265E00B1652B /* WeakHandleOwner.h in Headers */ = {isa = PBXBuildFile; fileRef = 14F7256414EE265E00B1652B /* WeakHandleOwner.h */; settings = {ATTRIBUTES = (Private, ); }; };
                14F79F70216EAFD200046D39 /* Opcode.h in Headers */ = {isa = PBXBuildFile; fileRef = 969A07950ED1D3AE00F1F681 /* Opcode.h */; settings = {ATTRIBUTES = (Private, ); }; };
                1A28D4A8177B71C80007FA3C /* JSStringRefPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1A28D4A7177B71C80007FA3C /* JSStringRefPrivate.h */; settings = {ATTRIBUTES = (Private, ); }; };
                1440FCE20A51E46B0005F061 /* JSClassRef.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSClassRef.cpp; sourceTree = "<group>"; };
                1442565F15EDE98D0066A49B /* JSWithScope.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSWithScope.cpp; sourceTree = "<group>"; };
                1442566015EDE98D0066A49B /* JSWithScope.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSWithScope.h; sourceTree = "<group>"; };
+               144CA34F221F037900817789 /* CachedBytecode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CachedBytecode.h; sourceTree = "<group>"; };
                145722851437E140005FDE26 /* StrongInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StrongInlines.h; sourceTree = "<group>"; };
                145C507F0D9DF63B0088F6B9 /* CallData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CallData.h; sourceTree = "<group>"; };
                146AAB2A0B66A84900E55F16 /* JSStringRefCF.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = JSStringRefCF.h; sourceTree = "<group>"; };
                14874AE215EBDE4A002E3587 /* JSScope.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSScope.h; sourceTree = "<group>"; };
                148A7BED1B82975A002D9157 /* InlineCallFrame.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InlineCallFrame.cpp; sourceTree = "<group>"; };
                148A7BEE1B82975A002D9157 /* InlineCallFrame.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InlineCallFrame.h; sourceTree = "<group>"; };
+               148B1416225DD1D700D6E998 /* CachePayload.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CachePayload.h; sourceTree = "<group>"; };
+               148B1417225DD1D700D6E998 /* LeafExecutable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LeafExecutable.h; sourceTree = "<group>"; };
+               148B1418225DD1D700D6E998 /* CacheUpdate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CacheUpdate.h; sourceTree = "<group>"; };
+               148B1419225DD1E900D6E998 /* CachedBytecode.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CachedBytecode.cpp; sourceTree = "<group>"; };
+               148B141A225DD1E900D6E998 /* CacheUpdate.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CacheUpdate.cpp; sourceTree = "<group>"; };
+               148B141B225DD1EA00D6E998 /* CachePayload.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CachePayload.cpp; sourceTree = "<group>"; };
+               148B141C225DD1EA00D6E998 /* LeafExecutable.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = LeafExecutable.cpp; sourceTree = "<group>"; };
                148CD1D7108CF902008163C6 /* JSContextRefPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSContextRefPrivate.h; sourceTree = "<group>"; };
                149559ED0DDCDDF700648087 /* DebuggerCallFrame.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DebuggerCallFrame.cpp; sourceTree = "<group>"; };
                1498CAD3214656C400710879 /* libWTF.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libWTF.a; sourceTree = BUILT_PRODUCTS_DIR; };
                                9E729409190F0306001A91B5 /* BundlePath.mm */,
                                0FB7F38B15ED8E3800F167B2 /* Butterfly.h */,
                                0FB7F38C15ED8E3800F167B2 /* ButterflyInlines.h */,
+                               148B1419225DD1E900D6E998 /* CachedBytecode.cpp */,
+                               144CA34F221F037900817789 /* CachedBytecode.h */,
                                14DAFA4521E3B871004B68F7 /* CachedTypes.cpp */,
                                143BE26521C857770020CD17 /* CachedTypes.h */,
+                               148B141B225DD1EA00D6E998 /* CachePayload.cpp */,
+                               148B1416225DD1D700D6E998 /* CachePayload.h */,
+                               148B141A225DD1E900D6E998 /* CacheUpdate.cpp */,
+                               148B1418225DD1D700D6E998 /* CacheUpdate.h */,
                                0FEC3C5F1F379F5300F59B6C /* CagedBarrierPtr.h */,
                                BCA62DFE0E2826230004F30D /* CallData.cpp */,
                                145C507F0D9DF63B0088F6B9 /* CallData.h */,
                                DCF3D5661CD29468003D5C65 /* LazyClassStructureInlines.h */,
                                DCF3D5671CD29468003D5C65 /* LazyProperty.h */,
                                DCF3D5681CD29468003D5C65 /* LazyPropertyInlines.h */,
+                               148B141C225DD1EA00D6E998 /* LeafExecutable.cpp */,
+                               148B1417225DD1D700D6E998 /* LeafExecutable.h */,
                                A7E2EA6A0FB460CF00601F06 /* LiteralParser.cpp */,
                                A7E2EA690FB460CF00601F06 /* LiteralParser.h */,
                                F692A8680255597D01FF60F7 /* Lookup.cpp */,
                                6514F21918B3E1670098FF8B /* Bytecodes.h in Headers */,
                                0F885E111849A3BE00F1E3FA /* BytecodeUseDef.h in Headers */,
                                0F8023EA1613832B00A0BA45 /* ByValInfo.h in Headers */,
+                               144CA3502224180100817789 /* CachedBytecode.h in Headers */,
                                65B8392E1BACAD360044E824 /* CachedRecovery.h in Headers */,
+                               14F09C2A2231923100CF88EB /* CachedTypes.h in Headers */,
+                               1409ECC1225E178C00BEDD54 /* CachePayload.h in Headers */,
+                               1409ECC0225E178100BEDD54 /* CacheUpdate.h in Headers */,
                                0FEC3C601F379F5300F59B6C /* CagedBarrierPtr.h in Headers */,
                                BC18C3ED0E16F5CD00B34460 /* CallData.h in Headers */,
                                0F64B27A1A7957B2006E4E66 /* CallEdge.h in Headers */,
                                DCF3D56C1CD29475003D5C65 /* LazyProperty.h in Headers */,
                                DCF3D56D1CD29476003D5C65 /* LazyPropertyInlines.h in Headers */,
                                99DA00B01BD5994E00F4575C /* lazywriter.py in Headers */,
+                               1409ECBF225E177400BEDD54 /* LeafExecutable.h in Headers */,
                                BC18C4310E16F5CD00B34460 /* Lexer.h in Headers */,
                                BC18C52E0E16FCE100B34460 /* Lexer.lut.h in Headers */,
                                86D3B3C310159D7F002865E7 /* LinkBuffer.h in Headers */,
index 3302dea..3e5859c 100644 (file)
@@ -717,6 +717,9 @@ runtime/BooleanConstructor.cpp
 runtime/BooleanObject.cpp
 runtime/BooleanPrototype.cpp
 runtime/CallData.cpp
+runtime/CachePayload.cpp
+runtime/CacheUpdate.cpp
+runtime/CachedBytecode.cpp
 runtime/CachedTypes.cpp
 runtime/CatchScope.cpp
 runtime/ClassInfo.cpp
@@ -872,6 +875,7 @@ runtime/JSWeakSet.cpp
 runtime/JSWithScope.cpp
 runtime/JSWrapperObject.cpp
 runtime/LazyClassStructure.cpp
+runtime/LeafExecutable.cpp
 runtime/LiteralParser.cpp
 runtime/Lookup.cpp
 runtime/MapConstructor.cpp
index 7997e66..44d5e53 100644 (file)
@@ -77,6 +77,7 @@ static UnlinkedFunctionCodeBlock* generateUnlinkedFunctionCodeBlock(
 
     if (error.isValid())
         return nullptr;
+    vm.codeCache()->updateCache(executable, source, kind, result);
     return result;
 }
 
index 6336642..8dfa9c7 100644 (file)
@@ -967,48 +967,87 @@ public:
 
     ~ShellSourceProvider()
     {
-#if OS(DARWIN)
-        if (m_cachedBytecode.size())
-            munmap(const_cast<void*>(m_cachedBytecode.data()), m_cachedBytecode.size());
-#endif
+        commitCachedBytecode();
+    }
+
+    RefPtr<CachedBytecode> cachedBytecode() const override
+    {
+        if (!m_cachedBytecode->size())
+            loadBytecode();
+        return m_cachedBytecode.copyRef();
     }
 
-    const CachedBytecode* cachedBytecode() const override
+    void updateCache(const UnlinkedFunctionExecutable* executable, const SourceCode&, CodeSpecializationKind kind, const UnlinkedFunctionCodeBlock* codeBlock) const override
     {
-        return &m_cachedBytecode;
+        if (!cacheEnabled())
+            return;
+        Ref<CachedBytecode> cachedBytecode = encodeFunctionCodeBlock(*executable->vm(), codeBlock);
+        m_cachedBytecode->addFunctionUpdate(executable, kind, WTFMove(cachedBytecode));
     }
 
     void cacheBytecode(const BytecodeCacheGenerator& generator) const override
     {
+        if (!cacheEnabled())
+            return;
+        m_cachedBytecode->addGlobalUpdate(generator());
+    }
+
+    void commitCachedBytecode() const override
+    {
 #if OS(DARWIN)
-        String filename = cachePath();
-        if (filename.isNull())
+        if (!cacheEnabled() || !m_cachedBytecode->hasUpdates())
             return;
+
+        auto clearBytecode = makeScopeExit([&] {
+            m_cachedBytecode = CachedBytecode::create();
+        });
+
+        String filename = cachePath();
         int fd = open(filename.utf8().data(), O_CREAT | O_WRONLY | O_TRUNC | O_EXLOCK | O_NONBLOCK, 0666);
         if (fd == -1)
             return;
-        CachedBytecode cachedBytecode = generator();
-        write(fd, cachedBytecode.data(), cachedBytecode.size());
-        close(fd);
-#else
-        UNUSED_PARAM(generator);
+
+        auto closeFD = makeScopeExit([&] {
+            close(fd);
+        });
+
+        struct stat sb;
+        int res = fstat(fd, &sb);
+        size_t size = static_cast<size_t>(sb.st_size);
+        if (res || size != m_cachedBytecode->size()) {
+            // The bytecode cache has already been updated
+            return;
+        }
+
+        if (ftruncate(fd, m_cachedBytecode->sizeForUpdate()))
+            return;
+
+        m_cachedBytecode->commitUpdates([&] (off_t offset, const void* data, size_t size) {
+            int result = lseek(fd, offset, SEEK_SET);
+            ASSERT_UNUSED(result, result != -1);
+            size_t bytesWritten = static_cast<size_t>(write(fd, data, size));
+            ASSERT_UNUSED(bytesWritten, bytesWritten == size);
+        });
 #endif
     }
 
 private:
     String cachePath() const
     {
-        const char* cachePath = Options::diskCachePath();
-        if (!cachePath)
+        if (!cacheEnabled())
             return static_cast<const char*>(nullptr);
+        const char* cachePath = Options::diskCachePath();
         String filename = sourceOrigin().string();
         filename.replace('/', '_');
         return makeString(cachePath, '/', source().toString().hash(), '-', filename, ".bytecode-cache");
     }
 
-    void loadBytecode()
+    void loadBytecode() const
     {
 #if OS(DARWIN)
+        if (!cacheEnabled())
+            return;
+
         String filename = cachePath();
         if (filename.isNull())
             return;
@@ -1030,17 +1069,24 @@ private:
         void* buffer = mmap(nullptr, size, PROT_READ, MAP_PRIVATE, fd, 0);
         if (buffer == MAP_FAILED)
             return;
-        m_cachedBytecode = CachedBytecode { buffer, size };
+        m_cachedBytecode = CachedBytecode::create(buffer, size);
 #endif
     }
 
     ShellSourceProvider(const String& source, const SourceOrigin& sourceOrigin, URL&& url, const TextPosition& startPosition, SourceProviderSourceType sourceType)
         : StringSourceProvider(source, sourceOrigin, WTFMove(url), startPosition, sourceType)
+        , m_cachedBytecode(CachedBytecode::create())
     {
         loadBytecode();
     }
 
-    CachedBytecode m_cachedBytecode;
+    static bool cacheEnabled()
+    {
+        static bool enabled = !!Options::diskCachePath();
+        return enabled;
+    }
+
+    mutable Ref<CachedBytecode> m_cachedBytecode;
 };
 
 static inline SourceCode jscSource(const String& source, const SourceOrigin& sourceOrigin, URL&& url = URL(), const TextPosition& startPosition = TextPosition(), SourceProviderSourceType sourceType = SourceProviderSourceType::Program)
index 2493d75..d8e0415 100644 (file)
@@ -28,6 +28,8 @@
 
 #pragma once
 
+#include "CachedBytecode.h"
+#include "CodeSpecializationKind.h"
 #include "SourceOrigin.h"
 #include <wtf/RefCounted.h>
 #include <wtf/URL.h>
 
 namespace JSC {
 
+class SourceCode;
+class UnlinkedFunctionExecutable;
+class UnlinkedFunctionCodeBlock;
+
     enum class SourceProviderSourceType : uint8_t {
         Program,
         Module,
         WebAssembly,
     };
 
-    class CachedBytecode {
-        WTF_MAKE_NONCOPYABLE(CachedBytecode);
-
-    public:
-        CachedBytecode()
-            : CachedBytecode(nullptr, 0)
-        {
-        }
-
-        CachedBytecode(const void* data, size_t size)
-            : m_owned(false)
-            , m_size(size)
-            , m_data(data)
-        {
-        }
-
-        CachedBytecode(MallocPtr<uint8_t>&& data, size_t size)
-            : m_owned(true)
-            , m_size(size)
-            , m_data(data.leakPtr())
-        {
-        }
-
-        CachedBytecode(CachedBytecode&& other)
-        {
-            m_owned = other.m_owned;
-            m_size = other.m_size;
-            m_data = other.m_data;
-            other.m_owned = false;
-        }
-
-        CachedBytecode& operator=(CachedBytecode&& other)
-        {
-            freeDataIfOwned();
-            m_owned = other.m_owned;
-            m_size = other.m_size;
-            m_data = other.m_data;
-            other.m_owned = false;
-            return *this;
-        }
-
-        const void* data() const { return m_data; }
-        size_t size() const { return m_size; }
-        bool owned() const { return m_owned; }
-
-        ~CachedBytecode()
-        {
-            freeDataIfOwned();
-        }
-
-    private:
-        void freeDataIfOwned()
-        {
-            if (m_data && m_owned)
-                fastFree(const_cast<void*>(m_data));
-        }
-
-        bool m_owned;
-        size_t m_size;
-        const void* m_data;
-    };
-
-    using BytecodeCacheGenerator = Function<CachedBytecode()>;
+    using BytecodeCacheGenerator = Function<Ref<CachedBytecode>()>;
 
     class SourceProvider : public RefCounted<SourceProvider> {
     public:
@@ -116,8 +60,10 @@ namespace JSC {
 
         virtual unsigned hash() const = 0;
         virtual StringView source() const = 0;
-        virtual const CachedBytecode* cachedBytecode() const { return nullptr; }
+        virtual RefPtr<CachedBytecode> cachedBytecode() const { return nullptr; }
         virtual void cacheBytecode(const BytecodeCacheGenerator&) const { }
+        virtual void updateCache(const UnlinkedFunctionExecutable*, const SourceCode&, CodeSpecializationKind, const UnlinkedFunctionCodeBlock*) const { }
+        virtual void commitCachedBytecode() const { }
 
         StringView getRange(int start, int end) const
         {
diff --git a/Source/JavaScriptCore/runtime/CachePayload.cpp b/Source/JavaScriptCore/runtime/CachePayload.cpp
new file mode 100644 (file)
index 0000000..8c3e85b
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2019 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "CachePayload.h"
+
+#if !OS(WINDOWS)
+#include <sys/mman.h>
+#endif
+
+namespace JSC {
+
+#if !OS(WINDOWS)
+CachePayload CachePayload::makeMappedPayload(void* data, size_t size)
+{
+    return CachePayload(true, data, size);
+}
+#endif
+
+CachePayload CachePayload::makeMallocPayload(MallocPtr<uint8_t>&& data, size_t size)
+{
+    return CachePayload(false, data.leakPtr(), size);
+}
+
+CachePayload CachePayload::makeEmptyPayload()
+{
+    return CachePayload(true, nullptr, 0);
+}
+
+CachePayload::CachePayload(CachePayload&& other)
+{
+    m_mapped = other.m_mapped;
+    m_size = other.m_size;
+    m_data = other.m_data;
+    other.m_mapped = false;
+    other.m_data = nullptr;
+    other.m_size = 0;
+}
+
+CachePayload::~CachePayload()
+{
+    freeData();
+}
+
+CachePayload& CachePayload::operator=(CachePayload&& other)
+{
+    ASSERT(&other != this);
+    freeData();
+    return *new (this) CachePayload(WTFMove(other));
+}
+
+void CachePayload::freeData()
+{
+    if (!m_data)
+        return;
+    if (m_mapped) {
+#if !OS(WINDOWS)
+        munmap(m_data, m_size);
+#else
+        RELEASE_ASSERT_NOT_REACHED();
+#endif
+    } else
+        fastFree(m_data);
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/CachePayload.h b/Source/JavaScriptCore/runtime/CachePayload.h
new file mode 100644 (file)
index 0000000..e048f31
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2019 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <wtf/MallocPtr.h>
+
+namespace JSC {
+
+class CachePayload {
+public:
+#if !OS(WINDOWS)
+    JS_EXPORT_PRIVATE static CachePayload makeMappedPayload(void*, size_t);
+#endif
+    JS_EXPORT_PRIVATE static CachePayload makeMallocPayload(MallocPtr<uint8_t>&&, size_t);
+    JS_EXPORT_PRIVATE static CachePayload makeEmptyPayload();
+
+    JS_EXPORT_PRIVATE CachePayload(CachePayload&&);
+    JS_EXPORT_PRIVATE ~CachePayload();
+    JS_EXPORT_PRIVATE CachePayload& operator=(CachePayload&& other);
+
+    const uint8_t* data() const { return m_data; }
+    size_t size() const { return m_size; }
+
+private:
+    CachePayload(bool mapped, void* data, size_t size)
+        : m_mapped(mapped)
+        , m_size(size)
+        , m_data(static_cast<uint8_t*>(data))
+    {
+    }
+
+    void freeData();
+
+    bool m_mapped;
+    size_t m_size;
+    uint8_t* m_data;
+};
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/CacheUpdate.cpp b/Source/JavaScriptCore/runtime/CacheUpdate.cpp
new file mode 100644 (file)
index 0000000..70d36b3
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2019 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "CacheUpdate.h"
+
+namespace JSC {
+
+CacheUpdate::CacheUpdate(GlobalUpdate&& update)
+    : m_update(WTFMove(update))
+{
+}
+
+CacheUpdate::CacheUpdate(FunctionUpdate&& update)
+    : m_update(WTFMove(update))
+{
+}
+
+CacheUpdate::CacheUpdate(CacheUpdate&& other)
+{
+    if (WTF::holds_alternative<GlobalUpdate>(other.m_update))
+        new (this) CacheUpdate(WTFMove(WTF::get<GlobalUpdate>(other.m_update)));
+    else
+        new (this) CacheUpdate(WTFMove(WTF::get<FunctionUpdate>(other.m_update)));
+}
+
+CacheUpdate& CacheUpdate::operator=(CacheUpdate&& other)
+{
+    this->~CacheUpdate();
+    return *new (this) CacheUpdate(WTFMove(other));
+}
+
+bool CacheUpdate::isGlobal() const
+{
+    return WTF::holds_alternative<GlobalUpdate>(m_update);
+}
+
+const CacheUpdate::GlobalUpdate& CacheUpdate::asGlobal() const
+{
+    ASSERT(isGlobal());
+    return WTF::get<GlobalUpdate>(m_update);
+}
+
+const CacheUpdate::FunctionUpdate& CacheUpdate::asFunction() const
+{
+    ASSERT(!isGlobal());
+    return WTF::get<FunctionUpdate>(m_update);
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/CacheUpdate.h b/Source/JavaScriptCore/runtime/CacheUpdate.h
new file mode 100644 (file)
index 0000000..2c88283
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2019 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "CachePayload.h"
+#include "CachedTypes.h"
+#include "CodeSpecializationKind.h"
+#include <wtf/Variant.h>
+
+namespace JSC {
+
+class CacheUpdate {
+public:
+    struct GlobalUpdate {
+        CachePayload m_payload;
+    };
+
+    struct FunctionUpdate {
+        ptrdiff_t m_base;
+        CodeSpecializationKind m_kind;
+        CachedFunctionExecutableMetadata m_metadata;
+        CachePayload m_payload;
+    };
+
+
+    CacheUpdate(GlobalUpdate&&);
+    CacheUpdate(FunctionUpdate&&);
+
+    CacheUpdate(CacheUpdate&&);
+    CacheUpdate& operator=(CacheUpdate&&);
+
+    bool isGlobal() const;
+    const GlobalUpdate& asGlobal() const;
+    const FunctionUpdate& asFunction() const;
+
+private:
+    Variant<GlobalUpdate, FunctionUpdate> m_update;
+};
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/CachedBytecode.cpp b/Source/JavaScriptCore/runtime/CachedBytecode.cpp
new file mode 100644 (file)
index 0000000..ef8c6f7
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2019 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "CachedBytecode.h"
+
+#include "CachedTypes.h"
+#include "UnlinkedFunctionExecutable.h"
+#include <wtf/Function.h>
+
+namespace JSC {
+
+void CachedBytecode::addGlobalUpdate(Ref<CachedBytecode> bytecode)
+{
+    ASSERT(m_updates.isEmpty());
+    m_leafExecutables.clear();
+    copyLeafExecutables(bytecode.get());
+    m_updates.append(CacheUpdate::GlobalUpdate { WTFMove(bytecode->m_payload) });
+}
+
+void CachedBytecode::addFunctionUpdate(const UnlinkedFunctionExecutable* executable, CodeSpecializationKind kind, Ref<CachedBytecode> bytecode)
+{
+    auto it = m_leafExecutables.find(executable);
+    ASSERT(it != m_leafExecutables.end());
+    ptrdiff_t offset = it->value.base();
+    ASSERT(offset);
+    copyLeafExecutables(bytecode.get());
+    m_updates.append(CacheUpdate::FunctionUpdate { offset, kind, { executable->features(), executable->hasCapturedVariables() }, WTFMove(bytecode->m_payload) });
+}
+
+void CachedBytecode::copyLeafExecutables(const CachedBytecode& bytecode)
+{
+    for (const auto& it : bytecode.m_leafExecutables) {
+        auto addResult = m_leafExecutables.add(it.key, it.value + m_size);
+        ASSERT_UNUSED(addResult, addResult.isNewEntry);
+    }
+    m_size += bytecode.size();
+}
+
+void CachedBytecode::commitUpdates(const ForEachUpdateCallback& callback) const
+{
+    off_t offset = m_payload.size();
+    for (const auto& update : m_updates) {
+        const CachePayload* payload = nullptr;
+        if (update.isGlobal())
+            payload = &update.asGlobal().m_payload;
+        else {
+            const CacheUpdate::FunctionUpdate& functionUpdate = update.asFunction();
+            payload = &functionUpdate.m_payload;
+            {
+                ptrdiff_t kindOffset = functionUpdate.m_kind == CodeForCall ? CachedFunctionExecutableOffsets::codeBlockForCallOffset() : CachedFunctionExecutableOffsets::codeBlockForConstructOffset();
+                ptrdiff_t codeBlockOffset = functionUpdate.m_base + kindOffset + CachedWriteBarrierOffsets::ptrOffset() + CachedPtrOffsets::offsetOffset();
+                ptrdiff_t offsetPayload = static_cast<ptrdiff_t>(offset) - codeBlockOffset;
+                static_assert(std::is_same<decltype(VariableLengthObjectBase::m_offset), ptrdiff_t>::value, "");
+                callback(codeBlockOffset, &offsetPayload, sizeof(ptrdiff_t));
+            }
+
+            {
+                ptrdiff_t metadataOffset = functionUpdate.m_base + CachedFunctionExecutableOffsets::metadataOffset();
+                callback(metadataOffset, &functionUpdate.m_metadata, sizeof(functionUpdate.m_metadata));
+            }
+        }
+
+        ASSERT(payload);
+        callback(offset, payload->data(), payload->size());
+        offset += payload->size();
+    }
+    ASSERT(static_cast<size_t>(offset) == m_size);
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/CachedBytecode.h b/Source/JavaScriptCore/runtime/CachedBytecode.h
new file mode 100644 (file)
index 0000000..5793668
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2019 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "CacheUpdate.h"
+#include "LeafExecutable.h"
+#include "ParserModes.h"
+#include <wtf/MallocPtr.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/RefCounted.h>
+#include <wtf/Vector.h>
+
+namespace JSC {
+
+class UnlinkedFunctionExecutable;
+
+class CachedBytecode : public RefCounted<CachedBytecode> {
+    WTF_MAKE_NONCOPYABLE(CachedBytecode);
+
+public:
+    static Ref<CachedBytecode> create()
+    {
+        return adoptRef(*new CachedBytecode(CachePayload::makeEmptyPayload()));
+    }
+
+#if !OS(WINDOWS)
+    static Ref<CachedBytecode> create(void* data, size_t size)
+    {
+        return adoptRef(*new CachedBytecode(CachePayload::makeMappedPayload(data, size)));
+    }
+#endif
+
+    static Ref<CachedBytecode> create(MallocPtr<uint8_t>&& data, size_t size, LeafExecutableMap&& leafExecutables)
+    {
+        return adoptRef(*new CachedBytecode(CachePayload::makeMallocPayload(WTFMove(data), size), WTFMove(leafExecutables)));
+    }
+
+    LeafExecutableMap& leafExecutables() { return m_leafExecutables; }
+
+    JS_EXPORT_PRIVATE void addGlobalUpdate(Ref<CachedBytecode>);
+    JS_EXPORT_PRIVATE void addFunctionUpdate(const UnlinkedFunctionExecutable*, CodeSpecializationKind, Ref<CachedBytecode>);
+
+    using ForEachUpdateCallback = Function<void(off_t, const void*, size_t)>;
+    JS_EXPORT_PRIVATE void commitUpdates(const ForEachUpdateCallback&) const;
+
+    const uint8_t* data() const { return m_payload.data(); }
+    size_t size() const { return m_payload.size(); }
+    bool hasUpdates() const { return !m_updates.isEmpty(); }
+    size_t sizeForUpdate() const { return m_size; }
+
+private:
+    CachedBytecode(CachePayload&& payload, LeafExecutableMap&& leafExecutables = { })
+        : m_size(payload.size())
+        , m_payload(WTFMove(payload))
+        , m_leafExecutables(WTFMove(leafExecutables))
+    {
+    }
+
+    void copyLeafExecutables(const CachedBytecode&);
+
+    size_t m_size { 0 };
+    CachePayload m_payload;
+    LeafExecutableMap m_leafExecutables;
+    Vector<CacheUpdate> m_updates;
+};
+
+
+} // namespace JSC
index 9e56bb2..a7ba2ac 100644 (file)
@@ -139,7 +139,12 @@ public:
         return { it->value };
     }
 
-    std::pair<MallocPtr<uint8_t>, size_t> release()
+    void addLeafExecutable(const UnlinkedFunctionExecutable* executable, ptrdiff_t offset)
+    {
+        m_leafExecutables.add(executable, offset);
+    }
+
+    Ref<CachedBytecode> release()
     {
         size_t size = m_baseOffset + m_currentPage->size();
         MallocPtr<uint8_t> buffer = MallocPtr<uint8_t>::malloc(size);
@@ -149,7 +154,7 @@ public:
             offset += page.size();
         }
         RELEASE_ASSERT(offset == size);
-        return { WTFMove(buffer), size };
+        return CachedBytecode::create(WTFMove(buffer), size, WTFMove(m_leafExecutables));
     }
 
 private:
@@ -212,16 +217,13 @@ private:
     Page* m_currentPage;
     Vector<Page> m_pages;
     HashMap<const void*, ptrdiff_t> m_ptrToOffsetMap;
+    LeafExecutableMap m_leafExecutables;
 };
 
-Decoder::Decoder(VM& vm, const void* baseAddress, size_t size)
+Decoder::Decoder(VM& vm, Ref<CachedBytecode> cachedBytecode)
     : m_vm(vm)
-    , m_baseAddress(reinterpret_cast<const uint8_t*>(baseAddress))
-#ifndef NDEBUG
-    , m_size(size)
-#endif
+    , m_cachedBytecode(WTFMove(cachedBytecode))
 {
-    UNUSED_PARAM(size);
 }
 
 Decoder::~Decoder()
@@ -230,16 +232,21 @@ Decoder::~Decoder()
         finalizer();
 }
 
-Ref<Decoder> Decoder::create(VM& vm, const void* baseAddress, size_t size)
+Ref<Decoder> Decoder::create(VM& vm, Ref<CachedBytecode> cachedBytecode)
+{
+    return adoptRef(*new Decoder(vm, WTFMove(cachedBytecode)));
+}
+
+size_t Decoder::size() const
 {
-    return adoptRef(*new Decoder(vm, baseAddress, size));
+    return m_cachedBytecode->size();
 }
 
 ptrdiff_t Decoder::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;
+    ASSERT(addr >= m_cachedBytecode->data() && addr < m_cachedBytecode->data() + m_cachedBytecode->size());
+    return addr - m_cachedBytecode->data();
 }
 
 void Decoder::cacheOffset(ptrdiff_t offset, void* ptr)
@@ -258,9 +265,9 @@ WTF::Optional<void*> Decoder::cachedPtrForOffset(ptrdiff_t offset)
 const void* Decoder::ptrForOffsetFromBase(ptrdiff_t offset)
 {
 #ifndef NDEBUG
-    ASSERT(offset > 0 && static_cast<size_t>(offset) < m_size);
+    ASSERT(offset > 0 && static_cast<size_t>(offset) < m_cachedBytecode->size());
 #endif
-    return m_baseAddress + offset;
+    return m_cachedBytecode->data() + offset;
 }
 
 CompactVariableMap::Handle Decoder::handleForEnvironment(CompactVariableEnvironment* environment) const
@@ -276,6 +283,11 @@ void Decoder::setHandleForEnvironment(CompactVariableEnvironment* environment, c
     ASSERT_UNUSED(addResult, addResult.isNewEntry);
 }
 
+void Decoder::addLeafExecutable(const UnlinkedFunctionExecutable* executable, ptrdiff_t offset)
+{
+    m_cachedBytecode->leafExecutables().add(executable, offset);
+}
+
 template<typename Functor>
 void Decoder::addFinalizer(const Functor& fn)
 {
@@ -339,11 +351,17 @@ public:
 };
 
 template<typename Source>
-class VariableLengthObject : public CachedObject<Source> {
+class VariableLengthObject : public CachedObject<Source>, VariableLengthObjectBase {
     template<typename, typename>
-    friend struct CachedPtr;
+    friend class CachedPtr;
+    friend struct CachedPtrOffsets;
 
 public:
+    VariableLengthObject()
+        : VariableLengthObjectBase(s_invalidOffset)
+    {
+    }
+
     bool isEmpty() const
     {
         return m_offset == s_invalidOffset;
@@ -352,7 +370,7 @@ public:
 protected:
     const uint8_t* buffer() const
     {
-        ASSERT(m_offset != s_invalidOffset);
+        ASSERT(!isEmpty());
         return bitwise_cast<const uint8_t*>(this) + m_offset;
     }
 
@@ -379,15 +397,14 @@ protected:
 
 private:
     constexpr static ptrdiff_t s_invalidOffset = std::numeric_limits<ptrdiff_t>::max();
-
-    ptrdiff_t m_offset { s_invalidOffset };
-
 };
 
 template<typename T, typename Source = SourceType<T>>
 class CachedPtr : public VariableLengthObject<Source*> {
     template<typename, typename>
-    friend struct CachedRefPtr;
+    friend class CachedRefPtr;
+
+    friend struct CachedPtrOffsets;
 
 public:
     void encode(Encoder& encoder, const Source* src)
@@ -443,6 +460,11 @@ private:
     }
 };
 
+ptrdiff_t CachedPtrOffsets::offsetOffset()
+{
+    return OBJECT_OFFSETOF(CachedPtr<void>, m_offset);
+}
+
 template<typename T, typename Source = SourceType<T>>
 class CachedRefPtr : public CachedObject<RefPtr<Source>> {
 public:
@@ -482,6 +504,8 @@ private:
 
 template<typename T, typename Source = SourceType<T>>
 class CachedWriteBarrier : public CachedObject<WriteBarrier<Source>> {
+    friend struct CachedWriteBarrierOffsets;
+
 public:
     bool isEmpty() const { return m_ptr.isEmpty(); }
 
@@ -501,6 +525,11 @@ private:
     CachedPtr<T, Source> m_ptr;
 };
 
+ptrdiff_t CachedWriteBarrierOffsets::ptrOffset()
+{
+    return OBJECT_OFFSETOF(CachedWriteBarrier<void>, m_ptr);
+}
+
 template<typename T, size_t InlineCapacity = 0, typename OverflowHandler = CrashOnOverflow>
 class CachedVector : public VariableLengthObject<Vector<SourceType<T>, InlineCapacity, OverflowHandler>> {
 public:
@@ -1536,6 +1565,8 @@ private:
 };
 
 class CachedFunctionExecutable : public CachedObject<UnlinkedFunctionExecutable> {
+    friend struct CachedFunctionExecutableOffsets;
+
 public:
     void encode(Encoder&, const UnlinkedFunctionExecutable&);
     UnlinkedFunctionExecutable* decode(Decoder&) const;
@@ -1552,11 +1583,11 @@ public:
     unsigned typeProfilingEndOffset() const { return m_typeProfilingEndOffset; }
     unsigned parameterCount() const { return m_parameterCount; }
 
-    CodeFeatures features() const { return m_features; }
+    CodeFeatures features() const { return m_mutableMetadata.m_features; }
     SourceParseMode sourceParseMode() const { return m_sourceParseMode; }
 
     unsigned isInStrictContext() const { return m_isInStrictContext; }
-    unsigned hasCapturedVariables() const { return m_hasCapturedVariables; }
+    unsigned hasCapturedVariables() const { return m_mutableMetadata.m_hasCapturedVariables; }
     unsigned isBuiltinFunction() const { return m_isBuiltinFunction; }
     unsigned isBuiltinDefaultClassConstructor() const { return m_isBuiltinDefaultClassConstructor; }
     unsigned constructAbility() const { return m_constructAbility; }
@@ -1576,6 +1607,8 @@ public:
     const CachedWriteBarrier<CachedFunctionCodeBlock, UnlinkedFunctionCodeBlock>& unlinkedCodeBlockForConstruct() const { return m_unlinkedCodeBlockForConstruct; }
 
 private:
+    CachedFunctionExecutableMetadata m_mutableMetadata;
+
     unsigned m_firstLineOffset;
     unsigned m_lineCount;
     unsigned m_unlinkedFunctionNameStart;
@@ -1587,10 +1620,8 @@ private:
     unsigned m_typeProfilingStartOffset;
     unsigned m_typeProfilingEndOffset;
     unsigned m_parameterCount;
-    CodeFeatures m_features;
     SourceParseMode m_sourceParseMode;
     unsigned m_isInStrictContext : 1;
-    unsigned m_hasCapturedVariables : 1;
     unsigned m_isBuiltinFunction : 1;
     unsigned m_isBuiltinDefaultClassConstructor : 1;
     unsigned m_constructAbility: 1;
@@ -1610,6 +1641,21 @@ private:
     CachedWriteBarrier<CachedFunctionCodeBlock, UnlinkedFunctionCodeBlock> m_unlinkedCodeBlockForConstruct;
 };
 
+ptrdiff_t CachedFunctionExecutableOffsets::codeBlockForCallOffset()
+{
+    return OBJECT_OFFSETOF(CachedFunctionExecutable, m_unlinkedCodeBlockForCall);
+}
+
+ptrdiff_t CachedFunctionExecutableOffsets::codeBlockForConstructOffset()
+{
+    return OBJECT_OFFSETOF(CachedFunctionExecutable, m_unlinkedCodeBlockForConstruct);
+}
+
+ptrdiff_t CachedFunctionExecutableOffsets::metadataOffset()
+{
+    return OBJECT_OFFSETOF(CachedFunctionExecutable, m_mutableMetadata);
+}
+
 template<typename CodeBlockType>
 class CachedCodeBlock : public CachedObject<CodeBlockType> {
 public:
@@ -1925,6 +1971,9 @@ ALWAYS_INLINE UnlinkedEvalCodeBlock::UnlinkedEvalCodeBlock(Decoder& decoder, con
 
 ALWAYS_INLINE void CachedFunctionExecutable::encode(Encoder& encoder, const UnlinkedFunctionExecutable& executable)
 {
+    m_mutableMetadata.m_features = executable.m_features;
+    m_mutableMetadata.m_hasCapturedVariables = executable.m_hasCapturedVariables;
+
     m_firstLineOffset = executable.m_firstLineOffset;
     m_lineCount = executable.m_lineCount;
     m_unlinkedFunctionNameStart = executable.m_unlinkedFunctionNameStart;
@@ -1937,11 +1986,9 @@ ALWAYS_INLINE void CachedFunctionExecutable::encode(Encoder& encoder, const Unli
     m_typeProfilingEndOffset = executable.m_typeProfilingEndOffset;
     m_parameterCount = executable.m_parameterCount;
 
-    m_features = executable.m_features;
     m_sourceParseMode = executable.m_sourceParseMode;
 
     m_isInStrictContext = executable.m_isInStrictContext;
-    m_hasCapturedVariables = executable.m_hasCapturedVariables;
     m_isBuiltinFunction = executable.m_isBuiltinFunction;
     m_isBuiltinDefaultClassConstructor = executable.m_isBuiltinDefaultClassConstructor;
     m_constructAbility = executable.m_constructAbility;
@@ -1959,13 +2006,15 @@ ALWAYS_INLINE void CachedFunctionExecutable::encode(Encoder& encoder, const Unli
 
     m_unlinkedCodeBlockForCall.encode(encoder, executable.m_unlinkedCodeBlockForCall);
     m_unlinkedCodeBlockForConstruct.encode(encoder, executable.m_unlinkedCodeBlockForConstruct);
+
+    if (!executable.m_unlinkedCodeBlockForCall || !executable.m_unlinkedCodeBlockForConstruct)
+        encoder.addLeafExecutable(&executable, encoder.offsetOf(this));
 }
 
 ALWAYS_INLINE UnlinkedFunctionExecutable* CachedFunctionExecutable::decode(Decoder& decoder) const
 {
     UnlinkedFunctionExecutable* executable = new (NotNull, allocateCell<UnlinkedFunctionExecutable>(decoder.vm().heap)) UnlinkedFunctionExecutable(decoder, *this);
     executable->finishCreation(decoder.vm());
-
     return executable;
 }
 
@@ -2005,18 +2054,27 @@ ALWAYS_INLINE UnlinkedFunctionExecutable::UnlinkedFunctionExecutable(Decoder& de
     , m_rareData(cachedExecutable.rareData(decoder))
 {
 
+    uint32_t leafExecutables = 2;
+    auto checkBounds = [&](int32_t& codeBlockOffset, auto& cachedPtr) {
+        if (!cachedPtr.isEmpty()) {
+            ptrdiff_t offset = decoder.offsetOf(&cachedPtr);
+            if (static_cast<size_t>(offset) < decoder.size()) {
+                codeBlockOffset = offset;
+                m_isCached = true;
+                leafExecutables--;
+            }
+        }
+    };
+
     if (!cachedExecutable.unlinkedCodeBlockForCall().isEmpty() || !cachedExecutable.unlinkedCodeBlockForConstruct().isEmpty()) {
-        m_isCached = true;
-        m_decoder = &decoder;
-        if (!cachedExecutable.unlinkedCodeBlockForCall().isEmpty())
-            m_cachedCodeBlockForCallOffset = decoder.offsetOf(&cachedExecutable.unlinkedCodeBlockForCall());
-        else
-            m_cachedCodeBlockForCallOffset = 0;
-        if (!cachedExecutable.unlinkedCodeBlockForConstruct().isEmpty())
-            m_cachedCodeBlockForConstructOffset = decoder.offsetOf(&cachedExecutable.unlinkedCodeBlockForConstruct());
-        else
-            m_cachedCodeBlockForConstructOffset = 0;
+        checkBounds(m_cachedCodeBlockForCallOffset, cachedExecutable.unlinkedCodeBlockForCall());
+        checkBounds(m_cachedCodeBlockForConstructOffset, cachedExecutable.unlinkedCodeBlockForConstruct());
+        if (m_isCached)
+            m_decoder = &decoder;
     }
+
+    if (leafExecutables)
+        decoder.addLeafExecutable(this, decoder.offsetOf(&cachedExecutable));
 }
 
 template<typename CodeBlockType>
@@ -2209,7 +2267,7 @@ void encodeCodeBlock(Encoder& encoder, const SourceCodeKey& key, const UnlinkedC
     entry->encode(encoder, { key, jsCast<const UnlinkedCodeBlockType*>(codeBlock) });
 }
 
-std::pair<MallocPtr<uint8_t>, size_t> encodeCodeBlock(VM& vm, const SourceCodeKey& key, const UnlinkedCodeBlock* codeBlock)
+Ref<CachedBytecode> encodeCodeBlock(VM& vm, const SourceCodeKey& key, const UnlinkedCodeBlock* codeBlock)
 {
     const ClassInfo* classInfo = codeBlock->classInfo(vm);
 
@@ -2224,10 +2282,17 @@ std::pair<MallocPtr<uint8_t>, size_t> encodeCodeBlock(VM& vm, const SourceCodeKe
     return encoder.release();
 }
 
-UnlinkedCodeBlock* decodeCodeBlockImpl(VM& vm, const SourceCodeKey& key, const void* buffer, size_t size)
+Ref<CachedBytecode> encodeFunctionCodeBlock(VM& vm, const UnlinkedFunctionCodeBlock* codeBlock)
 {
-    const auto* cachedEntry = bitwise_cast<const GenericCacheEntry*>(buffer);
-    Ref<Decoder> decoder = Decoder::create(vm, buffer, size);
+    Encoder encoder(vm);
+    encoder.malloc<CachedFunctionCodeBlock>()->encode(encoder, *codeBlock);
+    return encoder.release();
+}
+
+UnlinkedCodeBlock* decodeCodeBlockImpl(VM& vm, const SourceCodeKey& key, Ref<CachedBytecode> cachedBytecode)
+{
+    const auto* cachedEntry = bitwise_cast<const GenericCacheEntry*>(cachedBytecode->data());
+    Ref<Decoder> decoder = Decoder::create(vm, WTFMove(cachedBytecode));
     std::pair<SourceCodeKey, UnlinkedCodeBlock*> entry;
     {
         DeferGC deferGC(vm.heap);
@@ -2240,14 +2305,14 @@ UnlinkedCodeBlock* decodeCodeBlockImpl(VM& vm, const SourceCodeKey& key, const v
     return entry.second;
 }
 
-bool isCachedBytecodeStillValid(VM& vm, const CachedBytecode& cachedBytecode, const SourceCodeKey& key, SourceCodeType type)
+bool isCachedBytecodeStillValid(VM& vm, Ref<CachedBytecode> cachedBytecode, const SourceCodeKey& key, SourceCodeType type)
 {
-    const void* buffer = cachedBytecode.data();
-    size_t size = cachedBytecode.size();
+    const void* buffer = cachedBytecode->data();
+    size_t size = cachedBytecode->size();
     if (!size)
         return false;
     const auto* cachedEntry = bitwise_cast<const GenericCacheEntry*>(buffer);
-    Ref<Decoder> decoder = Decoder::create(vm, buffer, size);
+    Ref<Decoder> decoder = Decoder::create(vm, WTFMove(cachedBytecode));
     return cachedEntry->isStillValid(decoder.get(), key, tagFromSourceCodeType(type));
 }
 
index 9db3abd..2e04b10 100644 (file)
@@ -26,6 +26,7 @@
 #pragma once
 
 #include "JSCast.h"
+#include "ParserModes.h"
 #include "VariableEnvironment.h"
 #include <wtf/HashMap.h>
 #include <wtf/MallocPtr.h>
@@ -37,15 +38,51 @@ class SourceCodeKey;
 class UnlinkedCodeBlock;
 class UnlinkedFunctionCodeBlock;
 
+enum class SourceCodeType;
+
+// This struct has to be updated when incrementally writing to the bytecode
+// cache, since this will only be filled in when we parse the function
+struct CachedFunctionExecutableMetadata {
+    CodeFeatures m_features;
+    bool m_hasCapturedVariables;
+};
+
+struct CachedFunctionExecutableOffsets {
+    static ptrdiff_t codeBlockForCallOffset();
+    static ptrdiff_t codeBlockForConstructOffset();
+    static ptrdiff_t metadataOffset();
+};
+
+struct CachedWriteBarrierOffsets {
+    static ptrdiff_t ptrOffset();
+};
+
+struct CachedPtrOffsets {
+    static ptrdiff_t offsetOffset();
+};
+
+class VariableLengthObjectBase {
+    friend class CachedBytecode;
+
+protected:
+    VariableLengthObjectBase(ptrdiff_t offset)
+        : m_offset(offset)
+    {
+    }
+
+    ptrdiff_t m_offset;
+};
+
 class Decoder : public RefCounted<Decoder> {
     WTF_MAKE_NONCOPYABLE(Decoder);
 
 public:
-    static Ref<Decoder> create(VM&, const void*, size_t);
+    static Ref<Decoder> create(VM&, Ref<CachedBytecode>);
 
     ~Decoder();
 
     VM& vm() { return m_vm; }
+    size_t size() const;
 
     ptrdiff_t offsetOf(const void*);
     void cacheOffset(ptrdiff_t, void*);
@@ -53,37 +90,35 @@ public:
     const void* ptrForOffsetFromBase(ptrdiff_t);
     CompactVariableMap::Handle handleForEnvironment(CompactVariableEnvironment*) const;
     void setHandleForEnvironment(CompactVariableEnvironment*, const CompactVariableMap::Handle&);
+    void addLeafExecutable(const UnlinkedFunctionExecutable*, ptrdiff_t);
 
     template<typename Functor>
     void addFinalizer(const Functor&);
 
 private:
-    Decoder(VM&, const void*, size_t);
+    Decoder(VM&, Ref<CachedBytecode>);
 
     VM& m_vm;
-    const uint8_t* m_baseAddress;
-#ifndef NDEBUG
-    size_t m_size;
-#endif
+    Ref<CachedBytecode> m_cachedBytecode;
     HashMap<ptrdiff_t, void*> m_offsetToPtrMap;
     Vector<std::function<void()>> m_finalizers;
     HashMap<CompactVariableEnvironment*, CompactVariableMap::Handle> m_environmentToHandleMap;
 };
 
-enum class SourceCodeType;
+JS_EXPORT_PRIVATE Ref<CachedBytecode> encodeCodeBlock(VM&, const SourceCodeKey&, const UnlinkedCodeBlock*);
 
-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*);
+UnlinkedCodeBlock* decodeCodeBlockImpl(VM&, const SourceCodeKey&, Ref<CachedBytecode>);
 
 template<typename UnlinkedCodeBlockType>
-UnlinkedCodeBlockType* decodeCodeBlock(VM& vm, const SourceCodeKey& key, const void* buffer, size_t size)
+UnlinkedCodeBlockType* decodeCodeBlock(VM& vm, const SourceCodeKey& key, Ref<CachedBytecode> cachedBytecode)
 {
-    return jsCast<UnlinkedCodeBlockType*>(decodeCodeBlockImpl(vm, key, buffer, size));
+    return jsCast<UnlinkedCodeBlockType*>(decodeCodeBlockImpl(vm, key, WTFMove(cachedBytecode)));
 }
 
-bool isCachedBytecodeStillValid(VM&, const CachedBytecode&, const SourceCodeKey&, SourceCodeType);
+JS_EXPORT_PRIVATE Ref<CachedBytecode> encodeFunctionCodeBlock(VM&, const UnlinkedFunctionCodeBlock*);
+
+JS_EXPORT_PRIVATE void decodeFunctionCodeBlock(Decoder&, int32_t cachedFunctionCodeBlockOffset, WriteBarrier<UnlinkedFunctionCodeBlock>&, const JSCell*);
+
+bool isCachedBytecodeStillValid(VM&, Ref<CachedBytecode>, const SourceCodeKey&, SourceCodeType);
 
 } // namespace JSC
index 3e424df..931348d 100644 (file)
@@ -83,6 +83,10 @@ UnlinkedCodeBlockType* CodeCache::getUnlinkedGlobalCodeBlock(VM& vm, ExecutableT
     if (unlinkedCodeBlock && Options::useCodeCache())
         m_sourceCode.addCache(key, SourceCodeValue(vm, unlinkedCodeBlock, m_sourceCode.age()));
 
+    key.source().provider().cacheBytecode([&] {
+        return encodeCodeBlock(vm, key, unlinkedCodeBlock);
+    });
+
     return unlinkedCodeBlock;
 }
 
@@ -162,14 +166,15 @@ UnlinkedFunctionExecutable* CodeCache::getUnlinkedGlobalFunctionExecutable(VM& v
     return functionExecutable;
 }
 
+void CodeCache::updateCache(const UnlinkedFunctionExecutable* executable, const SourceCode& parentSource, CodeSpecializationKind kind, const UnlinkedFunctionCodeBlock* codeBlock)
+{
+    parentSource.provider()->updateCache(executable, parentSource, kind, codeBlock);
+}
+
 void CodeCache::write(VM& vm)
 {
-    for (auto& it : m_sourceCode) {
-        if (it.value.written)
-            continue;
-        it.value.written = true;
+    for (auto& it : m_sourceCode)
         writeCodeBlock(vm, it.key, it.value);
-    }
 }
 
 void generateUnlinkedCodeBlockForFunctions(VM& vm, UnlinkedCodeBlock* unlinkedCodeBlock, const SourceCode& parentSource, DebuggerMode debuggerMode, ParserError& error)
@@ -198,10 +203,7 @@ void writeCodeBlock(VM& vm, const SourceCodeKey& key, const SourceCodeValue& val
     if (!codeBlock)
         return;
 
-    key.source().provider().cacheBytecode([&] {
-        std::pair<MallocPtr<uint8_t>, size_t> result = encodeCodeBlock(vm, key, codeBlock);
-        return CachedBytecode { WTFMove(result.first), result.second };
-    });
+    key.source().provider().commitCachedBytecode();
 }
 
 static SourceCodeKey sourceCodeKeyForSerializedBytecode(VM& vm, const SourceCode& sourceCode, SourceCodeType codeType, JSParserStrictMode strictMode, JSParserScriptMode scriptMode, DebuggerMode debuggerMode)
@@ -230,11 +232,10 @@ SourceCodeKey sourceCodeKeyForSerializedModule(VM& vm, const SourceCode& sourceC
     return sourceCodeKeyForSerializedBytecode(vm, sourceCode, SourceCodeType::ModuleType, strictMode, scriptMode, debuggerMode);
 }
 
-CachedBytecode serializeBytecode(VM& vm, UnlinkedCodeBlock* codeBlock, const SourceCode& source, SourceCodeType codeType, JSParserStrictMode strictMode, JSParserScriptMode scriptMode, DebuggerMode debuggerMode)
+Ref<CachedBytecode> serializeBytecode(VM& vm, UnlinkedCodeBlock* codeBlock, const SourceCode& source, SourceCodeType codeType, JSParserStrictMode strictMode, JSParserScriptMode scriptMode, DebuggerMode debuggerMode)
 {
-    std::pair<MallocPtr<uint8_t>, size_t> result = encodeCodeBlock(vm,
+    return encodeCodeBlock(vm,
         sourceCodeKeyForSerializedBytecode(vm, source, codeType, strictMode, scriptMode, debuggerMode), codeBlock);
-    return CachedBytecode { WTFMove(result.first), result.second };
 }
 
 }
index c85afa5..16abd1d 100644 (file)
@@ -62,26 +62,19 @@ namespace CodeCacheInternal {
 static const bool verbose = false;
 } // namespace CodeCacheInternal
 
-#define VERBOSE_LOG(...) do { \
-    if (CodeCacheInternal::verbose) \
-        dataLogLn("(JSC::CodeCache) ", __VA_ARGS__); \
-} while (false)
-
 struct SourceCodeValue {
     SourceCodeValue()
     {
     }
 
-    SourceCodeValue(VM& vm, JSCell* cell, int64_t age, bool written = false)
+    SourceCodeValue(VM& vm, JSCell* cell, int64_t age)
         : cell(vm, cell)
         , age(age)
-        , written(written)
     {
     }
 
     Strong<JSCell> cell;
     int64_t age;
-    bool written;
 };
 
 class CodeCacheMap {
@@ -108,7 +101,6 @@ public:
     {
         prune();
 
-        VERBOSE_LOG("Trying to find cached CodeBlock for ", key.source().provider().url().string());
         iterator findResult = m_map.find(key);
         if (findResult == m_map.end())
             return fetchFromDisk<UnlinkedCodeBlockType>(vm, key);
@@ -131,7 +123,6 @@ public:
         findResult->value.age = m_age;
         m_age += key.length();
 
-        VERBOSE_LOG("Found cached CodeBlock in memory");
         return jsCast<UnlinkedCodeBlockType*>(findResult->value.cell.get());
     }
 
@@ -166,14 +157,10 @@ private:
     template<typename UnlinkedCodeBlockType>
     UnlinkedCodeBlockType* fetchFromDiskImpl(VM& vm, const SourceCodeKey& key)
     {
-        const CachedBytecode* cachedBytecode = key.source().provider().cachedBytecode();
-        if (cachedBytecode && cachedBytecode->size()) {
-            VERBOSE_LOG("Found cached CodeBlock in the SourceProvider");
-            UnlinkedCodeBlockType* unlinkedCodeBlock = decodeCodeBlock<UnlinkedCodeBlockType>(vm, key, cachedBytecode->data(), cachedBytecode->size());
-            if (unlinkedCodeBlock)
-                return unlinkedCodeBlock;
-        }
-        return nullptr;
+        RefPtr<CachedBytecode> cachedBytecode = key.source().provider().cachedBytecode();
+        if (!cachedBytecode || !cachedBytecode->size())
+            return nullptr;
+        return decodeCodeBlock<UnlinkedCodeBlockType>(vm, key, *cachedBytecode);
     }
 
     template<typename UnlinkedCodeBlockType>
@@ -240,6 +227,8 @@ public:
     UnlinkedModuleProgramCodeBlock* getUnlinkedModuleProgramCodeBlock(VM&, ModuleProgramExecutable*, const SourceCode&, DebuggerMode, ParserError&);
     UnlinkedFunctionExecutable* getUnlinkedGlobalFunctionExecutable(VM&, const Identifier&, const SourceCode&, DebuggerMode, Optional<int> functionConstructorParametersEndPosition, ParserError&);
 
+    void updateCache(const UnlinkedFunctionExecutable*, const SourceCode&, CodeSpecializationKind, const UnlinkedFunctionCodeBlock*);
+
     void clear() { m_sourceCode.clear(); }
     JS_EXPORT_PRIVATE void write(VM&);
 
@@ -329,7 +318,7 @@ recursivelyGenerateUnlinkedCodeBlock(VM& vm, const SourceCode& source, JSParserS
 }
 
 void writeCodeBlock(VM&, const SourceCodeKey&, const SourceCodeValue&);
-CachedBytecode serializeBytecode(VM&, UnlinkedCodeBlock*, const SourceCode&, SourceCodeType, JSParserStrictMode, JSParserScriptMode, DebuggerMode);
+Ref<CachedBytecode> serializeBytecode(VM&, UnlinkedCodeBlock*, const SourceCode&, SourceCodeType, JSParserStrictMode, JSParserScriptMode, DebuggerMode);
 SourceCodeKey sourceCodeKeyForSerializedProgram(VM&, const SourceCode&);
 SourceCodeKey sourceCodeKeyForSerializedModule(VM&, const SourceCode&);
 
index 3bf9fb7..27237b1 100644 (file)
@@ -91,7 +91,7 @@ bool checkModuleSyntax(ExecState* exec, const SourceCode& source, ParserError& e
     return true;
 }
 
-CachedBytecode generateProgramBytecode(VM& vm, const SourceCode& source, ParserError& error)
+Ref<CachedBytecode> generateProgramBytecode(VM& vm, const SourceCode& source, ParserError& error)
 {
     JSLockHolder lock(vm);
     RELEASE_ASSERT(vm.atomicStringTable() == Thread::current().atomicStringTable());
@@ -104,11 +104,11 @@ CachedBytecode generateProgramBytecode(VM& vm, const SourceCode& source, ParserE
 
     UnlinkedCodeBlock* unlinkedCodeBlock = recursivelyGenerateUnlinkedCodeBlock<UnlinkedProgramCodeBlock>(vm, source, strictMode, scriptMode, debuggerMode, error, evalContextType, &variablesUnderTDZ);
     if (!unlinkedCodeBlock)
-        return { };
+        return CachedBytecode::create();
     return serializeBytecode(vm, unlinkedCodeBlock, source, SourceCodeType::ProgramType, strictMode, scriptMode, debuggerMode);
 }
 
-CachedBytecode generateModuleBytecode(VM& vm, const SourceCode& source, ParserError& error)
+Ref<CachedBytecode> generateModuleBytecode(VM& vm, const SourceCode& source, ParserError& error)
 {
     JSLockHolder lock(vm);
     RELEASE_ASSERT(vm.atomicStringTable() == Thread::current().atomicStringTable());
@@ -121,7 +121,7 @@ CachedBytecode generateModuleBytecode(VM& vm, const SourceCode& source, ParserEr
 
     UnlinkedCodeBlock* unlinkedCodeBlock = recursivelyGenerateUnlinkedCodeBlock<UnlinkedModuleProgramCodeBlock>(vm, source, strictMode, scriptMode, debuggerMode, error, evalContextType, &variablesUnderTDZ);
     if (!unlinkedCodeBlock)
-        return { };
+        return CachedBytecode::create();
     return serializeBytecode(vm, unlinkedCodeBlock, source, SourceCodeType::ModuleType, strictMode, scriptMode, debuggerMode);
 }
 
index 8d14200..d5a0231 100644 (file)
@@ -42,8 +42,8 @@ JS_EXPORT_PRIVATE bool checkSyntax(VM&, const SourceCode&, ParserError&);
 JS_EXPORT_PRIVATE bool checkSyntax(ExecState*, const SourceCode&, JSValue* exception = 0);
 JS_EXPORT_PRIVATE bool checkModuleSyntax(ExecState*, const SourceCode&, ParserError&);
 
-JS_EXPORT_PRIVATE CachedBytecode generateProgramBytecode(VM&, const SourceCode&, ParserError&);
-JS_EXPORT_PRIVATE CachedBytecode generateModuleBytecode(VM&, const SourceCode&, ParserError&);
+JS_EXPORT_PRIVATE Ref<CachedBytecode> generateProgramBytecode(VM&, const SourceCode&, ParserError&);
+JS_EXPORT_PRIVATE Ref<CachedBytecode> generateModuleBytecode(VM&, const SourceCode&, ParserError&);
 
 JS_EXPORT_PRIVATE JSValue evaluate(ExecState*, const SourceCode&, JSValue thisValue, NakedPtr<Exception>& returnedException);
 inline JSValue evaluate(ExecState* exec, const SourceCode& sourceCode, JSValue thisValue = JSValue())
diff --git a/Source/JavaScriptCore/runtime/LeafExecutable.cpp b/Source/JavaScriptCore/runtime/LeafExecutable.cpp
new file mode 100644 (file)
index 0000000..81e0f71
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2019 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "LeafExecutable.h"
+
+namespace JSC {
+
+LeafExecutable LeafExecutable::operator+(size_t offset) const
+{
+    return LeafExecutable { static_cast<ptrdiff_t>(m_base + offset) };
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/LeafExecutable.h b/Source/JavaScriptCore/runtime/LeafExecutable.h
new file mode 100644 (file)
index 0000000..0cb10f6
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2019 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <wtf/HashMap.h>
+
+namespace JSC {
+
+class LeafExecutable;
+class UnlinkedFunctionExecutable;
+
+using LeafExecutableMap = HashMap<const UnlinkedFunctionExecutable*, LeafExecutable>;
+
+class LeafExecutable {
+public:
+    LeafExecutable() = default;
+
+    LeafExecutable(ptrdiff_t offset)
+        : m_base(offset)
+    {
+    }
+
+    ptrdiff_t base() const { return m_base; }
+    LeafExecutable operator+(size_t) const;
+
+private:
+    ptrdiff_t m_base;
+};
+
+} // namespace JSC
index ddab7a4..bdfab11 100644 (file)
@@ -1,3 +1,14 @@
+2019-04-10  Tadeu Zagallo  <tzagallo@apple.com>
+
+        Add support for incremental bytecode cache updates
+        https://bugs.webkit.org/show_bug.cgi?id=195000
+
+        Reviewed by Filip Pizlo.
+
+        Exit when the initial run to generate bytecode fails.
+
+        * Scripts/jsc-stress-test-helpers/bytecode-cache-test-helper.sh:
+
 2019-04-10  Alex Christensen  <achristensen@webkit.org>
 
         RemoteObjectRegistry message receiver should be removed when WebPage::close is called instead of waiting until dealloc
index 83e2d59..4f39e72 100644 (file)
@@ -29,7 +29,7 @@ mysys() {
     exitCode=$?
     if [ $exitCode != 0 ]; then
         echo "Command '$*' failed"
-        return $exitCode
+        exit $exitCode
     fi
 }