WebKit Bugzilla
Attachment 359899 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]
WIP patch
bug-193401-20190123190304.patch (text/plain), 34.96 KB, created by
Tadeu Zagallo
on 2019-01-23 10:03:19 PST
(
hide
)
Description:
WIP patch
Filename:
MIME Type:
Creator:
Tadeu Zagallo
Created:
2019-01-23 10:03:19 PST
Size:
34.96 KB
patch
obsolete
>Subversion Revision: 240343 >diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog >index a514c8fddd34f5ca4a729fd42814a627e14109a3..f263cdce055ae8176cbb6e3ffb0658906ec539f9 100644 >--- a/Source/JavaScriptCore/ChangeLog >+++ b/Source/JavaScriptCore/ChangeLog >@@ -1,3 +1,34 @@ >+2019-01-14 Tadeu Zagallo <tzagallo@apple.com> >+ >+ Add entry point to eagerly generate bytecode for a given SourceCode >+ https://bugs.webkit.org/show_bug.cgi?id=193401 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Add a new `generateBytecode` function that eagerly generates bytecode >+ for a given source file and all its functions. Currently, this function >+ relies on Options::diskCachePath() to write the bytecode to disk. >+ >+ This function is not being used for running the bytecode-cache tests yet, >+ because we can't guarantee that all the necessary code has been cached >+ since some tests `load` and `import` other files. >+ >+ * jsc.cpp: >+ (runWithOptions): >+ (printUsageStatement): >+ (CommandLine::parseArguments): >+ * runtime/CodeCache.cpp: >+ (JSC::CodeCacheMap::pruneSlowCase): >+ (JSC::CodeCache::write): >+ (JSC::generateUnlinkedCodeBlockForFunctions): >+ (JSC::writeCodeBlock): >+ (JSC::writeGlobalCodeBlockToDisk): >+ * runtime/CodeCache.h: >+ (JSC::recursivelyGenerateUnlinkedCodeBlock): >+ * runtime/Completion.cpp: >+ (JSC::generateBytecode): >+ * runtime/Completion.h: >+ > 2019-01-23 David Kilzer <ddkilzer@apple.com> > > [JSC] Duplicate global variables: JSC::opcodeLengths >diff --git a/Source/JavaScriptCore/API/JSAPIGlobalObject.mm b/Source/JavaScriptCore/API/JSAPIGlobalObject.mm >index 3ca4ab9251f71a55ed2484ac1176c3906e992cc5..8f775fafba03687d29f16267359b036d308e2f6d 100644 >--- a/Source/JavaScriptCore/API/JSAPIGlobalObject.mm >+++ b/Source/JavaScriptCore/API/JSAPIGlobalObject.mm >@@ -36,7 +36,7 @@ > #import "JSContextInternal.h" > #import "JSInternalPromiseDeferred.h" > #import "JSNativeStdFunction.h" >-#import "JSScriptInternal.h" >+#import "JSScript.h" > #import "JSSourceCode.h" > #import "JSValueInternal.h" > #import "JSVirtualMachineInternal.h" >@@ -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..723b1bbdb6884265a626b6cada9acfb27b9f0b4f 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" >diff --git a/Source/JavaScriptCore/API/JSScript.h b/Source/JavaScriptCore/API/JSScript.h >index 8ded7ca770efc1b871db04f245db5531c617d4e1..754687224d140db01f695027aec74bbe4b59a9e8 100644 >--- a/Source/JavaScriptCore/API/JSScript.h >+++ b/Source/JavaScriptCore/API/JSScript.h >@@ -25,6 +25,11 @@ > > #import <JavaScriptCore/JSValue.h> > >+namespace JSC { >+class JSSourceCode; >+class Identifier; >+}; >+ > #if JSC_OBJC_API_ENABLED > > NS_ASSUME_NONNULL_BEGIN >@@ -63,6 +68,8 @@ JSC_CLASS_AVAILABLE(macosx(JSC_MAC_TBA), ios(JSC_IOS_TBA)) > */ > + (nullable instancetype)scriptFromUTF8File:(NSURL *)filePath inVirtualMachine:(JSVirtualMachine *)vm withCodeSigning:(nullable NSURL *)codeSigningPath andBytecodeCache:(nullable NSURL *)cachePath; > >+- (JSC::JSSourceCode*)jsSourceCode:(JSC::Identifier)moduleKey; >+ > @end > > NS_ASSUME_NONNULL_END >diff --git a/Source/JavaScriptCore/API/JSScript.mm b/Source/JavaScriptCore/API/JSScript.mm >index f7e939af098bf5d0f53ed1e8b32d75a4d823fd7f..412604db4ca5fe4798e9b5a6c597c78eba2001b0 100644 >--- a/Source/JavaScriptCore/API/JSScript.mm >+++ b/Source/JavaScriptCore/API/JSScript.mm >@@ -24,24 +24,33 @@ > */ > > #import "config.h" >-#import "JSScriptInternal.h" >+#import "JSScript.h" > > #import "APICast.h" >+#import "Identifier.h" > #import "JSContextInternal.h" >+#import "JSSourceCode.h" > #import "JSValuePrivate.h" >+#import "JSVirtualMachineInternal.h" > #import "Symbol.h" >+#include <sys/stat.h> > > #if JSC_OBJC_API_ENABLED > > @implementation JSScript { >+ __unsafe_unretained JSVirtualMachine* m_virtualMachine; > String m_source; >+ NSURL* m_cachePath; >+ JSC::CachedBytecode m_cachedBytecode; >+ HashMap<UniquedStringImpl*, JSC::Strong<JSC::JSSourceCode>> m_jsSourceCodeMap; > } > > + (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 +90,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 +101,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 +114,74 @@ + (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()) >+ munmap(const_cast<void*>(m_cachedBytecode.data()), m_cachedBytecode.size()); >+ [self writeCache]; >+ [super dealloc]; >+} >+ >+- (void)readCache >+{ >+ if (!m_cachePath) >+ return; >+ >+ int fd = open(m_cachePath.absoluteString.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 >+{ >+ JSC::VM& vm = m_virtualMachine.vm; >+ dataLogLn("vm.entryScope: ", RawPointer(vm.entryScope)); >+ if (!m_cachePath || m_cachedBytecode.size()) >+ return; >+ //ParserError error; >+ //CachedBytecode cachedBytecode = generateModuleBytecode(exec, m_source, error); >+ //int fd = open(m_cachePath.absoluteString.UTF8String, O_CREAT | O_WRONLY, 0666); >+ //if (fd == -1) >+ //return; >+ //int rc = flock(fd, LOCK_EX | LOCK_NB); >+ //if (!rc) >+ //write(fd, cachedBytecode.data(), cachedBytecode.size()); >+ //close(fd); >+} >+ >+- (JSC::JSSourceCode*)jsSourceCode:(JSC::Identifier)moduleKey >+{ >+ auto it = m_jsSourceCodeMap.find(moduleKey.impl()); >+ if (it != m_jsSourceCodeMap.end()) >+ return it->value.get(); >+ >+ JSC::VM& vm = m_virtualMachine.vm; >+ TextPosition startPosition {}; >+ Ref<JSC::CachedBytecodeSourceProvider> sourceProvider = JSC::CachedBytecodeSourceProvider::create(m_source, &m_cachedBytecode, 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_jsSourceCodeMap.set(moduleKey.impl(), JSC::Strong<JSC::JSSourceCode> { m_virtualMachine.vm, jsSourceCode }); >+ return jsSourceCode; >+} > > @end > >diff --git a/Source/JavaScriptCore/API/JSScriptInternal.h b/Source/JavaScriptCore/API/JSScriptInternal.h >deleted file mode 100644 >index a973ed1ad4a1fc5fdf35cf9482301795ae1f2eb3..0000000000000000000000000000000000000000 >--- a/Source/JavaScriptCore/API/JSScriptInternal.h >+++ /dev/null >@@ -1,33 +0,0 @@ >-/* >- * Copyright (C) 2019 Apple Inc. All rights reserved. >- * >- * Redistribution and use in source and binary forms, with or without >- * modification, are permitted provided that the following conditions >- * are met: >- * 1. Redistributions of source code must retain the above copyright >- * notice, this list of conditions and the following disclaimer. >- * 2. Redistributions in binary form must reproduce the above copyright >- * notice, this list of conditions and the following disclaimer in the >- * documentation and/or other materials provided with the distribution. >- * >- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY >- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE >- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR >- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, >- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, >- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR >- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY >- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT >- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE >- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. >- */ >- >-#pragma once >- >-#import "JSScript.h" >-#import "SourceCode.h" >- >-OBJC_CLASS JSScript; >- >-const String& getJSScriptSourceCode(JSScript *); >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..85f06245336dc557daa9546d9ad3678e177719e5 100644 >--- a/Source/JavaScriptCore/API/tests/testapi.mm >+++ b/Source/JavaScriptCore/API/tests/testapi.mm >@@ -1980,6 +1980,43 @@ 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]; >+ auto *context = [JSContextFetchDelegate contextWithBlockForFetch:^(JSContext *context, JSValue *identifier, JSValue *resolve, JSValue *reject) { >+ 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]]]; >+ }]; >+ 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); >+ } >+} >+ > @interface JSContextFileLoaderDelegate : JSContext <JSModuleLoaderDelegate> > > + (instancetype)newContext; >@@ -2049,6 +2086,7 @@ void testObjectiveCAPI() > testFetchWithTwoCycle(); > testFetchWithThreeCycle(); > testImportModuleTwice(); >+ testBytecodeCache(); > > testLoaderRejectsNilScriptURL(); > testLoaderRejectsFailedFetch(); >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..7dbccee7616150b75052e92e179f815b750990ba 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,43 @@ namespace JSC { > WebAssembly, > }; > >+ class 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()) >+ { >+ } >+ >+ const void* data() const { return m_data; } >+ size_t size() const { return m_size; } >+ >+ ~CachedBytecode() >+ { >+ if (m_data && m_owned) >+ fastFree(const_cast<void*>(m_data)); >+ } >+ >+ private: >+ 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 +89,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,15 +143,38 @@ 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; > }; >+ >+ class CachedBytecodeSourceProvider : public StringSourceProvider { >+ public: >+ static Ref<CachedBytecodeSourceProvider> create(const String& source, const CachedBytecode* cachedBytecode, const SourceOrigin& sourceOrigin, URL&& url, const TextPosition& startPosition = TextPosition(), SourceProviderSourceType sourceType = SourceProviderSourceType::Program) >+ { >+ return adoptRef(*new CachedBytecodeSourceProvider(source, cachedBytecode, sourceOrigin, WTFMove(url), startPosition, sourceType)); >+ } >+ >+ const CachedBytecode* cachedBytecode() const override >+ { >+ return m_cachedBytecode; >+ } >+ >+ private: >+ CachedBytecodeSourceProvider(const String& source, const CachedBytecode* cachedBytecode, const SourceOrigin& sourceOrigin, URL&& url, const TextPosition& startPosition, SourceProviderSourceType sourceType) >+ : StringSourceProvider(source, sourceOrigin, WTFMove(url), startPosition, sourceType) >+ , m_cachedBytecode(cachedBytecode) >+ { >+ } >+ >+ const CachedBytecode* m_cachedBytecode; >+ }; > > #if ENABLE(WEBASSEMBLY) > class WebAssemblySourceProvider : public SourceProvider { >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..895a840b9156ceb90397052ca0cd7116d3389156 100644 >--- a/Source/JavaScriptCore/runtime/CodeCache.cpp >+++ b/Source/JavaScriptCore/runtime/CodeCache.cpp >@@ -162,4 +162,72 @@ 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); >+ }; >+ >+ for (unsigned i = 0; i < unlinkedCodeBlock->numberOfFunctionDecls(); i++) { >+ generate(unlinkedCodeBlock->functionDecl(i), CodeForCall); >+ generate(unlinkedCodeBlock->functionDecl(i), CodeForConstruct); >+ } >+ for (unsigned i = 0; i < unlinkedCodeBlock->numberOfFunctionExprs(); i++) { >+ generate(unlinkedCodeBlock->functionExpr(i), CodeForCall); >+ generate(unlinkedCodeBlock->functionExpr(i), CodeForConstruct); >+ } >+} >+ >+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; >+ >+ 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); >+ 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..f459c0271756fdcddba90ccb34eedecf3c8eafd6 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,19 @@ class UnlinkedProgramCodeBlock; > class VM; > class VariableEnvironment; > >+namespace CodeCacheInternal { >+#ifdef NDEBUG >+static const bool verbose = false; >+#else >+static const bool verbose = true; >+#endif >+} // namespace CodeCacheInternal >+ >+#define VERBOSE_LOG(...) do { \ >+ if (CodeCacheInternal::verbose) \ >+ dataLogLn("(JSC::CodeCache) ", __VA_ARGS__); \ >+} while (false) >+ > struct SourceCodeValue { > SourceCodeValue() > { >@@ -97,6 +111,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 +145,20 @@ 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 +187,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 +210,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()); > } > >@@ -322,36 +353,20 @@ UnlinkedCodeBlockType* generateUnlinkedCodeBlock(VM& vm, ExecutableType* executa > return unlinkedCodeBlock; > } > >-ALWAYS_INLINE static void writeCodeBlock(VM& vm, const SourceCodeKey& key, const SourceCodeValue& value) >+void generateUnlinkedCodeBlockForFunctions(VM&, UnlinkedCodeBlock*, const SourceCode&, DebuggerMode, ParserError&); >+ >+template <class UnlinkedCodeBlockType, class ExecutableType> >+UnlinkedCodeBlockType* recursivelyGenerateUnlinkedCodeBlock(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 >+ UnlinkedCodeBlockType* unlinkedCodeBlock = generateUnlinkedCodeBlock<UnlinkedCodeBlockType, ExecutableType>(vm, executable, source, strictMode, scriptMode, debuggerMode, error, evalContextType, 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..9c4a0e4fc8f07d41aa301d2770368ecf835c81fe 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,44 @@ bool checkModuleSyntax(ExecState* exec, const SourceCode& source, ParserError& e > return true; > } > >+CachedBytecode generateBytecode(ExecState* exec, const SourceCode& source, ParserError& error) >+{ >+ VM& vm = exec->vm(); >+ JSLockHolder lock(vm); >+ RELEASE_ASSERT(vm.atomicStringTable() == Thread::current().atomicStringTable()); >+ >+ ProgramExecutable* executable = ProgramExecutable::create(exec, source); >+ JSGlobalObject* globalObject = vm.vmEntryGlobalObject(exec); >+ >+ VariableEnvironment variablesUnderTDZ; >+ JSParserStrictMode strictMode = JSParserStrictMode::NotStrict; >+ JSParserScriptMode scriptMode = JSParserScriptMode::Classic; >+ DebuggerMode debuggerMode = globalObject->hasInteractiveDebugger() ? DebuggerOn : DebuggerOff; >+ EvalContextType evalContextType = EvalContextType::None; >+ >+ UnlinkedCodeBlock* unlinkedCodeBlock = recursivelyGenerateUnlinkedCodeBlock<UnlinkedProgramCodeBlock>(vm, executable, source, strictMode, scriptMode, debuggerMode, error, evalContextType, &variablesUnderTDZ); >+ return serializeBytecode(vm, unlinkedCodeBlock, source, SourceCodeType::ProgramType, strictMode, scriptMode, debuggerMode); >+} >+ >+CachedBytecode generateModuleBytecode(ExecState* exec, const SourceCode& source, ParserError& error) >+{ >+ VM& vm = exec->vm(); >+ JSLockHolder lock(vm); >+ RELEASE_ASSERT(vm.atomicStringTable() == Thread::current().atomicStringTable()); >+ >+ ModuleProgramExecutable* executable = ModuleProgramExecutable::create(exec, source); >+ JSGlobalObject* globalObject = vm.vmEntryGlobalObject(exec); >+ >+ VariableEnvironment variablesUnderTDZ; >+ JSParserStrictMode strictMode = JSParserStrictMode::Strict; >+ JSParserScriptMode scriptMode = JSParserScriptMode::Module; >+ DebuggerMode debuggerMode = globalObject->hasInteractiveDebugger() ? DebuggerOn : DebuggerOff; >+ EvalContextType evalContextType = EvalContextType::None; >+ >+ UnlinkedCodeBlock* unlinkedCodeBlock = recursivelyGenerateUnlinkedCodeBlock<UnlinkedModuleProgramCodeBlock>(vm, executable, 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..5cacd6da7eb752033b5c4806bd8e84986ad0a700 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(ExecState*, const SourceCode&, ParserError&); >+JS_EXPORT_PRIVATE CachedBytecode generateModuleBytecode(ExecState*, 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()) > {
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