Diff
Modified: trunk/Source/_javascript_Core/API/JSAPIGlobalObject.mm (240510 => 240511)
--- trunk/Source/_javascript_Core/API/JSAPIGlobalObject.mm 2019-01-25 22:23:54 UTC (rev 240510)
+++ trunk/Source/_javascript_Core/API/JSAPIGlobalObject.mm 2019-01-25 22:31:12 UTC (rev 240511)
@@ -164,7 +164,6 @@
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 @@
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();
});
Modified: trunk/Source/_javascript_Core/API/JSContext.mm (240510 => 240511)
--- trunk/Source/_javascript_Core/API/JSContext.mm 2019-01-25 22:23:54 UTC (rev 240510)
+++ trunk/Source/_javascript_Core/API/JSContext.mm 2019-01-25 22:31:12 UTC (rev 240511)
@@ -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 @@
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 @@
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));
Modified: trunk/Source/_javascript_Core/API/JSContextInternal.h (240510 => 240511)
--- trunk/Source/_javascript_Core/API/JSContextInternal.h 2019-01-25 22:23:54 UTC (rev 240510)
+++ trunk/Source/_javascript_Core/API/JSContextInternal.h 2019-01-25 22:31:12 UTC (rev 240511)
@@ -51,6 +51,7 @@
- (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;
Modified: trunk/Source/_javascript_Core/API/JSScript.mm (240510 => 240511)
--- trunk/Source/_javascript_Core/API/JSScript.mm 2019-01-25 22:23:54 UTC (rev 240510)
+++ trunk/Source/_javascript_Core/API/JSScript.mm 2019-01-25 22:31:12 UTC (rev 240511)
@@ -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 @@
{
// 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 @@
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,9 +116,97 @@
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
+
+
#endif
Modified: trunk/Source/_javascript_Core/API/JSScriptInternal.h (240510 => 240511)
--- trunk/Source/_javascript_Core/API/JSScriptInternal.h 2019-01-25 22:23:54 UTC (rev 240510)
+++ trunk/Source/_javascript_Core/API/JSScriptInternal.h 2019-01-25 22:31:12 UTC (rev 240511)
@@ -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
Copied: trunk/Source/_javascript_Core/API/JSScriptSourceProvider.h (from rev 240510, trunk/Source/_javascript_Core/API/JSScriptInternal.h) (0 => 240511)
--- trunk/Source/_javascript_Core/API/JSScriptSourceProvider.h (rev 0)
+++ trunk/Source/_javascript_Core/API/JSScriptSourceProvider.h 2019-01-25 22:31:12 UTC (rev 240511)
@@ -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
Copied: trunk/Source/_javascript_Core/API/JSScriptSourceProvider.mm (from rev 240510, trunk/Source/_javascript_Core/API/JSScriptInternal.h) (0 => 240511)
--- trunk/Source/_javascript_Core/API/JSScriptSourceProvider.mm (rev 0)
+++ trunk/Source/_javascript_Core/API/JSScriptSourceProvider.mm 2019-01-25 22:31:12 UTC (rev 240511)
@@ -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
Modified: trunk/Source/_javascript_Core/API/JSVirtualMachine.mm (240510 => 240511)
--- trunk/Source/_javascript_Core/API/JSVirtualMachine.mm 2019-01-25 22:23:54 UTC (rev 240510)
+++ trunk/Source/_javascript_Core/API/JSVirtualMachine.mm 2019-01-25 22:31:12 UTC (rev 240511)
@@ -297,6 +297,11 @@
#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)
Modified: trunk/Source/_javascript_Core/API/JSVirtualMachineInternal.h (240510 => 240511)
--- trunk/Source/_javascript_Core/API/JSVirtualMachineInternal.h 2019-01-25 22:23:54 UTC (rev 240510)
+++ trunk/Source/_javascript_Core/API/JSVirtualMachineInternal.h 2019-01-25 22:31:12 UTC (rev 240511)
@@ -46,6 +46,8 @@
- (JSContext *)contextForGlobalContextRef:(JSGlobalContextRef)globalContext;
- (void)addContext:(JSContext *)wrapper forGlobalContextRef:(JSGlobalContextRef)globalContext;
+- (JSC::VM&)vm;
+
@end
#endif // defined(__OBJC__)
Modified: trunk/Source/_javascript_Core/API/tests/testapi.mm (240510 => 240511)
--- trunk/Source/_javascript_Core/API/tests/testapi.mm 2019-01-25 22:23:54 UTC (rev 240510)
+++ trunk/Source/_javascript_Core/API/tests/testapi.mm 2019-01-25 22:31:12 UTC (rev 240511)
@@ -1980,6 +1980,68 @@
}
}
+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 @@
- (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 @@
testFetchWithTwoCycle();
testFetchWithThreeCycle();
testImportModuleTwice();
+ testBytecodeCache();
testLoaderRejectsNilScriptURL();
testLoaderRejectsFailedFetch();
Modified: trunk/Source/_javascript_Core/ChangeLog (240510 => 240511)
--- trunk/Source/_javascript_Core/ChangeLog 2019-01-25 22:23:54 UTC (rev 240510)
+++ trunk/Source/_javascript_Core/ChangeLog 2019-01-25 22:31:12 UTC (rev 240511)
@@ -1,3 +1,82 @@
+2019-01-25 Tadeu Zagallo <[email protected]>
+
+ 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/_javascript_Core/API/JSScriptInternal.h.
+ (JSScriptSourceProvider::create):
+ (JSScriptSourceProvider::JSScriptSourceProvider):
+ * API/JSScriptSourceProvider.mm: Copied from Source/_javascript_Core/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):
+ * _javascript_Core.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 <[email protected]>
Update WebKitAdditions.xcconfig with correct order of variable definitions
Modified: trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj (240510 => 240511)
--- trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj 2019-01-25 22:23:54 UTC (rev 240510)
+++ trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj 2019-01-25 22:31:12 UTC (rev 240511)
@@ -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 */,
Modified: trunk/Source/_javascript_Core/SourcesCocoa.txt (240510 => 240511)
--- trunk/Source/_javascript_Core/SourcesCocoa.txt 2019-01-25 22:23:54 UTC (rev 240510)
+++ trunk/Source/_javascript_Core/SourcesCocoa.txt 2019-01-25 22:31:12 UTC (rev 240511)
@@ -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
Modified: trunk/Source/_javascript_Core/bytecode/UnlinkedFunctionExecutable.cpp (240510 => 240511)
--- trunk/Source/_javascript_Core/bytecode/UnlinkedFunctionExecutable.cpp 2019-01-25 22:23:54 UTC (rev 240510)
+++ trunk/Source/_javascript_Core/bytecode/UnlinkedFunctionExecutable.cpp 2019-01-25 22:31:12 UTC (rev 240511)
@@ -194,6 +194,16 @@
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)
Modified: trunk/Source/_javascript_Core/bytecode/UnlinkedFunctionExecutable.h (240510 => 240511)
--- trunk/Source/_javascript_Core/bytecode/UnlinkedFunctionExecutable.h 2019-01-25 22:23:54 UTC (rev 240510)
+++ trunk/Source/_javascript_Core/bytecode/UnlinkedFunctionExecutable.h 2019-01-25 22:31:12 UTC (rev 240511)
@@ -104,6 +104,8 @@
unsigned typeProfilingEndOffset() const { return m_typeProfilingEndOffset; }
void setInvalidTypeProfilingOffsets();
+ UnlinkedFunctionCodeBlock* unlinkedCodeBlockFor(CodeSpecializationKind);
+
UnlinkedFunctionCodeBlock* unlinkedCodeBlockFor(
VM&, const SourceCode&, CodeSpecializationKind, DebuggerMode,
ParserError&, SourceParseMode);
Modified: trunk/Source/_javascript_Core/parser/SourceCodeKey.h (240510 => 240511)
--- trunk/Source/_javascript_Core/parser/SourceCodeKey.h 2019-01-25 22:23:54 UTC (rev 240510)
+++ trunk/Source/_javascript_Core/parser/SourceCodeKey.h 2019-01-25 22:31:12 UTC (rev 240511)
@@ -100,6 +100,8 @@
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(); }
Modified: trunk/Source/_javascript_Core/parser/SourceProvider.h (240510 => 240511)
--- trunk/Source/_javascript_Core/parser/SourceProvider.h 2019-01-25 22:23:54 UTC (rev 240510)
+++ trunk/Source/_javascript_Core/parser/SourceProvider.h 2019-01-25 22:31:12 UTC (rev 240511)
@@ -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 @@
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 @@
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,7 +166,7 @@
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())
@@ -111,9 +173,10 @@
{
}
+ private:
Ref<StringImpl> m_source;
};
-
+
#if ENABLE(WEBASSEMBLY)
class WebAssemblySourceProvider : public SourceProvider {
public:
Modified: trunk/Source/_javascript_Core/parser/UnlinkedSourceCode.h (240510 => 240511)
--- trunk/Source/_javascript_Core/parser/UnlinkedSourceCode.h 2019-01-25 22:23:54 UTC (rev 240510)
+++ trunk/Source/_javascript_Core/parser/UnlinkedSourceCode.h 2019-01-25 22:31:12 UTC (rev 240511)
@@ -81,6 +81,11 @@
bool isHashTableDeletedValue() const { return m_provider.isHashTableDeletedValue(); }
+ const SourceProvider& provider() const
+ {
+ return *m_provider;
+ }
+
unsigned hash() const
{
ASSERT(m_provider);
Modified: trunk/Source/_javascript_Core/runtime/CodeCache.cpp (240510 => 240511)
--- trunk/Source/_javascript_Core/runtime/CodeCache.cpp 2019-01-25 22:23:54 UTC (rev 240510)
+++ trunk/Source/_javascript_Core/runtime/CodeCache.cpp 2019-01-25 22:31:12 UTC (rev 240511)
@@ -162,4 +162,65 @@
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 };
+}
+
+}
Modified: trunk/Source/_javascript_Core/runtime/CodeCache.h (240510 => 240511)
--- trunk/Source/_javascript_Core/runtime/CodeCache.h 2019-01-25 22:23:54 UTC (rev 240510)
+++ trunk/Source/_javascript_Core/runtime/CodeCache.h 2019-01-25 22:31:12 UTC (rev 240511)
@@ -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 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 @@
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 @@
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 @@
{
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 @@
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 @@
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 @@
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);
- UnlinkedCodeBlockType* unlinkedCodeBlock = UnlinkedCodeBlockType::create(&vm, executable->executableInfo(), debuggerMode);
+ 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, executableInfo, debuggerMode);
unlinkedCodeBlock->recordParse(rootNode->features(), rootNode->hasCapturedVariables(), lineCount, unlinkedEndColumn);
unlinkedCodeBlock->setSourceURLDirective(source.provider()->sourceURL());
unlinkedCodeBlock->setSourceMappingURLDirective(source.provider()->sourceMappingURL());
@@ -322,36 +352,28 @@
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;
+ return generateUnlinkedCodeBlockImpl<UnlinkedCodeBlockType, ExecutableType>(vm, source, strictMode, scriptMode, debuggerMode, error, evalContextType, executable->derivedContextType(), executable->isArrowFunctionContext(), variablesUnderTDZ, executable);
+}
- UnlinkedCodeBlock* codeBlock = jsDynamicCast<UnlinkedCodeBlock*>(vm, value.cell.get());
- if (!codeBlock)
- return;
+void generateUnlinkedCodeBlockForFunctions(VM&, UnlinkedCodeBlock*, const SourceCode&, DebuggerMode, ParserError&);
- unsigned hash = key.hash();
- char filename[512];
- int count = snprintf(filename, 512, "%s/%u.cache", cachePath, hash);
- if (count < 0 || count > 512)
- return;
+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;
- 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
+ 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
Modified: trunk/Source/_javascript_Core/runtime/Completion.cpp (240510 => 240511)
--- trunk/Source/_javascript_Core/runtime/Completion.cpp 2019-01-25 22:23:54 UTC (rev 240510)
+++ trunk/Source/_javascript_Core/runtime/Completion.cpp 2019-01-25 22:31:12 UTC (rev 240511)
@@ -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 @@
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();
Modified: trunk/Source/_javascript_Core/runtime/Completion.h (240510 => 240511)
--- trunk/Source/_javascript_Core/runtime/Completion.h 2019-01-25 22:23:54 UTC (rev 240510)
+++ trunk/Source/_javascript_Core/runtime/Completion.h 2019-01-25 22:31:12 UTC (rev 240511)
@@ -28,6 +28,7 @@
namespace JSC {
+class CachedBytecode;
class Exception;
class ExecState;
class JSObject;
@@ -41,6 +42,9 @@
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())
{
Modified: trunk/Source/_javascript_Core/runtime/Options.cpp (240510 => 240511)
--- trunk/Source/_javascript_Core/runtime/Options.cpp 2019-01-25 22:23:54 UTC (rev 240510)
+++ trunk/Source/_javascript_Core/runtime/Options.cpp 2019-01-25 22:31:12 UTC (rev 240511)
@@ -527,9 +527,6 @@
if (!Options::useCodeCache())
Options::diskCachePath() = nullptr;
-
- if (!Options::diskCachePath())
- Options::forceDiskCache() = false;
}
void Options::initialize()