WebKit Bugzilla
Attachment 360158 Details for
Bug 193401
: Add API to generate and consume cached bytecode
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch for landing
bug-193401-20190125224920.patch (text/plain), 50.72 KB, created by
Tadeu Zagallo
on 2019-01-25 13:49:37 PST
(
hide
)
Description:
Patch for landing
Filename:
MIME Type:
Creator:
Tadeu Zagallo
Created:
2019-01-25 13:49:37 PST
Size:
50.72 KB
patch
obsolete
>Subversion Revision: 240499 >diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog >index fee924841fd1e866945470d51083438bc6c4e5c7..6631c3b1469f4f2811bf6ac23419066117b1338c 100644 >--- a/Source/JavaScriptCore/ChangeLog >+++ b/Source/JavaScriptCore/ChangeLog >@@ -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 Jon Davis <jond@apple.com> > > Update JavaScriptCore feature status entries. >diff --git a/Source/JavaScriptCore/API/JSAPIGlobalObject.mm b/Source/JavaScriptCore/API/JSAPIGlobalObject.mm >index 3ca4ab9251f71a55ed2484ac1176c3906e992cc5..d5c2365d0847148c80f8992bc044352f31bcbf0e 100644 >--- a/Source/JavaScriptCore/API/JSAPIGlobalObject.mm >+++ b/Source/JavaScriptCore/API/JSAPIGlobalObject.mm >@@ -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) { >- 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))); >@@ -176,8 +175,7 @@ JSInternalPromise* JSAPIGlobalObject::moduleLoaderFetch(JSGlobalObject* globalOb > 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(); > }); >diff --git a/Source/JavaScriptCore/API/JSContext.mm b/Source/JavaScriptCore/API/JSContext.mm >index 3c776d4d900ee1733362ac29f624f444d545e7b4..518fb872398483412ffa1fbddcfd9ffae168aff0 100644 >--- a/Source/JavaScriptCore/API/JSContext.mm >+++ b/Source/JavaScriptCore/API/JSContext.mm >@@ -34,7 +34,6 @@ > #import "JSGlobalObject.h" > #import "JSInternalPromise.h" > #import "JSModuleLoader.h" >-#import "JSScriptInternal.h" > #import "JSValueInternal.h" > #import "JSVirtualMachineInternal.h" > #import "JSWrapperMap.h" >@@ -135,11 +134,6 @@ - (JSValue *)exception > 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]; >@@ -332,6 +326,11 @@ - (JSValue *)wrapperForObjCObject:(id)object > 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)); >diff --git a/Source/JavaScriptCore/API/JSContextInternal.h b/Source/JavaScriptCore/API/JSContextInternal.h >index ab45829f0027e4fad6bfbd1afc402b3a1be85b58..958c479f41ce8413fc694ac123d794eb3d7f4d4d 100644 >--- a/Source/JavaScriptCore/API/JSContextInternal.h >+++ b/Source/JavaScriptCore/API/JSContextInternal.h >@@ -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; > >+- (JSWrapperMap *)wrapperMap; > - (JSValue *)wrapperForObjCObject:(id)object; > - (JSValue *)wrapperForJSObject:(JSValueRef)value; > >diff --git a/Source/JavaScriptCore/API/JSScript.mm b/Source/JavaScriptCore/API/JSScript.mm >index f7e939af098bf5d0f53ed1e8b32d75a4d823fd7f..fef446dedf86b2450aa7f83f2ba3ee70a8852fe0 100644 >--- a/Source/JavaScriptCore/API/JSScript.mm >+++ b/Source/JavaScriptCore/API/JSScript.mm >@@ -27,21 +27,32 @@ > #import "JSScriptInternal.h" > > #import "APICast.h" >+#import "Identifier.h" > #import "JSContextInternal.h" >+#import "JSScriptSourceProvider.h" >+#import "JSSourceCode.h" > #import "JSValuePrivate.h" >+#import "JSVirtualMachineInternal.h" >+#import "ParserError.h" > #import "Symbol.h" >+#include <sys/stat.h> > > #if JSC_OBJC_API_ENABLED > > @implementation JSScript { >+ __weak JSVirtualMachine* m_virtualMachine; > 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 > { >- UNUSED_PARAM(vm); >- JSScript *result = [[JSScript alloc] init]; >+ JSScript *result = [[[JSScript alloc] init] autorelease]; > result->m_source = source; >+ result->m_virtualMachine = vm; > return result; > } > >@@ -81,9 +92,6 @@ + (instancetype)scriptFromASCIIFile:(NSURL *)filePath inVirtualMachine:(JSVirtua > { > // 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; >@@ -95,8 +103,11 @@ + (instancetype)scriptFromASCIIFile:(NSURL *)filePath inVirtualMachine:(JSVirtua > 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_cachePath = cachePath; >+ [result readCache]; > return result; > } > >@@ -105,7 +116,95 @@ + (instancetype)scriptFromUTF8File:(NSURL *)filePath inVirtualMachine:(JSVirtual > 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 > >diff --git a/Source/JavaScriptCore/API/JSScriptInternal.h b/Source/JavaScriptCore/API/JSScriptInternal.h >index a973ed1ad4a1fc5fdf35cf9482301795ae1f2eb3..66a75e26e52a76bd2d088981fca0b8c1c9455402 100644 >--- a/Source/JavaScriptCore/API/JSScriptInternal.h >+++ b/Source/JavaScriptCore/API/JSScriptInternal.h >@@ -28,6 +28,29 @@ > #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 >index 0000000000000000000000000000000000000000..3e8431de6f295829e28fc58aa75596ab5e78779b >--- /dev/null >+++ b/Source/JavaScriptCore/API/JSScriptSourceProvider.h >@@ -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 >index 0000000000000000000000000000000000000000..5536a8b93a97dbef4bda7e90c078982710854e4a >--- /dev/null >+++ b/Source/JavaScriptCore/API/JSScriptSourceProvider.mm >@@ -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 >diff --git a/Source/JavaScriptCore/API/JSVirtualMachine.mm b/Source/JavaScriptCore/API/JSVirtualMachine.mm >index 5e795f016f05a381bdcf1040f335d0895395deaa..504d33cf5f7cb53f16dd37793fc61c915e23bfe6 100644 >--- a/Source/JavaScriptCore/API/JSVirtualMachine.mm >+++ b/Source/JavaScriptCore/API/JSVirtualMachine.mm >@@ -297,6 +297,11 @@ + (NSUInteger)setNumberOfFTLCompilerThreads:(NSUInteger)numberOfThreads > > #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) >diff --git a/Source/JavaScriptCore/API/JSVirtualMachineInternal.h b/Source/JavaScriptCore/API/JSVirtualMachineInternal.h >index 9122ed49a4ea1aa49ec667fef6627fc43b77716d..9b0bf6beeb07add09c63e8b14034a88ce83d6ed7 100644 >--- a/Source/JavaScriptCore/API/JSVirtualMachineInternal.h >+++ b/Source/JavaScriptCore/API/JSVirtualMachineInternal.h >@@ -46,6 +46,8 @@ JSContextGroupRef getGroupFromVirtualMachine(JSVirtualMachine *); > > - (JSContext *)contextForGlobalContextRef:(JSGlobalContextRef)globalContext; > - (void)addContext:(JSContext *)wrapper forGlobalContextRef:(JSGlobalContextRef)globalContext; >+- (JSC::VM&)vm; >+ > @end > > #endif // defined(__OBJC__) >diff --git a/Source/JavaScriptCore/API/tests/testapi.mm b/Source/JavaScriptCore/API/tests/testapi.mm >index 13beb69f2bcd72194c70af568f9612d61ef6acc3..2289e6e3489ae2f6cdcebf56562a3113d696855b 100644 >--- a/Source/JavaScriptCore/API/tests/testapi.mm >+++ b/Source/JavaScriptCore/API/tests/testapi.mm >@@ -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; >@@ -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]]; >- 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 >@@ -2049,6 +2111,7 @@ void testObjectiveCAPI() > testFetchWithTwoCycle(); > testFetchWithThreeCycle(); > testImportModuleTwice(); >+ testBytecodeCache(); > > testLoaderRejectsNilScriptURL(); > testLoaderRejectsFailedFetch(); >diff --git a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj >index 47a7c73c0b1aa85554bced34339d58f93979f5ab..4eb59ac560a6878be4f52c4437614df6f12d13f2 100644 >--- a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj >+++ b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj >@@ -814,6 +814,7 @@ > 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, ); }; }; >@@ -3238,6 +3239,8 @@ > 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>"; }; >@@ -5993,6 +5996,8 @@ > 53EE01B7218F7EFF00AD1F8D /* JSScriptInternal.h */, > A7C0C4AA167C08CD0017011D /* JSScriptRef.cpp */, > A7C0C4AB167C08CD0017011D /* JSScriptRefPrivate.h */, >+ 14D01A7621FB350300BC54E9 /* JSScriptSourceProvider.h */, >+ 14D01A7521FB350300BC54E9 /* JSScriptSourceProvider.mm */, > 1482B74C0A43032800517CFC /* JSStringRef.cpp */, > 1482B74B0A43032800517CFC /* JSStringRef.h */, > 146AAB370B66A94400E55F16 /* JSStringRefCF.cpp */, >@@ -9775,6 +9780,7 @@ > 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 */, >diff --git a/Source/JavaScriptCore/SourcesCocoa.txt b/Source/JavaScriptCore/SourcesCocoa.txt >index af6f9ef5fc33e01f1def673f12679b1d77776b4d..760aa0c425bdeac118ed0c5e5a6c79838cc1fe98 100644 >--- a/Source/JavaScriptCore/SourcesCocoa.txt >+++ b/Source/JavaScriptCore/SourcesCocoa.txt >@@ -24,6 +24,7 @@ > API/JSAPIGlobalObject.mm > API/JSAPIWrapperObject.mm > API/JSScript.mm >+API/JSScriptSourceProvider.mm > API/JSContext.mm > API/JSManagedValue.mm > API/JSRemoteInspector.cpp >diff --git a/Source/JavaScriptCore/bytecode/UnlinkedFunctionExecutable.cpp b/Source/JavaScriptCore/bytecode/UnlinkedFunctionExecutable.cpp >index b114d39e90226a510b2458521d95c63f75033eeb..e8dc1981f0e63c2601609d240b9a379719caa589 100644 >--- a/Source/JavaScriptCore/bytecode/UnlinkedFunctionExecutable.cpp >+++ b/Source/JavaScriptCore/bytecode/UnlinkedFunctionExecutable.cpp >@@ -194,6 +194,16 @@ UnlinkedFunctionExecutable* UnlinkedFunctionExecutable::fromGlobalCode( > 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) >diff --git a/Source/JavaScriptCore/bytecode/UnlinkedFunctionExecutable.h b/Source/JavaScriptCore/bytecode/UnlinkedFunctionExecutable.h >index 6526cd90cbbaa69e26cc0a1c0ac77b68c195fb56..d637d68af5ad631558ea93b3b86b9da04cb83175 100644 >--- a/Source/JavaScriptCore/bytecode/UnlinkedFunctionExecutable.h >+++ b/Source/JavaScriptCore/bytecode/UnlinkedFunctionExecutable.h >@@ -104,6 +104,8 @@ public: > unsigned typeProfilingEndOffset() const { return m_typeProfilingEndOffset; } > void setInvalidTypeProfilingOffsets(); > >+ UnlinkedFunctionCodeBlock* unlinkedCodeBlockFor(CodeSpecializationKind); >+ > UnlinkedFunctionCodeBlock* unlinkedCodeBlockFor( > VM&, const SourceCode&, CodeSpecializationKind, DebuggerMode, > ParserError&, SourceParseMode); >diff --git a/Source/JavaScriptCore/parser/SourceCodeKey.h b/Source/JavaScriptCore/parser/SourceCodeKey.h >index cc3abe21faf5714bf99801dfb9eed4283481f189..bc02f129abf185be7558fbd6354d593f86c8bb70 100644 >--- a/Source/JavaScriptCore/parser/SourceCodeKey.h >+++ b/Source/JavaScriptCore/parser/SourceCodeKey.h >@@ -100,6 +100,8 @@ public: > > 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(); } >diff --git a/Source/JavaScriptCore/parser/SourceProvider.h b/Source/JavaScriptCore/parser/SourceProvider.h >index 09ad16834b0afb7be9f314afc2f250ad82edb5e5..a5e825b7727115429f0a74d2e5190b2addb3f59e 100644 >--- a/Source/JavaScriptCore/parser/SourceProvider.h >+++ b/Source/JavaScriptCore/parser/SourceProvider.h >@@ -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 >@@ -42,6 +42,66 @@ namespace JSC { > 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; >@@ -52,6 +112,8 @@ namespace JSC { > > 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); >@@ -104,16 +166,17 @@ namespace JSC { > 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()) > { > } > >+ private: > Ref<StringImpl> m_source; > }; >- >+ > #if ENABLE(WEBASSEMBLY) > class WebAssemblySourceProvider : public SourceProvider { > public: >diff --git a/Source/JavaScriptCore/parser/UnlinkedSourceCode.h b/Source/JavaScriptCore/parser/UnlinkedSourceCode.h >index aaaad3f412f8f3fa5bc1f2febfb14cc74de22424..fae0e351eabe50fb8a4c539289f35b862d17db77 100644 >--- a/Source/JavaScriptCore/parser/UnlinkedSourceCode.h >+++ b/Source/JavaScriptCore/parser/UnlinkedSourceCode.h >@@ -81,6 +81,11 @@ namespace JSC { > > bool isHashTableDeletedValue() const { return m_provider.isHashTableDeletedValue(); } > >+ const SourceProvider& provider() const >+ { >+ return *m_provider; >+ } >+ > unsigned hash() const > { > ASSERT(m_provider); >diff --git a/Source/JavaScriptCore/runtime/CodeCache.cpp b/Source/JavaScriptCore/runtime/CodeCache.cpp >index c32d204b6cd8968181cb0d1df0eab83ec11819d4..26e0931d4689d2d9cb401a1c73d16638ae0d9d58 100644 >--- a/Source/JavaScriptCore/runtime/CodeCache.cpp >+++ b/Source/JavaScriptCore/runtime/CodeCache.cpp >@@ -162,4 +162,65 @@ void CodeCache::write(VM& vm) > 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 }; >+} >+ > } >diff --git a/Source/JavaScriptCore/runtime/CodeCache.h b/Source/JavaScriptCore/runtime/CodeCache.h >index 99395f2cd2841139a035c8b1589bb939c69c5702..80c0d95f9ef794952e5fbc683ee56650e0a021af 100644 >--- a/Source/JavaScriptCore/runtime/CodeCache.h >+++ b/Source/JavaScriptCore/runtime/CodeCache.h >@@ -36,6 +36,7 @@ > #include "StrongInlines.h" > #include "UnlinkedCodeBlock.h" > #include "UnlinkedEvalCodeBlock.h" >+#include "UnlinkedFunctionCodeBlock.h" > #include "UnlinkedModuleProgramCodeBlock.h" > #include "UnlinkedProgramCodeBlock.h" > #include <sys/stat.h> >@@ -60,6 +61,15 @@ class UnlinkedProgramCodeBlock; > 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() > { >@@ -97,6 +107,16 @@ public: > 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) >@@ -121,15 +141,19 @@ public: > 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; >+ } > >- 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); >+ munmap(buffer, size); > > if (!unlinkedCodeBlock) > return nullptr; > >+ VERBOSE_LOG("Found cached CodeBlock on disk"); > addCache(key, SourceCodeValue(vm, unlinkedCodeBlock, m_age)); > return unlinkedCodeBlock; > #else >@@ -158,6 +182,7 @@ 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); >@@ -180,6 +205,7 @@ public: > findResult->value.age = m_age; > m_age += key.length(); > >+ VERBOSE_LOG("Found cached CodeBlock in memory"); > return jsCast<UnlinkedCodeBlockType*>(findResult->value.cell.get()); > } > >@@ -291,11 +317,10 @@ template <> struct CacheTypes<UnlinkedModuleProgramCodeBlock> { > 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; >- 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) >@@ -306,10 +331,15 @@ UnlinkedCodeBlockType* generateUnlinkedCodeBlock(VM& vm, ExecutableType* executa > 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()); >@@ -322,36 +352,28 @@ UnlinkedCodeBlockType* generateUnlinkedCodeBlock(VM& vm, ExecutableType* executa > 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 >diff --git a/Source/JavaScriptCore/runtime/Completion.cpp b/Source/JavaScriptCore/runtime/Completion.cpp >index 3fb4ab9d3aa2e34bbcd9adffa7307e7076a461af..8a875cd7e3b05dc43659f01b70052bc13cc1ae19 100644 >--- a/Source/JavaScriptCore/runtime/Completion.cpp >+++ b/Source/JavaScriptCore/runtime/Completion.cpp >@@ -25,6 +25,7 @@ > > #include "CallFrame.h" > #include "CatchScope.h" >+#include "CodeCache.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; > } > >+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(); >diff --git a/Source/JavaScriptCore/runtime/Completion.h b/Source/JavaScriptCore/runtime/Completion.h >index 827e61f3c61d0cb7bbe75a61277124fb0da72aae..3072889bb4caa36b55d43f1c66a632d64138196c 100644 >--- a/Source/JavaScriptCore/runtime/Completion.h >+++ b/Source/JavaScriptCore/runtime/Completion.h >@@ -28,6 +28,7 @@ > > namespace JSC { > >+class CachedBytecode; > 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 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()) > { >diff --git a/Source/JavaScriptCore/runtime/Options.cpp b/Source/JavaScriptCore/runtime/Options.cpp >index 8b05ca82300bc79a229ac60f86bb45667eefda5e..84d7326a24fbe5a5de03c5c38dbf2bdedf2360cb 100644 >--- a/Source/JavaScriptCore/runtime/Options.cpp >+++ b/Source/JavaScriptCore/runtime/Options.cpp >@@ -527,9 +527,6 @@ static void recomputeDependentOptions() > > if (!Options::useCodeCache()) > Options::diskCachePath() = nullptr; >- >- if (!Options::diskCachePath()) >- Options::forceDiskCache() = false; > } > > void Options::initialize()
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 193401
:
359045
|
359899
|
359954
|
360008
|
360040
|
360114
| 360158