Add API to generate and consume cached bytecode
authortzagallo@apple.com <tzagallo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 25 Jan 2019 22:31:12 +0000 (22:31 +0000)
committertzagallo@apple.com <tzagallo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 25 Jan 2019 22:31:12 +0000 (22:31 +0000)
https://bugs.webkit.org/show_bug.cgi?id=193401
<rdar://problem/47514099>

Reviewed by Keith Miller.

Add the `generateBytecode` and `generateModuleBytecode` functions to
generate serialized bytecode for a given `SourceCode`. These functions
will eagerly generate code for all the nested functions.

Additionally, update the API methods in JSScript to generate and use the
bytecode when the bytecodeCache path is provided.

* API/JSAPIGlobalObject.mm:
(JSC::JSAPIGlobalObject::moduleLoaderFetch):
* API/JSContext.mm:
(-[JSContext wrapperMap]):
* API/JSContextInternal.h:
* API/JSScript.mm:
(+[JSScript scriptWithSource:inVirtualMachine:]):
(+[JSScript scriptFromASCIIFile:inVirtualMachine:withCodeSigning:andBytecodeCache:]):
(-[JSScript dealloc]):
(-[JSScript readCache]):
(-[JSScript writeCache]):
(-[JSScript hash]):
(-[JSScript source]):
(-[JSScript cachedBytecode]):
(-[JSScript jsSourceCode:]):
* API/JSScriptInternal.h:
* API/JSScriptSourceProvider.h: Copied from Source/JavaScriptCore/API/JSScriptInternal.h.
(JSScriptSourceProvider::create):
(JSScriptSourceProvider::JSScriptSourceProvider):
* API/JSScriptSourceProvider.mm: Copied from Source/JavaScriptCore/API/JSScriptInternal.h.
(JSScriptSourceProvider::hash const):
(JSScriptSourceProvider::source const):
(JSScriptSourceProvider::cachedBytecode const):
* API/JSVirtualMachine.mm:
(-[JSVirtualMachine vm]):
* API/JSVirtualMachineInternal.h:
* API/tests/testapi.mm:
(testBytecodeCache):
(-[JSContextFileLoaderDelegate context:fetchModuleForIdentifier:withResolveHandler:andRejectHandler:]):
(testObjectiveCAPI):
* JavaScriptCore.xcodeproj/project.pbxproj:
* SourcesCocoa.txt:
* bytecode/UnlinkedFunctionExecutable.cpp:
(JSC::UnlinkedFunctionExecutable::unlinkedCodeBlockFor):
* bytecode/UnlinkedFunctionExecutable.h:
* parser/SourceCodeKey.h:
(JSC::SourceCodeKey::source const):
* parser/SourceProvider.h:
(JSC::CachedBytecode::CachedBytecode):
(JSC::CachedBytecode::operator=):
(JSC::CachedBytecode::data const):
(JSC::CachedBytecode::size const):
(JSC::CachedBytecode::owned const):
(JSC::CachedBytecode::~CachedBytecode):
(JSC::CachedBytecode::freeDataIfOwned):
(JSC::SourceProvider::cachedBytecode const):
* parser/UnlinkedSourceCode.h:
(JSC::UnlinkedSourceCode::provider const):
* runtime/CodeCache.cpp:
(JSC::generateUnlinkedCodeBlockForFunctions):
(JSC::writeCodeBlock):
(JSC::serializeBytecode):
* runtime/CodeCache.h:
(JSC::CodeCacheMap::fetchFromDiskImpl):
(JSC::CodeCacheMap::findCacheAndUpdateAge):
(JSC::generateUnlinkedCodeBlockImpl):
(JSC::generateUnlinkedCodeBlock):
* runtime/Completion.cpp:
(JSC::generateBytecode):
(JSC::generateModuleBytecode):
* runtime/Completion.h:
* runtime/Options.cpp:
(JSC::recomputeDependentOptions):

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

23 files changed:
Source/JavaScriptCore/API/JSAPIGlobalObject.mm
Source/JavaScriptCore/API/JSContext.mm
Source/JavaScriptCore/API/JSContextInternal.h
Source/JavaScriptCore/API/JSScript.mm
Source/JavaScriptCore/API/JSScriptInternal.h
Source/JavaScriptCore/API/JSScriptSourceProvider.h [new file with mode: 0644]
Source/JavaScriptCore/API/JSScriptSourceProvider.mm [new file with mode: 0644]
Source/JavaScriptCore/API/JSVirtualMachine.mm
Source/JavaScriptCore/API/JSVirtualMachineInternal.h
Source/JavaScriptCore/API/tests/testapi.mm
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
Source/JavaScriptCore/SourcesCocoa.txt
Source/JavaScriptCore/bytecode/UnlinkedFunctionExecutable.cpp
Source/JavaScriptCore/bytecode/UnlinkedFunctionExecutable.h
Source/JavaScriptCore/parser/SourceCodeKey.h
Source/JavaScriptCore/parser/SourceProvider.h
Source/JavaScriptCore/parser/UnlinkedSourceCode.h
Source/JavaScriptCore/runtime/CodeCache.cpp
Source/JavaScriptCore/runtime/CodeCache.h
Source/JavaScriptCore/runtime/Completion.cpp
Source/JavaScriptCore/runtime/Completion.h
Source/JavaScriptCore/runtime/Options.cpp

index 3ca4ab9..d5c2365 100644 (file)
@@ -164,7 +164,6 @@ JSInternalPromise* JSAPIGlobalObject::moduleLoaderFetch(JSGlobalObject* globalOb
     auto deferredPromise = Strong<JSInternalPromiseDeferred>(vm, deferred);
     auto strongKey = Strong<JSString>(vm, jsSecureCast<JSString*>(vm, key));
     auto* resolve = JSNativeStdFunction::create(vm, globalObject, 1, "resolve", [=] (ExecState* exec) {
     auto deferredPromise = Strong<JSInternalPromiseDeferred>(vm, deferred);
     auto strongKey = Strong<JSString>(vm, jsSecureCast<JSString*>(vm, key));
     auto* resolve = JSNativeStdFunction::create(vm, globalObject, 1, "resolve", [=] (ExecState* exec) {
-        VM& vm = exec->vm();
         // This captures the globalObject but that's ok because our structure keeps it alive anyway.
         JSContext *context = [JSContext contextWithJSGlobalContextRef:toGlobalRef(globalObject->globalExec())];
         id script = valueToObject(context, toRef(exec, exec->argument(0)));
         // This captures the globalObject but that's ok because our structure keeps it alive anyway.
         JSContext *context = [JSContext contextWithJSGlobalContextRef:toGlobalRef(globalObject->globalExec())];
         id script = valueToObject(context, toRef(exec, exec->argument(0)));
@@ -176,8 +175,7 @@ JSInternalPromise* JSAPIGlobalObject::moduleLoaderFetch(JSGlobalObject* globalOb
             return encodedJSUndefined();
         }
 
             return encodedJSUndefined();
         }
 
-        const String& source = getJSScriptSourceCode(static_cast<JSScript *>(script));
-        args.append(JSSourceCode::create(vm, makeSource(source, SourceOrigin(moduleKey.string()), URL({ }, moduleKey.string()), TextPosition(), JSC::SourceProviderSourceType::Module)));
+        args.append([static_cast<JSScript *>(script) jsSourceCode:moduleKey]);
         call(exec, deferredPromise->JSPromiseDeferred::resolve(), args, "This should never be seen...");
         return encodedJSUndefined();
     });
         call(exec, deferredPromise->JSPromiseDeferred::resolve(), args, "This should never be seen...");
         return encodedJSUndefined();
     });
index 3c776d4..518fb87 100644 (file)
@@ -34,7 +34,6 @@
 #import "JSGlobalObject.h"
 #import "JSInternalPromise.h"
 #import "JSModuleLoader.h"
 #import "JSGlobalObject.h"
 #import "JSInternalPromise.h"
 #import "JSModuleLoader.h"
-#import "JSScriptInternal.h"
 #import "JSValueInternal.h"
 #import "JSVirtualMachineInternal.h"
 #import "JSWrapperMap.h"
 #import "JSValueInternal.h"
 #import "JSVirtualMachineInternal.h"
 #import "JSWrapperMap.h"
     return [JSValue valueWithJSValueRef:toRef(m_exception.get()) inContext:self];
 }
 
     return [JSValue valueWithJSValueRef:toRef(m_exception.get()) inContext:self];
 }
 
-- (JSWrapperMap *)wrapperMap
-{
-    return toJS(m_context)->lexicalGlobalObject()->wrapperMap();
-}
-
 - (JSValue *)globalObject
 {
     return [JSValue valueWithJSValueRef:JSContextGetGlobalObject(m_context) inContext:self];
 - (JSValue *)globalObject
 {
     return [JSValue valueWithJSValueRef:JSContextGetGlobalObject(m_context) inContext:self];
     return [[self wrapperMap] jsWrapperForObject:object inContext:self];
 }
 
     return [[self wrapperMap] jsWrapperForObject:object inContext:self];
 }
 
+- (JSWrapperMap *)wrapperMap
+{
+    return toJS(m_context)->lexicalGlobalObject()->wrapperMap();
+}
+
 - (JSValue *)wrapperForJSObject:(JSValueRef)value
 {
     JSC::JSLockHolder locker(toJS(m_context));
 - (JSValue *)wrapperForJSObject:(JSValueRef)value
 {
     JSC::JSLockHolder locker(toJS(m_context));
index ab45829..958c479 100644 (file)
@@ -51,6 +51,7 @@ struct CallbackData {
 - (void)beginCallbackWithData:(CallbackData *)callbackData calleeValue:(JSValueRef)calleeValue thisValue:(JSValueRef)thisValue argumentCount:(size_t)argumentCount arguments:(const JSValueRef *)arguments;
 - (void)endCallbackWithData:(CallbackData *)callbackData;
 
 - (void)beginCallbackWithData:(CallbackData *)callbackData calleeValue:(JSValueRef)calleeValue thisValue:(JSValueRef)thisValue argumentCount:(size_t)argumentCount arguments:(const JSValueRef *)arguments;
 - (void)endCallbackWithData:(CallbackData *)callbackData;
 
+- (JSWrapperMap *)wrapperMap;
 - (JSValue *)wrapperForObjCObject:(id)object;
 - (JSValue *)wrapperForJSObject:(JSValueRef)value;
 
 - (JSValue *)wrapperForObjCObject:(id)object;
 - (JSValue *)wrapperForJSObject:(JSValueRef)value;
 
index f7e939a..fef446d 100644 (file)
 #import "JSScriptInternal.h"
 
 #import "APICast.h"
 #import "JSScriptInternal.h"
 
 #import "APICast.h"
+#import "Identifier.h"
 #import "JSContextInternal.h"
 #import "JSContextInternal.h"
+#import "JSScriptSourceProvider.h"
+#import "JSSourceCode.h"
 #import "JSValuePrivate.h"
 #import "JSValuePrivate.h"
+#import "JSVirtualMachineInternal.h"
+#import "ParserError.h"
 #import "Symbol.h"
 #import "Symbol.h"
+#include <sys/stat.h>
 
 #if JSC_OBJC_API_ENABLED
 
 @implementation JSScript {
 
 #if JSC_OBJC_API_ENABLED
 
 @implementation JSScript {
+    __weak JSVirtualMachine* m_virtualMachine;
     String m_source;
     String m_source;
+    NSURL* m_cachePath;
+    JSC::CachedBytecode m_cachedBytecode;
+    JSC::Strong<JSC::JSSourceCode> m_jsSourceCode;
+    UniquedStringImpl* m_moduleKey;
 }
 
 + (instancetype)scriptWithSource:(NSString *)source inVirtualMachine:(JSVirtualMachine *)vm
 {
 }
 
 + (instancetype)scriptWithSource:(NSString *)source inVirtualMachine:(JSVirtualMachine *)vm
 {
-    UNUSED_PARAM(vm);
-    JSScript *result = [[JSScript alloc] init];
+    JSScript *result = [[[JSScript alloc] init] autorelease];
     result->m_source = source;
     result->m_source = source;
+    result->m_virtualMachine = vm;
     return result;
 }
 
     return result;
 }
 
@@ -81,9 +92,6 @@ static bool fillBufferWithContentsOfFile(const String& fileName, Vector<LChar>&
 {
     // FIXME: This should check codeSigning.
     UNUSED_PARAM(codeSigningPath);
 {
     // FIXME: This should check codeSigning.
     UNUSED_PARAM(codeSigningPath);
-    // FIXME: This should actually cache bytecode.
-    UNUSED_PARAM(cachePath);
-    UNUSED_PARAM(vm);
     URL filePathURL([filePath absoluteURL]);
     if (!filePathURL.isLocalFile())
         return nil;
     URL filePathURL([filePath absoluteURL]);
     if (!filePathURL.isLocalFile())
         return nil;
@@ -95,8 +103,11 @@ static bool fillBufferWithContentsOfFile(const String& fileName, Vector<LChar>&
     if (!charactersAreAllASCII(buffer.data(), buffer.size()))
         return nil;
 
     if (!charactersAreAllASCII(buffer.data(), buffer.size()))
         return nil;
 
-    JSScript *result = [[JSScript alloc] init];
+    JSScript *result = [[[JSScript alloc] init] autorelease];
+    result->m_virtualMachine = vm;
     result->m_source = String::fromUTF8WithLatin1Fallback(buffer.data(), buffer.size());
     result->m_source = String::fromUTF8WithLatin1Fallback(buffer.data(), buffer.size());
+    result->m_cachePath = cachePath;
+    [result readCache];
     return result;
 }
 
     return result;
 }
 
@@ -105,7 +116,95 @@ static bool fillBufferWithContentsOfFile(const String& fileName, Vector<LChar>&
     return [JSScript scriptFromASCIIFile:filePath inVirtualMachine:vm withCodeSigning:codeSigningPath andBytecodeCache:cachePath];
 }
 
     return [JSScript scriptFromASCIIFile:filePath inVirtualMachine:vm withCodeSigning:codeSigningPath andBytecodeCache:cachePath];
 }
 
-const String& getJSScriptSourceCode(JSScript *module) { return module->m_source; }
+- (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)
+        return;
+
+    int fd = open(m_cachePath.path.UTF8String, O_RDONLY);
+    if (fd == -1)
+        return;
+
+    int rc = flock(fd, LOCK_SH | LOCK_NB);
+    if (rc) {
+        close(fd);
+        return;
+    }
+
+    struct stat sb;
+    int res = fstat(fd, &sb);
+    size_t size = static_cast<size_t>(sb.st_size);
+    if (res || !size) {
+        close(fd);
+        return;
+    }
+
+    void* buffer = mmap(nullptr, size, PROT_READ, MAP_PRIVATE, fd, 0);
+    close(fd);
+
+    m_cachedBytecode = JSC::CachedBytecode { buffer, size };
+}
+
+- (void)writeCache
+{
+    if (m_cachedBytecode.size() || !m_cachePath)
+        return;
+
+    JSC::ParserError error;
+    m_cachedBytecode = JSC::generateModuleBytecode(m_virtualMachine.vm, m_jsSourceCode->sourceCode(), error);
+    if (error.isValid())
+        return;
+    int fd = open(m_cachePath.path.UTF8String, O_CREAT | O_WRONLY, 0666);
+    if (fd == -1)
+        return;
+    int rc = flock(fd, LOCK_EX | LOCK_NB);
+    if (!rc)
+        write(fd, m_cachedBytecode.data(), m_cachedBytecode.size());
+    close(fd);
+}
+
+@end
+
+@implementation JSScript(Internal)
+
+- (unsigned)hash
+{
+    return m_source.hash();
+}
+
+- (const String&)source
+{
+    return m_source;
+}
+
+- (const JSC::CachedBytecode*)cachedBytecode
+{
+    return &m_cachedBytecode;
+}
+
+- (JSC::JSSourceCode*)jsSourceCode:(const JSC::Identifier&)moduleKey
+{
+    if (m_jsSourceCode) {
+        ASSERT(moduleKey.impl() == m_moduleKey);
+        return m_jsSourceCode.get();
+    }
+
+    JSC::VM& vm = m_virtualMachine.vm;
+    TextPosition startPosition { };
+    Ref<JSScriptSourceProvider> sourceProvider = JSScriptSourceProvider::create(self, JSC::SourceOrigin(moduleKey.string()), URL({ }, moduleKey.string()), TextPosition(), JSC::SourceProviderSourceType::Module);
+    JSC::SourceCode sourceCode(WTFMove(sourceProvider), startPosition.m_line.oneBasedInt(), startPosition.m_column.oneBasedInt());
+    JSC::JSSourceCode* jsSourceCode = JSC::JSSourceCode::create(vm, WTFMove(sourceCode));
+    m_jsSourceCode.set(vm, jsSourceCode);
+    [self writeCache];
+    return jsSourceCode;
+}
 
 @end
 
 
 @end
 
index a973ed1..66a75e2 100644 (file)
 #import "JSScript.h"
 #import "SourceCode.h"
 
 #import "JSScript.h"
 #import "SourceCode.h"
 
-OBJC_CLASS JSScript;
+#if JSC_OBJC_API_ENABLED
 
 
-const String& getJSScriptSourceCode(JSScript *);
+NS_ASSUME_NONNULL_BEGIN
+
+namespace JSC {
+class CachedBytecode;
+class Identifier;
+class JSSourceCode;
+};
+
+namespace WTF {
+class String;
+};
+
+@interface JSScript(Internal)
+
+- (unsigned)hash;
+- (const WTF::String&)source;
+- (const JSC::CachedBytecode*)cachedBytecode;
+- (JSC::JSSourceCode*)jsSourceCode:(const JSC::Identifier&)moduleKey;
+
+@end
+
+NS_ASSUME_NONNULL_END
+
+#endif // JSC_OBJC_API_ENABLED
diff --git a/Source/JavaScriptCore/API/JSScriptSourceProvider.h b/Source/JavaScriptCore/API/JSScriptSourceProvider.h
new file mode 100644 (file)
index 0000000..3e8431d
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+
+#if JSC_OBJC_API_ENABLED
+
+#import "SourceProvider.h"
+
+@class JSScript;
+
+class JSScriptSourceProvider : public JSC::SourceProvider {
+public:
+    template<typename... Args>
+    static Ref<JSScriptSourceProvider> create(JSScript *script, Args&&... args)
+    {
+        return adoptRef(*new JSScriptSourceProvider(script, std::forward<Args>(args)...));
+    }
+
+    unsigned hash() const override;
+    StringView source() const override;
+    const JSC::CachedBytecode* cachedBytecode() const override;
+
+private:
+    template<typename... Args>
+    JSScriptSourceProvider(JSScript *script, Args&&... args)
+        : SourceProvider(std::forward<Args>(args)...)
+        , m_script(script)
+    { }
+
+    RetainPtr<JSScript> m_script;
+};
+
+#endif // JSC_OBJC_API_ENABLED
diff --git a/Source/JavaScriptCore/API/JSScriptSourceProvider.mm b/Source/JavaScriptCore/API/JSScriptSourceProvider.mm
new file mode 100644 (file)
index 0000000..5536a8b
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+#import "config.h"
+#import "JSScriptSourceProvider.h"
+
+#if JSC_OBJC_API_ENABLED
+
+#import "JSScriptInternal.h"
+
+unsigned JSScriptSourceProvider::hash() const
+{
+    return [m_script.get() hash];
+}
+
+StringView JSScriptSourceProvider::source() const
+{
+    return [m_script.get() source];
+}
+
+const JSC::CachedBytecode* JSScriptSourceProvider::cachedBytecode() const
+{
+    return [m_script.get() cachedBytecode];
+}
+
+#endif // JSC_OBJC_API_ENABLED
index 5e795f0..504d33c 100644 (file)
@@ -297,6 +297,11 @@ JSContextGroupRef getGroupFromVirtualMachine(JSVirtualMachine *virtualMachine)
 
 #endif // ENABLE(DFG_JIT)
 
 
 #endif // ENABLE(DFG_JIT)
 
+- (JSC::VM&)vm
+{
+    return *toJS(m_group);
+}
+
 @end
 
 static void scanExternalObjectGraph(JSC::VM& vm, JSC::SlotVisitor& visitor, void* root, bool lockAcquired)
 @end
 
 static void scanExternalObjectGraph(JSC::VM& vm, JSC::SlotVisitor& visitor, void* root, bool lockAcquired)
index 9122ed4..9b0bf6b 100644 (file)
@@ -46,6 +46,8 @@ JSContextGroupRef getGroupFromVirtualMachine(JSVirtualMachine *);
 
 - (JSContext *)contextForGlobalContextRef:(JSGlobalContextRef)globalContext;
 - (void)addContext:(JSContext *)wrapper forGlobalContextRef:(JSGlobalContextRef)globalContext;
 
 - (JSContext *)contextForGlobalContextRef:(JSGlobalContextRef)globalContext;
 - (void)addContext:(JSContext *)wrapper forGlobalContextRef:(JSGlobalContextRef)globalContext;
+- (JSC::VM&)vm;
+
 @end
 
 #endif // defined(__OBJC__)
 @end
 
 #endif // defined(__OBJC__)
index 13beb69..2289e6e 100644 (file)
@@ -1980,6 +1980,68 @@ static void testImportModuleTwice()
     }
 }
 
     }
 }
 
+static void testBytecodeCache()
+{
+    @autoreleasepool {
+        NSURL* tempDirectory = [NSURL fileURLWithPath:NSTemporaryDirectory() isDirectory:YES];
+
+        NSString* fooSource = @"import { n } from \"../foo.js\"; export let foo = n;";
+        NSString* barSource = @"import \"otherDirectory/baz.js\"; export let n = null;";
+        NSString* bazSource = @"import { foo } from \"../directory/bar.js\"; globalThis.ran = null; export let exp = foo;";
+
+        NSURL* fooPath = [tempDirectory URLByAppendingPathComponent:@"foo.js"];
+        NSURL* barPath = [tempDirectory URLByAppendingPathComponent:@"bar.js"];
+        NSURL* bazPath = [tempDirectory URLByAppendingPathComponent:@"baz.js"];
+
+        NSURL* fooCachePath = [tempDirectory URLByAppendingPathComponent:@"foo.js.cache"];
+        NSURL* barCachePath = [tempDirectory URLByAppendingPathComponent:@"bar.js.cache"];
+        NSURL* bazCachePath = [tempDirectory URLByAppendingPathComponent:@"baz.js.cache"];
+
+        [fooSource writeToURL:fooPath atomically:NO encoding:NSASCIIStringEncoding error:nil];
+        [barSource writeToURL:barPath atomically:NO encoding:NSASCIIStringEncoding error:nil];
+        [bazSource writeToURL:bazPath atomically:NO encoding:NSASCIIStringEncoding error:nil];
+
+        __block bool forceDiskCache = false;
+        auto block = ^(JSContext *context, JSValue *identifier, JSValue *resolve, JSValue *reject) {
+            JSC::Options::forceDiskCache() = forceDiskCache;
+            if ([identifier isEqualToObject:@"file:///directory/bar.js"])
+                [resolve callWithArguments:@[[JSScript scriptFromASCIIFile:fooPath inVirtualMachine:context.virtualMachine withCodeSigning:nil andBytecodeCache:fooCachePath]]];
+            else if ([identifier isEqualToObject:@"file:///foo.js"])
+                [resolve callWithArguments:@[[JSScript scriptFromASCIIFile:barPath inVirtualMachine:context.virtualMachine withCodeSigning:nil andBytecodeCache:barCachePath]]];
+            else if ([identifier isEqualToObject:@"file:///otherDirectory/baz.js"])
+                [resolve callWithArguments:@[[JSScript scriptFromASCIIFile:bazPath inVirtualMachine:context.virtualMachine withCodeSigning:nil andBytecodeCache:bazCachePath]]];
+            else
+                [reject callWithArguments:@[[JSValue valueWithNewErrorFromMessage:@"Weird path" inContext:context]]];
+        };
+
+        @autoreleasepool {
+            auto *context = [JSContextFetchDelegate contextWithBlockForFetch:block];
+            context.moduleLoaderDelegate = context;
+            JSValue *promise = [context evaluateScript:@"import('../otherDirectory/baz.js');" withSourceURL:[NSURL fileURLWithPath:@"/directory" isDirectory:YES]];
+            JSValue *null = [JSValue valueWithNullInContext:context];
+            checkModuleCodeRan(context, promise, null);
+        }
+
+        @autoreleasepool {
+            forceDiskCache = true;
+            auto *context = [JSContextFetchDelegate contextWithBlockForFetch:block];
+            context.moduleLoaderDelegate = context;
+            JSValue *promise = [context evaluateScript:@"import('../otherDirectory/baz.js');" withSourceURL:[NSURL fileURLWithPath:@"/directory" isDirectory:YES]];
+            JSValue *null = [JSValue valueWithNullInContext:context];
+            checkModuleCodeRan(context, promise, null);
+            JSC::Options::forceDiskCache() = false;
+        }
+
+        NSFileManager* fileManager = [NSFileManager defaultManager];
+        [fileManager removeItemAtURL:fooPath error:nil];
+        [fileManager removeItemAtURL:barPath error:nil];
+        [fileManager removeItemAtURL:bazPath error:nil];
+        [fileManager removeItemAtURL:fooCachePath error:nil];
+        [fileManager removeItemAtURL:barCachePath error:nil];
+        [fileManager removeItemAtURL:bazCachePath error:nil];
+    }
+}
+
 @interface JSContextFileLoaderDelegate : JSContext <JSModuleLoaderDelegate>
 
 + (instancetype)newContext;
 @interface JSContextFileLoaderDelegate : JSContext <JSModuleLoaderDelegate>
 
 + (instancetype)newContext;
@@ -2017,7 +2079,7 @@ static NSURL *resolvePathToScripts()
 - (void)context:(JSContext *)context fetchModuleForIdentifier:(JSValue *)identifier withResolveHandler:(JSValue *)resolve andRejectHandler:(JSValue *)reject
 {
     NSURL *filePath = [NSURL URLWithString:[identifier toString]];
 - (void)context:(JSContext *)context fetchModuleForIdentifier:(JSValue *)identifier withResolveHandler:(JSValue *)resolve andRejectHandler:(JSValue *)reject
 {
     NSURL *filePath = [NSURL URLWithString:[identifier toString]];
-    auto *script = [JSScript scriptFromASCIIFile:filePath inVirtualMachine:[context virtualMachine] withCodeSigning:nil andBytecodeCache:nil];
+    auto *script = [JSScript scriptFromASCIIFile:filePath inVirtualMachine:context.virtualMachine withCodeSigning:nil andBytecodeCache:nil];
     if (script)
         [resolve callWithArguments:@[script]];
     else
     if (script)
         [resolve callWithArguments:@[script]];
     else
@@ -2049,6 +2111,7 @@ void testObjectiveCAPI()
     testFetchWithTwoCycle();
     testFetchWithThreeCycle();
     testImportModuleTwice();
     testFetchWithTwoCycle();
     testFetchWithThreeCycle();
     testImportModuleTwice();
+    testBytecodeCache();
 
     testLoaderRejectsNilScriptURL();
     testLoaderRejectsFailedFetch();
 
     testLoaderRejectsNilScriptURL();
     testLoaderRejectsFailedFetch();
index e901570..82f7578 100644 (file)
@@ -1,3 +1,82 @@
+2019-01-25  Tadeu Zagallo  <tzagallo@apple.com>
+
+        Add API to generate and consume cached bytecode
+        https://bugs.webkit.org/show_bug.cgi?id=193401
+        <rdar://problem/47514099>
+
+        Reviewed by Keith Miller.
+
+        Add the `generateBytecode` and `generateModuleBytecode` functions to
+        generate serialized bytecode for a given `SourceCode`. These functions
+        will eagerly generate code for all the nested functions.
+
+        Additionally, update the API methods in JSScript to generate and use the
+        bytecode when the bytecodeCache path is provided.
+
+        * API/JSAPIGlobalObject.mm:
+        (JSC::JSAPIGlobalObject::moduleLoaderFetch):
+        * API/JSContext.mm:
+        (-[JSContext wrapperMap]):
+        * API/JSContextInternal.h:
+        * API/JSScript.mm:
+        (+[JSScript scriptWithSource:inVirtualMachine:]):
+        (+[JSScript scriptFromASCIIFile:inVirtualMachine:withCodeSigning:andBytecodeCache:]):
+        (-[JSScript dealloc]):
+        (-[JSScript readCache]):
+        (-[JSScript writeCache]):
+        (-[JSScript hash]):
+        (-[JSScript source]):
+        (-[JSScript cachedBytecode]):
+        (-[JSScript jsSourceCode:]):
+        * API/JSScriptInternal.h:
+        * API/JSScriptSourceProvider.h: Copied from Source/JavaScriptCore/API/JSScriptInternal.h.
+        (JSScriptSourceProvider::create):
+        (JSScriptSourceProvider::JSScriptSourceProvider):
+        * API/JSScriptSourceProvider.mm: Copied from Source/JavaScriptCore/API/JSScriptInternal.h.
+        (JSScriptSourceProvider::hash const):
+        (JSScriptSourceProvider::source const):
+        (JSScriptSourceProvider::cachedBytecode const):
+        * API/JSVirtualMachine.mm:
+        (-[JSVirtualMachine vm]):
+        * API/JSVirtualMachineInternal.h:
+        * API/tests/testapi.mm:
+        (testBytecodeCache):
+        (-[JSContextFileLoaderDelegate context:fetchModuleForIdentifier:withResolveHandler:andRejectHandler:]):
+        (testObjectiveCAPI):
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * SourcesCocoa.txt:
+        * bytecode/UnlinkedFunctionExecutable.cpp:
+        (JSC::UnlinkedFunctionExecutable::unlinkedCodeBlockFor):
+        * bytecode/UnlinkedFunctionExecutable.h:
+        * parser/SourceCodeKey.h:
+        (JSC::SourceCodeKey::source const):
+        * parser/SourceProvider.h:
+        (JSC::CachedBytecode::CachedBytecode):
+        (JSC::CachedBytecode::operator=):
+        (JSC::CachedBytecode::data const):
+        (JSC::CachedBytecode::size const):
+        (JSC::CachedBytecode::owned const):
+        (JSC::CachedBytecode::~CachedBytecode):
+        (JSC::CachedBytecode::freeDataIfOwned):
+        (JSC::SourceProvider::cachedBytecode const):
+        * parser/UnlinkedSourceCode.h:
+        (JSC::UnlinkedSourceCode::provider const):
+        * runtime/CodeCache.cpp:
+        (JSC::generateUnlinkedCodeBlockForFunctions):
+        (JSC::writeCodeBlock):
+        (JSC::serializeBytecode):
+        * runtime/CodeCache.h:
+        (JSC::CodeCacheMap::fetchFromDiskImpl):
+        (JSC::CodeCacheMap::findCacheAndUpdateAge):
+        (JSC::generateUnlinkedCodeBlockImpl):
+        (JSC::generateUnlinkedCodeBlock):
+        * runtime/Completion.cpp:
+        (JSC::generateBytecode):
+        (JSC::generateModuleBytecode):
+        * runtime/Completion.h:
+        * runtime/Options.cpp:
+        (JSC::recomputeDependentOptions):
+
 2019-01-25  Keith Rollin  <krollin@apple.com>
 
         Update WebKitAdditions.xcconfig with correct order of variable definitions
 2019-01-25  Keith Rollin  <krollin@apple.com>
 
         Update WebKitAdditions.xcconfig with correct order of variable definitions
index 47a7c73..4eb59ac 100644 (file)
                14C25B9E216EA36A00137764 /* InstructionStream.h in Headers */ = {isa = PBXBuildFile; fileRef = 14CC3BA22138A238002D58B6 /* InstructionStream.h */; settings = {ATTRIBUTES = (Private, ); }; };
                14CA958B16AB50DE00938A06 /* StaticPropertyAnalyzer.h in Headers */ = {isa = PBXBuildFile; fileRef = 14CA958A16AB50DE00938A06 /* StaticPropertyAnalyzer.h */; settings = {ATTRIBUTES = (Private, ); }; };
                14CA958D16AB50FA00938A06 /* ObjectAllocationProfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 14CA958C16AB50FA00938A06 /* ObjectAllocationProfile.h */; settings = {ATTRIBUTES = (Private, ); }; };
                14C25B9E216EA36A00137764 /* InstructionStream.h in Headers */ = {isa = PBXBuildFile; fileRef = 14CC3BA22138A238002D58B6 /* InstructionStream.h */; settings = {ATTRIBUTES = (Private, ); }; };
                14CA958B16AB50DE00938A06 /* StaticPropertyAnalyzer.h in Headers */ = {isa = PBXBuildFile; fileRef = 14CA958A16AB50DE00938A06 /* StaticPropertyAnalyzer.h */; settings = {ATTRIBUTES = (Private, ); }; };
                14CA958D16AB50FA00938A06 /* ObjectAllocationProfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 14CA958C16AB50FA00938A06 /* ObjectAllocationProfile.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               14D01A7721FB351F00BC54E9 /* JSScriptSourceProvider.h in Headers */ = {isa = PBXBuildFile; fileRef = 14D01A7621FB350300BC54E9 /* JSScriptSourceProvider.h */; };
                14D2F3DB139F4BE200491031 /* MarkedSpace.h in Headers */ = {isa = PBXBuildFile; fileRef = 14D2F3D9139F4BE200491031 /* MarkedSpace.h */; settings = {ATTRIBUTES = (Private, ); }; };
                14DF04DA16B3996D0016A513 /* StaticPropertyAnalysis.h in Headers */ = {isa = PBXBuildFile; fileRef = 14DF04D916B3996D0016A513 /* StaticPropertyAnalysis.h */; settings = {ATTRIBUTES = (Private, ); }; };
                14E84F9F14EE1ACC00D6D5D4 /* WeakBlock.h in Headers */ = {isa = PBXBuildFile; fileRef = 14E84F9A14EE1ACC00D6D5D4 /* WeakBlock.h */; settings = {ATTRIBUTES = (Private, ); }; };
                14D2F3DB139F4BE200491031 /* MarkedSpace.h in Headers */ = {isa = PBXBuildFile; fileRef = 14D2F3D9139F4BE200491031 /* MarkedSpace.h */; settings = {ATTRIBUTES = (Private, ); }; };
                14DF04DA16B3996D0016A513 /* StaticPropertyAnalysis.h in Headers */ = {isa = PBXBuildFile; fileRef = 14DF04D916B3996D0016A513 /* StaticPropertyAnalysis.h */; settings = {ATTRIBUTES = (Private, ); }; };
                14E84F9F14EE1ACC00D6D5D4 /* WeakBlock.h in Headers */ = {isa = PBXBuildFile; fileRef = 14E84F9A14EE1ACC00D6D5D4 /* WeakBlock.h */; settings = {ATTRIBUTES = (Private, ); }; };
                14CA958C16AB50FA00938A06 /* ObjectAllocationProfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ObjectAllocationProfile.h; sourceTree = "<group>"; };
                14CC3BA12138A238002D58B6 /* InstructionStream.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InstructionStream.cpp; sourceTree = "<group>"; };
                14CC3BA22138A238002D58B6 /* InstructionStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InstructionStream.h; sourceTree = "<group>"; };
                14CA958C16AB50FA00938A06 /* ObjectAllocationProfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ObjectAllocationProfile.h; sourceTree = "<group>"; };
                14CC3BA12138A238002D58B6 /* InstructionStream.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InstructionStream.cpp; sourceTree = "<group>"; };
                14CC3BA22138A238002D58B6 /* InstructionStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InstructionStream.h; sourceTree = "<group>"; };
+               14D01A7521FB350300BC54E9 /* JSScriptSourceProvider.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = JSScriptSourceProvider.mm; sourceTree = "<group>"; };
+               14D01A7621FB350300BC54E9 /* JSScriptSourceProvider.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JSScriptSourceProvider.h; sourceTree = "<group>"; };
                14D2F3D9139F4BE200491031 /* MarkedSpace.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MarkedSpace.h; sourceTree = "<group>"; };
                14D792640DAA03FB001A9F05 /* CLoopStack.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CLoopStack.h; sourceTree = "<group>"; };
                14D857740A4696C80032146C /* testapi.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = testapi.js; path = API/tests/testapi.js; sourceTree = "<group>"; };
                14D2F3D9139F4BE200491031 /* MarkedSpace.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MarkedSpace.h; sourceTree = "<group>"; };
                14D792640DAA03FB001A9F05 /* CLoopStack.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CLoopStack.h; sourceTree = "<group>"; };
                14D857740A4696C80032146C /* testapi.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = testapi.js; path = API/tests/testapi.js; sourceTree = "<group>"; };
                                53EE01B7218F7EFF00AD1F8D /* JSScriptInternal.h */,
                                A7C0C4AA167C08CD0017011D /* JSScriptRef.cpp */,
                                A7C0C4AB167C08CD0017011D /* JSScriptRefPrivate.h */,
                                53EE01B7218F7EFF00AD1F8D /* JSScriptInternal.h */,
                                A7C0C4AA167C08CD0017011D /* JSScriptRef.cpp */,
                                A7C0C4AB167C08CD0017011D /* JSScriptRefPrivate.h */,
+                               14D01A7621FB350300BC54E9 /* JSScriptSourceProvider.h */,
+                               14D01A7521FB350300BC54E9 /* JSScriptSourceProvider.mm */,
                                1482B74C0A43032800517CFC /* JSStringRef.cpp */,
                                1482B74B0A43032800517CFC /* JSStringRef.h */,
                                146AAB370B66A94400E55F16 /* JSStringRefCF.cpp */,
                                1482B74C0A43032800517CFC /* JSStringRef.cpp */,
                                1482B74B0A43032800517CFC /* JSStringRef.h */,
                                146AAB370B66A94400E55F16 /* JSStringRefCF.cpp */,
                                14F7256614EE265E00B1652B /* WeakHandleOwner.h in Headers */,
                                14E84FA214EE1ACC00D6D5D4 /* WeakImpl.h in Headers */,
                                14BE7D3317135CF400D1807A /* WeakInlines.h in Headers */,
                                14F7256614EE265E00B1652B /* WeakHandleOwner.h in Headers */,
                                14E84FA214EE1ACC00D6D5D4 /* WeakImpl.h in Headers */,
                                14BE7D3317135CF400D1807A /* WeakInlines.h in Headers */,
+                               14D01A7721FB351F00BC54E9 /* JSScriptSourceProvider.h in Headers */,
                                A7CA3AE417DA41AE006538AF /* WeakMapConstructor.h in Headers */,
                                E3A32BC71FC83147007D7E76 /* WeakMapImpl.h in Headers */,
                                E393ADD81FE702D00022D681 /* WeakMapImplInlines.h in Headers */,
                                A7CA3AE417DA41AE006538AF /* WeakMapConstructor.h in Headers */,
                                E3A32BC71FC83147007D7E76 /* WeakMapImpl.h in Headers */,
                                E393ADD81FE702D00022D681 /* WeakMapImplInlines.h in Headers */,
index af6f9ef..760aa0c 100644 (file)
@@ -24,6 +24,7 @@
 API/JSAPIGlobalObject.mm
 API/JSAPIWrapperObject.mm
 API/JSScript.mm
 API/JSAPIGlobalObject.mm
 API/JSAPIWrapperObject.mm
 API/JSScript.mm
+API/JSScriptSourceProvider.mm
 API/JSContext.mm
 API/JSManagedValue.mm
 API/JSRemoteInspector.cpp
 API/JSContext.mm
 API/JSManagedValue.mm
 API/JSRemoteInspector.cpp
index b114d39..e8dc198 100644 (file)
@@ -194,6 +194,16 @@ UnlinkedFunctionExecutable* UnlinkedFunctionExecutable::fromGlobalCode(
     return executable;
 }
 
     return executable;
 }
 
+UnlinkedFunctionCodeBlock* UnlinkedFunctionExecutable::unlinkedCodeBlockFor(CodeSpecializationKind specializationKind)
+{
+    switch (specializationKind) {
+    case CodeForCall:
+        return m_unlinkedCodeBlockForCall.get();
+    case CodeForConstruct:
+        return m_unlinkedCodeBlockForConstruct.get();
+    }
+}
+
 UnlinkedFunctionCodeBlock* UnlinkedFunctionExecutable::unlinkedCodeBlockFor(
     VM& vm, const SourceCode& source, CodeSpecializationKind specializationKind, 
     DebuggerMode debuggerMode, ParserError& error, SourceParseMode parseMode)
 UnlinkedFunctionCodeBlock* UnlinkedFunctionExecutable::unlinkedCodeBlockFor(
     VM& vm, const SourceCode& source, CodeSpecializationKind specializationKind, 
     DebuggerMode debuggerMode, ParserError& error, SourceParseMode parseMode)
index 6526cd9..d637d68 100644 (file)
@@ -104,6 +104,8 @@ public:
     unsigned typeProfilingEndOffset() const { return m_typeProfilingEndOffset; }
     void setInvalidTypeProfilingOffsets();
 
     unsigned typeProfilingEndOffset() const { return m_typeProfilingEndOffset; }
     void setInvalidTypeProfilingOffsets();
 
+    UnlinkedFunctionCodeBlock* unlinkedCodeBlockFor(CodeSpecializationKind);
+
     UnlinkedFunctionCodeBlock* unlinkedCodeBlockFor(
         VM&, const SourceCode&, CodeSpecializationKind, DebuggerMode,
         ParserError&, SourceParseMode);
     UnlinkedFunctionCodeBlock* unlinkedCodeBlockFor(
         VM&, const SourceCode&, CodeSpecializationKind, DebuggerMode,
         ParserError&, SourceParseMode);
index cc3abe2..bc02f12 100644 (file)
@@ -100,6 +100,8 @@ public:
 
     unsigned hash() const { return m_hash; }
 
 
     unsigned hash() const { return m_hash; }
 
+    const UnlinkedSourceCode& source() const { return m_sourceCode; }
+
     size_t length() const { return m_sourceCode.length(); }
 
     bool isNull() const { return m_sourceCode.isNull(); }
     size_t length() const { return m_sourceCode.length(); }
 
     bool isNull() const { return m_sourceCode.isNull(); }
index 09ad168..a5e825b 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright (C) 2008, 2009, 2012, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2008-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
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -42,6 +42,66 @@ namespace JSC {
         WebAssembly,
     };
 
         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)
+        {
+            *this = WTFMove(other);
+        }
+
+        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;
+    };
+
+
     class SourceProvider : public RefCounted<SourceProvider> {
     public:
         static const intptr_t nullID = 1;
     class SourceProvider : public RefCounted<SourceProvider> {
     public:
         static const intptr_t nullID = 1;
@@ -52,6 +112,8 @@ namespace JSC {
 
         virtual unsigned hash() const = 0;
         virtual StringView source() const = 0;
 
         virtual unsigned hash() const = 0;
         virtual StringView source() const = 0;
+        virtual const CachedBytecode* cachedBytecode() const { return nullptr; }
+
         StringView getRange(int start, int end) const
         {
             return source().substring(start, end - start);
         StringView getRange(int start, int end) const
         {
             return source().substring(start, end - start);
@@ -104,16 +166,17 @@ namespace JSC {
             return m_source.get();
         }
 
             return m_source.get();
         }
 
-    private:
+    protected:
         StringSourceProvider(const String& source, const SourceOrigin& sourceOrigin, URL&& url, const TextPosition& startPosition, SourceProviderSourceType sourceType)
             : SourceProvider(sourceOrigin, WTFMove(url), startPosition, sourceType)
             , m_source(source.isNull() ? *StringImpl::empty() : *source.impl())
         {
         }
 
         StringSourceProvider(const String& source, const SourceOrigin& sourceOrigin, URL&& url, const TextPosition& startPosition, SourceProviderSourceType sourceType)
             : SourceProvider(sourceOrigin, WTFMove(url), startPosition, sourceType)
             , m_source(source.isNull() ? *StringImpl::empty() : *source.impl())
         {
         }
 
+    private:
         Ref<StringImpl> m_source;
     };
         Ref<StringImpl> m_source;
     };
-    
+
 #if ENABLE(WEBASSEMBLY)
     class WebAssemblySourceProvider : public SourceProvider {
     public:
 #if ENABLE(WEBASSEMBLY)
     class WebAssemblySourceProvider : public SourceProvider {
     public:
index aaaad3f..fae0e35 100644 (file)
@@ -81,6 +81,11 @@ namespace JSC {
 
         bool isHashTableDeletedValue() const { return m_provider.isHashTableDeletedValue(); }
 
 
         bool isHashTableDeletedValue() const { return m_provider.isHashTableDeletedValue(); }
 
+        const SourceProvider& provider() const
+        {
+            return *m_provider;
+        }
+
         unsigned hash() const
         {
             ASSERT(m_provider);
         unsigned hash() const
         {
             ASSERT(m_provider);
index c32d204..26e0931 100644 (file)
@@ -162,4 +162,65 @@ void CodeCache::write(VM& vm)
         writeCodeBlock(vm, it.key, it.value);
 }
 
         writeCodeBlock(vm, it.key, it.value);
 }
 
+void generateUnlinkedCodeBlockForFunctions(VM& vm, UnlinkedCodeBlock* unlinkedCodeBlock, const SourceCode& parentSource, DebuggerMode debuggerMode, ParserError& error)
+{
+    auto generate = [&](UnlinkedFunctionExecutable* unlinkedExecutable, CodeSpecializationKind constructorKind) {
+        if (constructorKind == CodeForConstruct && SourceParseModeSet(SourceParseMode::AsyncArrowFunctionMode, SourceParseMode::AsyncMethodMode, SourceParseMode::AsyncFunctionMode).contains(unlinkedExecutable->parseMode()))
+            return;
+
+        FunctionExecutable* executable = unlinkedExecutable->link(vm, parentSource);
+        const SourceCode& source = executable->source();
+        UnlinkedFunctionCodeBlock* unlinkedFunctionCodeBlock = unlinkedExecutable->unlinkedCodeBlockFor(vm, source, constructorKind, debuggerMode, error, unlinkedExecutable->parseMode());
+        if (unlinkedFunctionCodeBlock)
+            generateUnlinkedCodeBlockForFunctions(vm, unlinkedFunctionCodeBlock, source, debuggerMode, error);
+    };
+
+    // FIXME: We should also generate CodeBlocks for CodeForConstruct
+    // https://bugs.webkit.org/show_bug.cgi?id=193823
+    for (unsigned i = 0; i < unlinkedCodeBlock->numberOfFunctionDecls(); i++)
+        generate(unlinkedCodeBlock->functionDecl(i), CodeForCall);
+    for (unsigned i = 0; i < unlinkedCodeBlock->numberOfFunctionExprs(); i++)
+        generate(unlinkedCodeBlock->functionExpr(i), CodeForCall);
+}
+
+void writeCodeBlock(VM& vm, const SourceCodeKey& key, const SourceCodeValue& value)
+{
+#if OS(DARWIN)
+    const char* cachePath = Options::diskCachePath();
+    if (LIKELY(!cachePath))
+        return;
+
+    UnlinkedCodeBlock* codeBlock = jsDynamicCast<UnlinkedCodeBlock*>(vm, value.cell.get());
+    if (!codeBlock)
+        return;
+
+    std::pair<MallocPtr<uint8_t>, size_t> result = encodeCodeBlock(vm, key, codeBlock);
+
+    String filename = makeString(cachePath, '/', String::number(key.hash()), ".cache");
+    int fd = open(filename.utf8().data(), O_CREAT | O_WRONLY, 0666);
+    if (fd == -1)
+        return;
+    int rc = flock(fd, LOCK_EX | LOCK_NB);
+    if (!rc)
+        ::write(fd, result.first.get(), result.second);
+    close(fd);
+#else
+    UNUSED_PARAM(vm);
+    UNUSED_PARAM(key);
+    UNUSED_PARAM(value);
+#endif
+}
+
+CachedBytecode serializeBytecode(VM& vm, UnlinkedCodeBlock* codeBlock, const SourceCode& source, SourceCodeType codeType, JSParserStrictMode strictMode, JSParserScriptMode scriptMode, DebuggerMode debuggerMode)
+{
+    SourceCodeKey key(
+        source, 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);
+    return CachedBytecode { WTFMove(result.first), result.second };
+}
+
 }
 }
index 99395f2..80c0d95 100644 (file)
@@ -36,6 +36,7 @@
 #include "StrongInlines.h"
 #include "UnlinkedCodeBlock.h"
 #include "UnlinkedEvalCodeBlock.h"
 #include "StrongInlines.h"
 #include "UnlinkedCodeBlock.h"
 #include "UnlinkedEvalCodeBlock.h"
+#include "UnlinkedFunctionCodeBlock.h"
 #include "UnlinkedModuleProgramCodeBlock.h"
 #include "UnlinkedProgramCodeBlock.h"
 #include <sys/stat.h>
 #include "UnlinkedModuleProgramCodeBlock.h"
 #include "UnlinkedProgramCodeBlock.h"
 #include <sys/stat.h>
@@ -60,6 +61,15 @@ class UnlinkedProgramCodeBlock;
 class VM;
 class VariableEnvironment;
 
 class VM;
 class VariableEnvironment;
 
+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()
     {
 struct SourceCodeValue {
     SourceCodeValue()
     {
@@ -97,6 +107,16 @@ public:
     template<typename UnlinkedCodeBlockType>
     UnlinkedCodeBlockType* fetchFromDiskImpl(VM& vm, const SourceCodeKey& key)
     {
     template<typename UnlinkedCodeBlockType>
     UnlinkedCodeBlockType* fetchFromDiskImpl(VM& vm, const SourceCodeKey& key)
     {
+        {
+            const auto* 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;
+            }
+        }
+
 #if OS(DARWIN)
         const char* cachePath = Options::diskCachePath();
         if (!cachePath)
 #if OS(DARWIN)
         const char* cachePath = Options::diskCachePath();
         if (!cachePath)
@@ -121,15 +141,19 @@ public:
         struct stat sb;
         int res = fstat(fd, &sb);
         size_t size = static_cast<size_t>(sb.st_size);
         struct stat sb;
         int res = fstat(fd, &sb);
         size_t size = static_cast<size_t>(sb.st_size);
-        if (res || !size)
+        if (res || !size) {
+            close(fd);
             return nullptr;
             return nullptr;
+        }
 
 
-        const void* buffer = mmap(nullptr, size, PROT_READ, MAP_PRIVATE, fd, 0);
+        void* buffer = mmap(nullptr, size, PROT_READ, MAP_PRIVATE, fd, 0);
         UnlinkedCodeBlockType* unlinkedCodeBlock = decodeCodeBlock<UnlinkedCodeBlockType>(vm, key, buffer, size);
         UnlinkedCodeBlockType* unlinkedCodeBlock = decodeCodeBlock<UnlinkedCodeBlockType>(vm, key, buffer, size);
+        munmap(buffer, size);
 
         if (!unlinkedCodeBlock)
             return nullptr;
 
 
         if (!unlinkedCodeBlock)
             return nullptr;
 
+        VERBOSE_LOG("Found cached CodeBlock on disk");
         addCache(key, SourceCodeValue(vm, unlinkedCodeBlock, m_age));
         return unlinkedCodeBlock;
 #else
         addCache(key, SourceCodeValue(vm, unlinkedCodeBlock, m_age));
         return unlinkedCodeBlock;
 #else
@@ -158,6 +182,7 @@ public:
     {
         prune();
 
     {
         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);
         iterator findResult = m_map.find(key);
         if (findResult == m_map.end())
             return fetchFromDisk<UnlinkedCodeBlockType>(vm, key);
@@ -180,6 +205,7 @@ public:
         findResult->value.age = m_age;
         m_age += key.length();
 
         findResult->value.age = m_age;
         m_age += key.length();
 
+        VERBOSE_LOG("Found cached CodeBlock in memory");
         return jsCast<UnlinkedCodeBlockType*>(findResult->value.cell.get());
     }
 
         return jsCast<UnlinkedCodeBlockType*>(findResult->value.cell.get());
     }
 
@@ -291,11 +317,10 @@ template <> struct CacheTypes<UnlinkedModuleProgramCodeBlock> {
     static const SourceParseMode parseMode = SourceParseMode::ModuleEvaluateMode;
 };
 
     static const SourceParseMode parseMode = SourceParseMode::ModuleEvaluateMode;
 };
 
-template <class UnlinkedCodeBlockType, class ExecutableType>
-UnlinkedCodeBlockType* generateUnlinkedCodeBlock(VM& vm, ExecutableType* executable, const SourceCode& source, JSParserStrictMode strictMode, JSParserScriptMode scriptMode, DebuggerMode debuggerMode, ParserError& error, EvalContextType evalContextType, const VariableEnvironment* variablesUnderTDZ)
+template <class UnlinkedCodeBlockType, class ExecutableType = ScriptExecutable>
+UnlinkedCodeBlockType* generateUnlinkedCodeBlockImpl(VM& vm, const SourceCode& source, JSParserStrictMode strictMode, JSParserScriptMode scriptMode, DebuggerMode debuggerMode, ParserError& error, EvalContextType evalContextType, DerivedContextType derivedContextType, bool isArrowFunctionContext, const VariableEnvironment* variablesUnderTDZ, ExecutableType* executable = nullptr)
 {
     typedef typename CacheTypes<UnlinkedCodeBlockType>::RootNode RootNode;
 {
     typedef typename CacheTypes<UnlinkedCodeBlockType>::RootNode RootNode;
-    DerivedContextType derivedContextType = executable->derivedContextType();
     std::unique_ptr<RootNode> rootNode = parse<RootNode>(
         &vm, source, Identifier(), JSParserBuiltinMode::NotBuiltin, strictMode, scriptMode, CacheTypes<UnlinkedCodeBlockType>::parseMode, SuperBinding::NotNeeded, error, nullptr, ConstructorKind::None, derivedContextType, evalContextType);
     if (!rootNode)
     std::unique_ptr<RootNode> rootNode = parse<RootNode>(
         &vm, source, Identifier(), JSParserBuiltinMode::NotBuiltin, strictMode, scriptMode, CacheTypes<UnlinkedCodeBlockType>::parseMode, SuperBinding::NotNeeded, error, nullptr, ConstructorKind::None, derivedContextType, evalContextType);
     if (!rootNode)
@@ -306,10 +331,15 @@ UnlinkedCodeBlockType* generateUnlinkedCodeBlock(VM& vm, ExecutableType* executa
     bool endColumnIsOnStartLine = !lineCount;
     unsigned unlinkedEndColumn = rootNode->endColumn();
     unsigned endColumn = unlinkedEndColumn + (endColumnIsOnStartLine ? startColumn : 1);
     bool endColumnIsOnStartLine = !lineCount;
     unsigned unlinkedEndColumn = rootNode->endColumn();
     unsigned endColumn = unlinkedEndColumn + (endColumnIsOnStartLine ? startColumn : 1);
-    unsigned arrowContextFeature = executable->isArrowFunctionContext() ? ArrowFunctionContextFeature : 0;
-    executable->recordParse(rootNode->features() | arrowContextFeature, rootNode->hasCapturedVariables(), rootNode->lastLine(), endColumn);
+    unsigned arrowContextFeature = isArrowFunctionContext ? ArrowFunctionContextFeature : 0;
+    if (executable)
+        executable->recordParse(rootNode->features() | arrowContextFeature, rootNode->hasCapturedVariables(), rootNode->lastLine(), endColumn);
+
+    bool usesEval = rootNode->features() & EvalFeature;
+    bool isStrictMode = rootNode->features() & StrictModeFeature;
+    ExecutableInfo executableInfo(usesEval, isStrictMode, false, false, ConstructorKind::None, scriptMode, SuperBinding::NotNeeded, CacheTypes<UnlinkedCodeBlockType>::parseMode, derivedContextType, isArrowFunctionContext, false, evalContextType);
 
 
-    UnlinkedCodeBlockType* unlinkedCodeBlock = UnlinkedCodeBlockType::create(&vm, executable->executableInfo(), debuggerMode);
+    UnlinkedCodeBlockType* unlinkedCodeBlock = UnlinkedCodeBlockType::create(&vm, executableInfo, debuggerMode);
     unlinkedCodeBlock->recordParse(rootNode->features(), rootNode->hasCapturedVariables(), lineCount, unlinkedEndColumn);
     unlinkedCodeBlock->setSourceURLDirective(source.provider()->sourceURL());
     unlinkedCodeBlock->setSourceMappingURLDirective(source.provider()->sourceMappingURL());
     unlinkedCodeBlock->recordParse(rootNode->features(), rootNode->hasCapturedVariables(), lineCount, unlinkedEndColumn);
     unlinkedCodeBlock->setSourceURLDirective(source.provider()->sourceURL());
     unlinkedCodeBlock->setSourceMappingURLDirective(source.provider()->sourceMappingURL());
@@ -322,36 +352,28 @@ UnlinkedCodeBlockType* generateUnlinkedCodeBlock(VM& vm, ExecutableType* executa
     return unlinkedCodeBlock;
 }
 
     return unlinkedCodeBlock;
 }
 
-ALWAYS_INLINE static void writeCodeBlock(VM& vm, const SourceCodeKey& key, const SourceCodeValue& value)
+template <class UnlinkedCodeBlockType, class ExecutableType>
+UnlinkedCodeBlockType* generateUnlinkedCodeBlock(VM& vm, ExecutableType* executable, const SourceCode& source, JSParserStrictMode strictMode, JSParserScriptMode scriptMode, DebuggerMode debuggerMode, ParserError& error, EvalContextType evalContextType, const VariableEnvironment* variablesUnderTDZ)
 {
 {
-#if OS(DARWIN)
-    const char* cachePath = Options::diskCachePath();
-    if (LIKELY(!cachePath))
-        return;
-
-    UnlinkedCodeBlock* codeBlock = jsDynamicCast<UnlinkedCodeBlock*>(vm, value.cell.get());
-    if (!codeBlock)
-        return;
-
-    unsigned hash = key.hash();
-    char filename[512];
-    int count = snprintf(filename, 512, "%s/%u.cache", cachePath, hash);
-    if (count < 0 || count > 512)
-        return;
-
-    std::pair<MallocPtr<uint8_t>, size_t> result = encodeCodeBlock(vm, key, codeBlock);
-
-    int fd = open(filename, O_CREAT | O_WRONLY, 0666);
-    int rc = flock(fd, LOCK_EX | LOCK_NB);
-    if (!rc)
-        ::write(fd, result.first.get(), result.second);
-    close(fd);
-#else
-    UNUSED_PARAM(vm);
-    UNUSED_PARAM(key);
-    UNUSED_PARAM(value);
-#endif
+    return generateUnlinkedCodeBlockImpl<UnlinkedCodeBlockType, ExecutableType>(vm, source, strictMode, scriptMode, debuggerMode, error, evalContextType, executable->derivedContextType(), executable->isArrowFunctionContext(), variablesUnderTDZ, executable);
+}
+
+void generateUnlinkedCodeBlockForFunctions(VM&, UnlinkedCodeBlock*, const SourceCode&, DebuggerMode, ParserError&);
+
+template <class UnlinkedCodeBlockType>
+std::enable_if_t<!std::is_same<UnlinkedCodeBlockType, UnlinkedEvalCodeBlock>::value, UnlinkedCodeBlockType*>
+recursivelyGenerateUnlinkedCodeBlock(VM& vm, const SourceCode& source, JSParserStrictMode strictMode, JSParserScriptMode scriptMode, DebuggerMode debuggerMode, ParserError& error, EvalContextType evalContextType, const VariableEnvironment* variablesUnderTDZ)
+{
+    bool isArrowFunctionContext = false;
+    UnlinkedCodeBlockType* unlinkedCodeBlock = generateUnlinkedCodeBlockImpl<UnlinkedCodeBlockType>(vm, source, strictMode, scriptMode, debuggerMode, error, evalContextType, DerivedContextType::None, isArrowFunctionContext, variablesUnderTDZ);
+    if (!unlinkedCodeBlock)
+        return nullptr;
+
+    generateUnlinkedCodeBlockForFunctions(vm, unlinkedCodeBlock, source, debuggerMode, error);
+    return unlinkedCodeBlock;
 }
 
 }
 
+void writeCodeBlock(VM&, const SourceCodeKey&, const SourceCodeValue&);
+CachedBytecode serializeBytecode(VM&, UnlinkedCodeBlock*, const SourceCode&, SourceCodeType, JSParserStrictMode, JSParserScriptMode, DebuggerMode);
 
 } // namespace JSC
 
 } // namespace JSC
index 3fb4ab9..8a875cd 100644 (file)
@@ -25,6 +25,7 @@
 
 #include "CallFrame.h"
 #include "CatchScope.h"
 
 #include "CallFrame.h"
 #include "CatchScope.h"
+#include "CodeCache.h"
 #include "CodeProfiling.h"
 #include "Exception.h"
 #include "IdentifierInlines.h"
 #include "CodeProfiling.h"
 #include "Exception.h"
 #include "IdentifierInlines.h"
@@ -90,6 +91,36 @@ bool checkModuleSyntax(ExecState* exec, const SourceCode& source, ParserError& e
     return true;
 }
 
     return true;
 }
 
+CachedBytecode generateBytecode(VM& vm, const SourceCode& source, ParserError& error)
+{
+    JSLockHolder lock(vm);
+    RELEASE_ASSERT(vm.atomicStringTable() == Thread::current().atomicStringTable());
+
+    VariableEnvironment variablesUnderTDZ;
+    JSParserStrictMode strictMode = JSParserStrictMode::NotStrict;
+    JSParserScriptMode scriptMode = JSParserScriptMode::Classic;
+    DebuggerMode debuggerMode = DebuggerOff;
+    EvalContextType evalContextType = EvalContextType::None;
+
+    UnlinkedCodeBlock* unlinkedCodeBlock = recursivelyGenerateUnlinkedCodeBlock<UnlinkedProgramCodeBlock>(vm, source, strictMode, scriptMode, debuggerMode, error, evalContextType, &variablesUnderTDZ);
+    return serializeBytecode(vm, unlinkedCodeBlock, source, SourceCodeType::ProgramType, strictMode, scriptMode, debuggerMode);
+}
+
+CachedBytecode generateModuleBytecode(VM& vm, const SourceCode& source, ParserError& error)
+{
+    JSLockHolder lock(vm);
+    RELEASE_ASSERT(vm.atomicStringTable() == Thread::current().atomicStringTable());
+
+    VariableEnvironment variablesUnderTDZ;
+    JSParserStrictMode strictMode = JSParserStrictMode::Strict;
+    JSParserScriptMode scriptMode = JSParserScriptMode::Module;
+    DebuggerMode debuggerMode = DebuggerOff;
+    EvalContextType evalContextType = EvalContextType::None;
+
+    UnlinkedCodeBlock* unlinkedCodeBlock = recursivelyGenerateUnlinkedCodeBlock<UnlinkedModuleProgramCodeBlock>(vm, source, strictMode, scriptMode, debuggerMode, error, evalContextType, &variablesUnderTDZ);
+    return serializeBytecode(vm, unlinkedCodeBlock, source, SourceCodeType::ModuleType, strictMode, scriptMode, debuggerMode);
+}
+
 JSValue evaluate(ExecState* exec, const SourceCode& source, JSValue thisValue, NakedPtr<Exception>& returnedException)
 {
     VM& vm = exec->vm();
 JSValue evaluate(ExecState* exec, const SourceCode& source, JSValue thisValue, NakedPtr<Exception>& returnedException)
 {
     VM& vm = exec->vm();
index 827e61f..3072889 100644 (file)
@@ -28,6 +28,7 @@
 
 namespace JSC {
 
 
 namespace JSC {
 
+class CachedBytecode;
 class Exception;
 class ExecState;
 class JSObject;
 class Exception;
 class ExecState;
 class JSObject;
@@ -41,6 +42,9 @@ 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 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 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())
 {
 JS_EXPORT_PRIVATE JSValue evaluate(ExecState*, const SourceCode&, JSValue thisValue, NakedPtr<Exception>& returnedException);
 inline JSValue evaluate(ExecState* exec, const SourceCode& sourceCode, JSValue thisValue = JSValue())
 {
index 8b05ca8..84d7326 100644 (file)
@@ -527,9 +527,6 @@ static void recomputeDependentOptions()
 
     if (!Options::useCodeCache())
         Options::diskCachePath() = nullptr;
 
     if (!Options::useCodeCache())
         Options::diskCachePath() = nullptr;
-
-    if (!Options::diskCachePath())
-        Options::forceDiskCache() = false;
 }
 
 void Options::initialize()
 }
 
 void Options::initialize()