Make JSScript:cacheBytecodeWithError update the cache when the script changes
authorsbarati@apple.com <sbarati@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 28 Feb 2019 23:58:12 +0000 (23:58 +0000)
committersbarati@apple.com <sbarati@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 28 Feb 2019 23:58:12 +0000 (23:58 +0000)
https://bugs.webkit.org/show_bug.cgi?id=194912

Reviewed by Mark Lam.

Prior to this patch, the JSScript SPI would never check if its cached
bytecode were still valid. This would lead the cacheBytecodeWithError
succeeding even if the underlying cache were stale. This patch fixes
that by making JSScript check if the cache is still valid. If it's not,
we will cache bytecode when cacheBytecodeWithError is invoked.

* API/JSScript.mm:
(-[JSScript readCache]):
(-[JSScript writeCache:]):
* API/tests/testapi.mm:
(testBytecodeCacheWithSameCacheFileAndDifferentScript):
(testObjectiveCAPI):
* runtime/CachedTypes.cpp:
(JSC::Decoder::Decoder):
(JSC::VariableLengthObject::buffer const):
(JSC::CachedPtr::decode const):
(JSC::tagFromSourceCodeType):
(JSC::GenericCacheEntry::isUpToDate const):
(JSC::CacheEntry::isStillValid const):
(JSC::GenericCacheEntry::decode const):
(JSC::GenericCacheEntry::isStillValid const):
(JSC::encodeCodeBlock):
(JSC::decodeCodeBlockImpl):
(JSC::isCachedBytecodeStillValid):
* runtime/CachedTypes.h:
* runtime/CodeCache.cpp:
(JSC::sourceCodeKeyForSerializedBytecode):
(JSC::sourceCodeKeyForSerializedProgram):
(JSC::sourceCodeKeyForSerializedModule):
(JSC::serializeBytecode):
* runtime/CodeCache.h:
(JSC::CodeCacheMap::fetchFromDiskImpl):
* runtime/Completion.cpp:
(JSC::generateProgramBytecode):
(JSC::generateBytecode): Deleted.
* runtime/Completion.h:

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

Source/JavaScriptCore/API/JSScript.mm
Source/JavaScriptCore/API/tests/testapi.mm
Source/JavaScriptCore/ChangeLog
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

index 434b02f..b33ad50 100644 (file)
@@ -27,6 +27,8 @@
 #import "JSScriptInternal.h"
 
 #import "APICast.h"
+#import "CachedTypes.h"
+#import "CodeCache.h"
 #import "Identifier.h"
 #import "JSContextInternal.h"
 #import "JSScriptSourceProvider.h"
@@ -201,7 +203,13 @@ static JSScript *createError(NSString *message, NSError** error)
     void* buffer = mmap(nullptr, size, PROT_READ, MAP_PRIVATE, fd, 0);
     close(fd);
 
-    m_cachedBytecode = JSC::CachedBytecode { buffer, size };
+    JSC::CachedBytecode cachedBytecode { buffer, size };
+
+    JSC::VM& vm = m_virtualMachine.vm;
+    const JSC::SourceCode& sourceCode = [self jsSourceCode]->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))
+        m_cachedBytecode = WTFMove(cachedBytecode);
 }
 
 - (BOOL)cacheBytecodeWithError:(NSError **)error
@@ -269,7 +277,7 @@ static JSScript *createError(NSString *message, NSError** error)
         m_cachedBytecode = JSC::generateModuleBytecode(m_virtualMachine.vm, [self jsSourceCode]->sourceCode(), parserError);
         break;
     case kJSScriptTypeProgram:
-        m_cachedBytecode = JSC::generateBytecode(m_virtualMachine.vm, [self jsSourceCode]->sourceCode(), parserError);
+        m_cachedBytecode = JSC::generateProgramBytecode(m_virtualMachine.vm, [self jsSourceCode]->sourceCode(), parserError);
         break;
     }
 
index fea65ce..c32d8be 100644 (file)
@@ -2094,6 +2094,50 @@ static void testBytecodeCacheWithSyntaxError(JSScriptType type)
     }
 }
 
+static void testBytecodeCacheWithSameCacheFileAndDifferentScript(bool forceDiskCache)
+{
+    NSURL *cachePath = tempFile(@"cachePath.cache");
+    NSURL *sourceURL = [NSURL URLWithString:@"my-path"];
+
+    @autoreleasepool {
+        JSVirtualMachine *vm = [[JSVirtualMachine alloc] init];
+        NSString *source = @"function foo() { return 42; }; function bar() { return 40; }; foo() + bar();";
+        JSContext *context = [[JSContext alloc] initWithVirtualMachine:vm];
+        JSScript *script = [JSScript scriptOfType:kJSScriptTypeProgram withSource:source andSourceURL:sourceURL andBytecodeCache:cachePath inVirtualMachine:vm error:nil];
+        RELEASE_ASSERT(script);
+        if (![script cacheBytecodeWithError:nil])
+            CRASH();
+
+        JSC::Options::forceDiskCache() = forceDiskCache;
+        JSValue *result = [context evaluateJSScript:script];
+        RELEASE_ASSERT(result);
+        RELEASE_ASSERT([result isNumber]);
+        checkResult(@"Expected 82 as result", [[result toNumber] intValue] == 82);
+    }
+
+    @autoreleasepool {
+        JSVirtualMachine *vm = [[JSVirtualMachine alloc] init];
+        NSString *source = @"function foo() { return 10; }; function bar() { return 20; }; foo() + bar();";
+        JSContext *context = [[JSContext alloc] initWithVirtualMachine:vm];
+        JSScript *script = [JSScript scriptOfType:kJSScriptTypeProgram withSource:source andSourceURL:sourceURL andBytecodeCache:cachePath inVirtualMachine:vm error:nil];
+        RELEASE_ASSERT(script);
+        if (![script cacheBytecodeWithError:nil])
+            CRASH();
+
+        JSC::Options::forceDiskCache() = forceDiskCache;
+        JSValue *result = [context evaluateJSScript:script];
+        RELEASE_ASSERT(result);
+        RELEASE_ASSERT([result isNumber]);
+        checkResult(@"Expected 30 as result", [[result toNumber] intValue] == 30);
+    }
+
+    JSC::Options::forceDiskCache() = false;
+
+    NSFileManager* fileManager = [NSFileManager defaultManager];
+    BOOL removedAll = [fileManager removeItemAtURL:cachePath error:nil];
+    checkResult(@"Removed all temp files created", removedAll);
+}
+
 static void testProgramJSScriptException()
 {
     @autoreleasepool {
@@ -2319,6 +2363,8 @@ void testObjectiveCAPI(const char* filter)
     RUN(testProgramBytecodeCache());
     RUN(testBytecodeCacheWithSyntaxError(kJSScriptTypeProgram));
     RUN(testBytecodeCacheWithSyntaxError(kJSScriptTypeModule));
+    RUN(testBytecodeCacheWithSameCacheFileAndDifferentScript(false));
+    RUN(testBytecodeCacheWithSameCacheFileAndDifferentScript(true));
     RUN(testProgramJSScriptException());
 
     RUN(testLoaderRejectsNilScriptURL());
index 38eddc6..670c95c 100644 (file)
@@ -1,3 +1,47 @@
+2019-02-28  Saam barati  <sbarati@apple.com>
+
+        Make JSScript:cacheBytecodeWithError update the cache when the script changes
+        https://bugs.webkit.org/show_bug.cgi?id=194912
+
+        Reviewed by Mark Lam.
+
+        Prior to this patch, the JSScript SPI would never check if its cached
+        bytecode were still valid. This would lead the cacheBytecodeWithError
+        succeeding even if the underlying cache were stale. This patch fixes
+        that by making JSScript check if the cache is still valid. If it's not,
+        we will cache bytecode when cacheBytecodeWithError is invoked.
+
+        * API/JSScript.mm:
+        (-[JSScript readCache]):
+        (-[JSScript writeCache:]):
+        * API/tests/testapi.mm:
+        (testBytecodeCacheWithSameCacheFileAndDifferentScript):
+        (testObjectiveCAPI):
+        * runtime/CachedTypes.cpp:
+        (JSC::Decoder::Decoder):
+        (JSC::VariableLengthObject::buffer const):
+        (JSC::CachedPtr::decode const):
+        (JSC::tagFromSourceCodeType):
+        (JSC::GenericCacheEntry::isUpToDate const):
+        (JSC::CacheEntry::isStillValid const):
+        (JSC::GenericCacheEntry::decode const):
+        (JSC::GenericCacheEntry::isStillValid const):
+        (JSC::encodeCodeBlock):
+        (JSC::decodeCodeBlockImpl):
+        (JSC::isCachedBytecodeStillValid):
+        * runtime/CachedTypes.h:
+        * runtime/CodeCache.cpp:
+        (JSC::sourceCodeKeyForSerializedBytecode):
+        (JSC::sourceCodeKeyForSerializedProgram):
+        (JSC::sourceCodeKeyForSerializedModule):
+        (JSC::serializeBytecode):
+        * runtime/CodeCache.h:
+        (JSC::CodeCacheMap::fetchFromDiskImpl):
+        * runtime/Completion.cpp:
+        (JSC::generateProgramBytecode):
+        (JSC::generateBytecode): Deleted.
+        * runtime/Completion.h:
+
 2019-02-28  Mark Lam  <mark.lam@apple.com>
 
         cloop.rb shift mask should depend on the word size being shifted.
index 46c9195..d19c2a5 100644 (file)
@@ -33,6 +33,7 @@
 #include "JSTemplateObjectDescriptor.h"
 #include "ScopedArgumentsTable.h"
 #include "SourceCodeKey.h"
+#include "SourceProvider.h"
 #include "UnlinkedEvalCodeBlock.h"
 #include "UnlinkedFunctionCodeBlock.h"
 #include "UnlinkedMetadataTableInlines.h"
@@ -217,7 +218,7 @@ class Decoder {
 public:
     Decoder(VM& vm, const void* baseAddress, size_t size)
         : m_vm(vm)
-        , m_baseAddress(reinterpret_cast<const uint8_t*>(baseAddress))
+        , m_baseAddress(static_cast<const uint8_t*>(baseAddress))
 #ifndef NDEBUG
         , m_size(size)
 #endif
@@ -348,7 +349,7 @@ protected:
     const uint8_t* buffer() const
     {
         ASSERT(m_offset != s_invalidOffset);
-        return reinterpret_cast<const uint8_t*>(this) + m_offset;
+        return bitwise_cast<const uint8_t*>(this) + m_offset;
     }
 
     template<typename T>
@@ -412,7 +413,7 @@ public:
         ptrdiff_t bufferOffset = decoder.offsetOf(this->buffer());
         if (Optional<void*> ptr = decoder.cachedPtrForOffset(bufferOffset)) {
             isNewAllocation = false;
-            return reinterpret_cast<Source*>(*ptr);
+            return static_cast<Source*>(*ptr);
         }
 
         isNewAllocation = true;
@@ -1815,6 +1816,21 @@ enum CachedCodeBlockTag {
     CachedEvalCodeBlockTag,
 };
 
+static constexpr CachedCodeBlockTag tagFromSourceCodeType(SourceCodeType type)
+{
+    switch (type) {
+    case SourceCodeType::ProgramType:
+        return CachedProgramCodeBlockTag;
+    case SourceCodeType::EvalType:
+        return CachedEvalCodeBlockTag;
+    case SourceCodeType::ModuleType:
+        return CachedModuleCodeBlockTag;
+    case SourceCodeType::FunctionType:
+        ASSERT_NOT_REACHED();
+        return static_cast<CachedCodeBlockTag>(-1);
+    }
+}
+
 template<>
 struct CachedCodeBlockTypeImpl<UnlinkedProgramCodeBlock> {
     using type = CachedProgramCodeBlock;
@@ -2078,6 +2094,7 @@ private:
 class GenericCacheEntry {
 public:
     bool decode(Decoder&, std::pair<SourceCodeKey, UnlinkedCodeBlock*>&) const;
+    bool isStillValid(Decoder&, const SourceCodeKey&, CachedCodeBlockTag) const;
 
 protected:
     GenericCacheEntry(Encoder& encoder, CachedCodeBlockTag tag)
@@ -2088,6 +2105,15 @@ protected:
 
     CachedCodeBlockTag tag() const { return m_tag; }
 
+    bool isUpToDate(Decoder& decoder) const
+    {
+        if (m_cacheVersion != JSC_BYTECODE_CACHE_VERSION)
+            return false;
+        if (m_bootSessionUUID.decode(decoder) != bootSessionUUIDString())
+            return false;
+        return true;
+    }
+
 private:
     uint32_t m_cacheVersion { JSC_BYTECODE_CACHE_VERSION };
     CachedString m_bootSessionUUID;
@@ -2111,6 +2137,13 @@ public:
 private:
     friend GenericCacheEntry;
 
+    bool isStillValid(Decoder& decoder, const SourceCodeKey& key) const
+    {
+        SourceCodeKey decodedKey;
+        m_key.decode(decoder, decodedKey);
+        return decodedKey == key;
+    }
+
     bool decode(Decoder& decoder, std::pair<SourceCodeKey, UnlinkedCodeBlockType*>& result) const
     {
         ASSERT(tag() == CachedCodeBlockTypeImpl<UnlinkedCodeBlockType>::tag);
@@ -2126,16 +2159,14 @@ private:
 
 bool GenericCacheEntry::decode(Decoder& decoder, std::pair<SourceCodeKey, UnlinkedCodeBlock*>& result) const
 {
-    if (m_cacheVersion != JSC_BYTECODE_CACHE_VERSION)
-        return false;
-    if (m_bootSessionUUID.decode(decoder) != bootSessionUUIDString())
+    if (!isUpToDate(decoder))
         return false;
 
     switch (m_tag) {
     case CachedProgramCodeBlockTag:
-        return reinterpret_cast<const CacheEntry<UnlinkedProgramCodeBlock>*>(this)->decode(decoder, reinterpret_cast<std::pair<SourceCodeKey, UnlinkedProgramCodeBlock*>&>(result));
+        return bitwise_cast<const CacheEntry<UnlinkedProgramCodeBlock>*>(this)->decode(decoder, reinterpret_cast<std::pair<SourceCodeKey, UnlinkedProgramCodeBlock*>&>(result));
     case CachedModuleCodeBlockTag:
-        return reinterpret_cast<const CacheEntry<UnlinkedModuleProgramCodeBlock>*>(this)->decode(decoder, reinterpret_cast<std::pair<SourceCodeKey, UnlinkedModuleProgramCodeBlock*>&>(result));
+        return bitwise_cast<const CacheEntry<UnlinkedModuleProgramCodeBlock>*>(this)->decode(decoder, reinterpret_cast<std::pair<SourceCodeKey, UnlinkedModuleProgramCodeBlock*>&>(result));
     case CachedEvalCodeBlockTag:
         // We do not cache eval code blocks
         RELEASE_ASSERT_NOT_REACHED();
@@ -2147,11 +2178,29 @@ bool GenericCacheEntry::decode(Decoder& decoder, std::pair<SourceCodeKey, Unlink
 #endif
 }
 
+bool GenericCacheEntry::isStillValid(Decoder& decoder, const SourceCodeKey& key, CachedCodeBlockTag tag) const
+{
+    if (!isUpToDate(decoder))
+        return false;
+
+    switch (tag) {
+    case CachedProgramCodeBlockTag:
+        return bitwise_cast<const CacheEntry<UnlinkedProgramCodeBlock>*>(this)->isStillValid(decoder, key);
+    case CachedModuleCodeBlockTag:
+        return bitwise_cast<const CacheEntry<UnlinkedModuleProgramCodeBlock>*>(this)->isStillValid(decoder, key);
+    case CachedEvalCodeBlockTag:
+        // We do not cache eval code blocks
+        RELEASE_ASSERT_NOT_REACHED();
+    }
+    RELEASE_ASSERT_NOT_REACHED();
+    return false;
+}
+
 template<typename UnlinkedCodeBlockType>
 void encodeCodeBlock(Encoder& encoder, const SourceCodeKey& key, const UnlinkedCodeBlock* codeBlock)
 {
     auto* entry = encoder.template malloc<CacheEntry<UnlinkedCodeBlockType>>(encoder);
-    entry->encode(encoder,  { key, jsCast<const UnlinkedCodeBlockType*>(codeBlock) });
+    entry->encode(encoder, { key, jsCast<const UnlinkedCodeBlockType*>(codeBlock) });
 }
 
 std::pair<MallocPtr<uint8_t>, size_t> encodeCodeBlock(VM& vm, const SourceCodeKey& key, const UnlinkedCodeBlock* codeBlock)
@@ -2171,7 +2220,7 @@ 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);
+    const auto* cachedEntry = bitwise_cast<const GenericCacheEntry*>(buffer);
     Decoder decoder(vm, buffer, size);
     std::pair<SourceCodeKey, UnlinkedCodeBlock*> entry;
     {
@@ -2185,4 +2234,15 @@ UnlinkedCodeBlock* decodeCodeBlockImpl(VM& vm, const SourceCodeKey& key, const v
     return entry.second;
 }
 
+bool isCachedBytecodeStillValid(VM& vm, const CachedBytecode& cachedBytecode, const SourceCodeKey& key, SourceCodeType type)
+{
+    const void* buffer = cachedBytecode.data();
+    size_t size = cachedBytecode.size();
+    if (!size)
+        return false;
+    const auto* cachedEntry = bitwise_cast<const GenericCacheEntry*>(buffer);
+    Decoder decoder(vm, buffer, size);
+    return cachedEntry->isStillValid(decoder, key, tagFromSourceCodeType(type));
+}
+
 } // namespace JSC
index bcb8acb..7e92d55 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 Apple Inc. All rights reserved.
+ * Copyright (C) 2018-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
 
 namespace JSC {
 
+class CachedBytecode;
 class SourceCodeKey;
 class UnlinkedCodeBlock;
 
+enum class SourceCodeType;
+
 std::pair<MallocPtr<uint8_t>, size_t> encodeCodeBlock(VM&, const SourceCodeKey&, const UnlinkedCodeBlock*);
 UnlinkedCodeBlock* decodeCodeBlockImpl(VM&, const SourceCodeKey&, const void*, size_t);
 
@@ -43,4 +46,6 @@ UnlinkedCodeBlockType* decodeCodeBlock(VM& vm, const SourceCodeKey& key, const v
     return jsCast<UnlinkedCodeBlockType*>(decodeCodeBlockImpl(vm, key, buffer, size));
 }
 
+bool isCachedBytecodeStillValid(VM&, const CachedBytecode&, const SourceCodeKey&, SourceCodeType);
+
 } // namespace JSC
index fd5f968..d6ea8e3 100644 (file)
@@ -205,15 +205,36 @@ void writeCodeBlock(VM& vm, const SourceCodeKey& key, const SourceCodeValue& val
     });
 }
 
-CachedBytecode serializeBytecode(VM& vm, UnlinkedCodeBlock* codeBlock, const SourceCode& source, SourceCodeType codeType, JSParserStrictMode strictMode, JSParserScriptMode scriptMode, DebuggerMode debuggerMode)
+static SourceCodeKey sourceCodeKeyForSerializedBytecode(VM& vm, const SourceCode& sourceCode, SourceCodeType codeType, JSParserStrictMode strictMode, JSParserScriptMode scriptMode, DebuggerMode debuggerMode)
 {
-    SourceCodeKey key(
-        source, String(), codeType, strictMode, scriptMode,
+    return SourceCodeKey(
+        sourceCode, String(), codeType, strictMode, scriptMode,
         DerivedContextType::None, EvalContextType::None, false, debuggerMode,
         vm.typeProfiler() ? TypeProfilerEnabled::Yes : TypeProfilerEnabled::No,
         vm.controlFlowProfiler() ? ControlFlowProfilerEnabled::Yes : ControlFlowProfilerEnabled::No,
         WTF::nullopt);
-    std::pair<MallocPtr<uint8_t>, size_t> result = encodeCodeBlock(vm, key, codeBlock);
+}
+
+SourceCodeKey sourceCodeKeyForSerializedProgram(VM& vm, const SourceCode& sourceCode)
+{
+    JSParserStrictMode strictMode = JSParserStrictMode::NotStrict;
+    JSParserScriptMode scriptMode = JSParserScriptMode::Classic;
+    DebuggerMode debuggerMode = DebuggerOff;
+    return sourceCodeKeyForSerializedBytecode(vm, sourceCode, SourceCodeType::ProgramType, strictMode, scriptMode, debuggerMode);
+}
+
+SourceCodeKey sourceCodeKeyForSerializedModule(VM& vm, const SourceCode& sourceCode)
+{
+    JSParserStrictMode strictMode = JSParserStrictMode::Strict;
+    JSParserScriptMode scriptMode = JSParserScriptMode::Module;
+    DebuggerMode debuggerMode = DebuggerOff;
+    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)
+{
+    std::pair<MallocPtr<uint8_t>, size_t> result = encodeCodeBlock(vm,
+        sourceCodeKeyForSerializedBytecode(vm, source, codeType, strictMode, scriptMode, debuggerMode), codeBlock);
     return CachedBytecode { WTFMove(result.first), result.second };
 }
 
index f14c27b..c85afa5 100644 (file)
@@ -104,33 +104,6 @@ public:
     iterator end() { return m_map.end(); }
 
     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;
-    }
-
-    template<typename UnlinkedCodeBlockType>
-    std::enable_if_t<std::is_base_of<UnlinkedCodeBlock, UnlinkedCodeBlockType>::value && !std::is_same<UnlinkedCodeBlockType, UnlinkedEvalCodeBlock>::value, UnlinkedCodeBlockType*>
-    fetchFromDisk(VM& vm, const SourceCodeKey& key)
-    {
-        UnlinkedCodeBlockType* codeBlock = fetchFromDiskImpl<UnlinkedCodeBlockType>(vm, key);
-        if (UNLIKELY(Options::forceDiskCache()))
-            RELEASE_ASSERT(codeBlock);
-        return codeBlock;
-    }
-
-    template<typename T>
-    std::enable_if_t<!std::is_base_of<UnlinkedCodeBlock, T>::value || std::is_same<T, UnlinkedEvalCodeBlock>::value, T*>
-    fetchFromDisk(VM&, const SourceCodeKey&) { return nullptr; }
-
-    template<typename UnlinkedCodeBlockType>
     UnlinkedCodeBlockType* findCacheAndUpdateAge(VM& vm, const SourceCodeKey& key)
     {
         prune();
@@ -190,6 +163,33 @@ public:
     int64_t age() { return m_age; }
 
 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;
+    }
+
+    template<typename UnlinkedCodeBlockType>
+    std::enable_if_t<std::is_base_of<UnlinkedCodeBlock, UnlinkedCodeBlockType>::value && !std::is_same<UnlinkedCodeBlockType, UnlinkedEvalCodeBlock>::value, UnlinkedCodeBlockType*>
+    fetchFromDisk(VM& vm, const SourceCodeKey& key)
+    {
+        UnlinkedCodeBlockType* codeBlock = fetchFromDiskImpl<UnlinkedCodeBlockType>(vm, key);
+        if (UNLIKELY(Options::forceDiskCache()))
+            RELEASE_ASSERT(codeBlock);
+        return codeBlock;
+    }
+
+    template<typename T>
+    std::enable_if_t<!std::is_base_of<UnlinkedCodeBlock, T>::value || std::is_same<T, UnlinkedEvalCodeBlock>::value, T*>
+    fetchFromDisk(VM&, const SourceCodeKey&) { return nullptr; }
+
     // This constant factor biases cache capacity toward allowing a minimum
     // working set to enter the cache before it starts evicting.
     static const Seconds workingSetTime;
@@ -330,5 +330,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);
+SourceCodeKey sourceCodeKeyForSerializedProgram(VM&, const SourceCode&);
+SourceCodeKey sourceCodeKeyForSerializedModule(VM&, const SourceCode&);
 
 } // namespace JSC
index 38a9b9f..3bf9fb7 100644 (file)
@@ -91,7 +91,7 @@ bool checkModuleSyntax(ExecState* exec, const SourceCode& source, ParserError& e
     return true;
 }
 
-CachedBytecode generateBytecode(VM& vm, const SourceCode& source, ParserError& error)
+CachedBytecode generateProgramBytecode(VM& vm, const SourceCode& source, ParserError& error)
 {
     JSLockHolder lock(vm);
     RELEASE_ASSERT(vm.atomicStringTable() == Thread::current().atomicStringTable());
index 3072889..8d14200 100644 (file)
@@ -42,7 +42,7 @@ 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 generateBytecode(VM&, const SourceCode&, ParserError&);
+JS_EXPORT_PRIVATE CachedBytecode generateProgramBytecode(VM&, const SourceCode&, ParserError&);
 JS_EXPORT_PRIVATE CachedBytecode generateModuleBytecode(VM&, const SourceCode&, ParserError&);
 
 JS_EXPORT_PRIVATE JSValue evaluate(ExecState*, const SourceCode&, JSValue thisValue, NakedPtr<Exception>& returnedException);