WebKit Bugzilla
Attachment 361924 Details for
Bug 194517
: Update JSScript SPI based on feedback
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
WIP
bug-194517-20190213103733.patch (text/plain), 39.18 KB, created by
Keith Miller
on 2019-02-13 10:37:34 PST
(
hide
)
Description:
WIP
Filename:
MIME Type:
Creator:
Keith Miller
Created:
2019-02-13 10:37:34 PST
Size:
39.18 KB
patch
obsolete
>Subversion Revision: 240795 >diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog >index 9596453cd3469bcdaf7c94b39dce5e554229a58c..12edaae3e04a4eeab73fb91b853910a536ae7d60 100644 >--- a/Source/JavaScriptCore/ChangeLog >+++ b/Source/JavaScriptCore/ChangeLog >@@ -1,3 +1,51 @@ >+2019-02-11 Keith Miller <keith_miller@apple.com> >+ >+ Update JSScript SPI from feedback >+ https://bugs.webkit.org/show_bug.cgi?id=194517 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ This changes the SPI for creating scripts to work with non-script >+ file. There are two main new methods for creating scripts one that >+ takes an NSString as source and another that takes a path to a >+ file which it memory maps in as the source. There is also a new >+ method for explicitly caching bytecode for a script. Lastly, there >+ is now a method on JSContext that will run a JSScript based on >+ whether or not the script is a module or program executable. >+ >+ * API/JSAPIGlobalObject.h: >+ * API/JSAPIGlobalObject.mm: >+ (JSC::JSAPIGlobalObject::moduleLoaderFetch): >+ (JSC::JSAPIGlobalObject::loadAndEvaluateJSScriptModule): >+ * API/JSContext.mm: >+ (evaluateScript): >+ (-[JSContext evaluateScript:withSourceURL:]): >+ (-[JSContext evaluateJSScript:]): >+ (-[JSContext cacheBytecodeForJSScript:recursivelyCacheModuleDependencies:]): >+ (-[JSContext valueFromNotifyExceptionWithString:]): >+ * API/JSContextPrivate.h: >+ * API/JSScript.h: >+ * API/JSScript.mm: >+ (+[JSScript scriptOfType:withSource:withURL:inVirtualMachine:andBytecodeCache:error:]): >+ (+[JSScript scriptOfType:memoryMappedFromASCIIFile:withURL:inVirtualMachine:andBytecodeCache:error:]): >+ (-[JSScript url]): >+ (-[JSScript readCache]): >+ (-[JSScript jsSourceCode:]): >+ (-[JSScript writeCache:]): >+ (-[JSScript writeCache]): Deleted. >+ * API/JSScriptInternal.h: >+ * API/tests/testapi.c: >+ (main): >+ * API/tests/testapi.mm: >+ (testBytecodeCache): >+ (testLoadBasicFileLegacySPI): >+ (+[JSContextMemoryMappedLoaderDelegate newContext]): >+ (-[JSContextMemoryMappedLoaderDelegate context:fetchModuleForIdentifier:withResolveHandler:andRejectHandler:]): >+ (testLoadBasicFile): >+ (testJSScriptURL): >+ (testObjectiveCAPI): >+ * config.h: >+ > 2019-01-31 Fujii Hironori <Hironori.Fujii@sony.com> > > [CMake][JSC] Changing ud_opcode.py should trigger invoking ud_opcode.py >diff --git a/Source/JavaScriptCore/API/JSAPIGlobalObject.h b/Source/JavaScriptCore/API/JSAPIGlobalObject.h >index 5d5f12c7ebf289942e678607f37bab9ce6c3dd68..4487371049ff9c316dab38d08e17070ac7c93edc 100644 >--- a/Source/JavaScriptCore/API/JSAPIGlobalObject.h >+++ b/Source/JavaScriptCore/API/JSAPIGlobalObject.h >@@ -27,6 +27,9 @@ > > #include "JSGlobalObject.h" > >+OBJC_CLASS JSScript; >+OBJC_CLASS NSURL; >+ > namespace JSC { > > class JSAPIGlobalObject : public JSGlobalObject { >@@ -55,6 +58,8 @@ public: > static JSInternalPromise* moduleLoaderFetch(JSGlobalObject*, ExecState*, JSModuleLoader*, JSValue, JSValue, JSValue); > static JSObject* moduleLoaderCreateImportMetaProperties(JSGlobalObject*, ExecState*, JSModuleLoader*, JSValue, JSModuleRecord*, JSValue); > >+ JSValue loadAndEvaluateJSScriptModule(JSScript *script, NSURL *url); >+ > private: > JSAPIGlobalObject(VM& vm, Structure* structure) > : Base(vm, structure, &s_globalObjectMethodTable) >diff --git a/Source/JavaScriptCore/API/JSAPIGlobalObject.mm b/Source/JavaScriptCore/API/JSAPIGlobalObject.mm >index d5c2365d0847148c80f8992bc044352f31bcbf0e..50c492072d365c18bd14de1c9d6854e4659f7fa7 100644 >--- a/Source/JavaScriptCore/API/JSAPIGlobalObject.mm >+++ b/Source/JavaScriptCore/API/JSAPIGlobalObject.mm >@@ -34,8 +34,10 @@ > #import "Error.h" > #import "Exception.h" > #import "JSContextInternal.h" >+#import "JSInternalPromise.h" > #import "JSInternalPromiseDeferred.h" > #import "JSNativeStdFunction.h" >+#import "JSPromiseDeferred.h" > #import "JSScriptInternal.h" > #import "JSSourceCode.h" > #import "JSValueInternal.h" >@@ -162,9 +164,9 @@ JSInternalPromise* JSAPIGlobalObject::moduleLoaderFetch(JSGlobalObject* globalOb > return deferred->reject(exec, createError(exec, "No module loader provided.")); > > 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) { > // This captures the globalObject but that's ok because our structure keeps it alive anyway. >+ VM& vm = exec->vm(); > JSContext *context = [JSContext contextWithJSGlobalContextRef:toGlobalRef(globalObject->globalExec())]; > id script = valueToObject(context, toRef(exec, exec->argument(0))); > >@@ -175,7 +177,15 @@ JSInternalPromise* JSAPIGlobalObject::moduleLoaderFetch(JSGlobalObject* globalOb > return encodedJSUndefined(); > } > >- args.append([static_cast<JSScript *>(script) jsSourceCode:moduleKey]); >+ JSSourceCode* source = [static_cast<JSScript *>(script) jsSourceCode:moduleKey]; >+ const String& oldModuleKey = source->sourceCode().provider()->sourceOrigin().string(); >+ if (UNLIKELY(Identifier::fromString(&vm, oldModuleKey) != moduleKey)) { >+ args.append(createTypeError(exec, makeString("The same JSScript was provided for two different identifiers, previously: ", oldModuleKey, " and now: ", moduleKey.string()))); >+ call(exec, deferredPromise->JSPromiseDeferred::reject(), args, "This should never be seen..."); >+ return encodedJSUndefined(); >+ } >+ >+ args.append(source); > call(exec, deferredPromise->JSPromiseDeferred::resolve(), args, "This should never be seen..."); > return encodedJSUndefined(); > }); >@@ -210,6 +220,21 @@ JSObject* JSAPIGlobalObject::moduleLoaderCreateImportMetaProperties(JSGlobalObje > return metaProperties; > } > >+JSValue JSAPIGlobalObject::loadAndEvaluateJSScriptModule(JSScript *script, NSURL *url) >+{ >+ ASSERT(script.type == kJSScriptTypeModule); >+ VM& vm = this->vm(); >+ auto scope = DECLARE_THROW_SCOPE(vm); >+ >+ auto key = Identifier::fromString(&vm, [url absoluteString]); >+ JSInternalPromise* promise = loadAndEvaluateModule(globalExec(), [script jsSourceCode:key]->sourceCode(), jsUndefined()); >+ RETURN_IF_EXCEPTION(scope, { }); >+ auto result = JSPromiseDeferred::tryCreate(globalExec(), this); >+ RETURN_IF_EXCEPTION(scope, { }); >+ result->resolve(globalExec(), promise); >+ return result; >+} >+ > } > > #endif // JSC_OBJC_API_ENABLED >diff --git a/Source/JavaScriptCore/API/JSContext.mm b/Source/JavaScriptCore/API/JSContext.mm >index 518fb872398483412ffa1fbddcfd9ffae168aff0..c63c6c557d87337a97637a4b3a8216f93888a43a 100644 >--- a/Source/JavaScriptCore/API/JSContext.mm >+++ b/Source/JavaScriptCore/API/JSContext.mm >@@ -103,17 +103,37 @@ > return [self evaluateScript:script withSourceURL:nil]; > } > >-- (JSValue *)evaluateScript:(NSString *)script withSourceURL:(NSURL *)sourceURL >+static JSValue *evaluateScript(JSContext *context, RefPtr<OpaqueJSString> source, RefPtr<OpaqueJSString> url) > { > JSValueRef exceptionValue = nullptr; >+ JSValueRef result = JSEvaluateScript(context->m_context, source.get(), nullptr, url.get(), 0, &exceptionValue); >+ >+ if (exceptionValue) >+ return [context valueFromNotifyException:exceptionValue]; >+ return [JSValue valueWithJSValueRef:result inContext:context]; >+} >+ >+- (JSValue *)evaluateScript:(NSString *)script withSourceURL:(NSURL *)sourceURL >+{ > auto scriptJS = OpaqueJSString::tryCreate(script); > auto sourceURLJS = OpaqueJSString::tryCreate([sourceURL absoluteString]); >- JSValueRef result = JSEvaluateScript(m_context, scriptJS.get(), nullptr, sourceURLJS.get(), 0, &exceptionValue); >+ return evaluateScript(self, scriptJS, sourceURLJS); >+} > >- if (exceptionValue) >- return [self valueFromNotifyException:exceptionValue]; >+- (JSValue *)evaluateJSScript:(JSScript *)script withSourceURL:(NSURL *)url >+{ >+ if (script.type == kJSScriptTypeProgram) { >+ String source = [script source]; >+ return evaluateScript(self, OpaqueJSString::tryCreate(WTFMove(source)), OpaqueJSString::tryCreate([url absoluteString])); >+ } >+ >+ JSC::ExecState* exec = toJS(m_context); >+ JSC::VM& vm = exec->vm(); >+ auto* globalObject = JSC::jsDynamicCast<JSC::JSAPIGlobalObject*>(vm, exec->lexicalGlobalObject()); >+ if (!globalObject) >+ return [JSValue valueWithNewPromiseRejectedWithReason:[JSValue valueWithNewErrorFromMessage:@"Context does not support module loading" inContext:self] inContext:self]; > >- return [JSValue valueWithJSValueRef:result inContext:self]; >+ return [JSValue valueWithJSValueRef:toRef(vm, globalObject->loadAndEvaluateJSScriptModule(script, url)) inContext:self]; > } > > - (void)setException:(JSValue *)value >@@ -300,6 +320,11 @@ > return NO; > } > >+- (JSValue *)valueFromNotifyExceptionWithString:(String&)string >+{ >+ return [self valueFromNotifyException:[JSValue valueWithNewErrorFromMessage:string inContext:self].JSValueRef]; >+} >+ > - (void)beginCallbackWithData:(CallbackData *)callbackData calleeValue:(JSValueRef)calleeValue thisValue:(JSValueRef)thisValue argumentCount:(size_t)argumentCount arguments:(const JSValueRef *)arguments > { > Thread& thread = Thread::current(); >diff --git a/Source/JavaScriptCore/API/JSContextPrivate.h b/Source/JavaScriptCore/API/JSContextPrivate.h >index d4e206b33575e9fa6d4182e9e1ad8940568a8677..2e21adc6e60e023b20ca8e59beb387956ed79b0b 100644 >--- a/Source/JavaScriptCore/API/JSContextPrivate.h >+++ b/Source/JavaScriptCore/API/JSContextPrivate.h >@@ -74,6 +74,16 @@ > /*! @abstract The delegate the context will use when trying to load a module. Note, this delegate will be ignored for contexts returned by UIWebView. */ > @property (nonatomic, weak) id <JSModuleLoaderDelegate> moduleLoaderDelegate JSC_API_AVAILABLE(macosx(JSC_MAC_TBA), ios(JSC_IOS_TBA)); > >+/*! >+ @method >+ @abstract Run a JSScript. >+ @param script the JSScript to evaluate. >+ @discussion If the provided JSScript was created with JSScriptTypeProgram, the script will run synchronously and return the result of evaluation. >+ >+ Otherwise, if the script was created with JSScriptTypeModule, the module will be run asynchronously and will return a promise resolved when the module and any transitive dependencies are loaded. The module loader will treat the script as if it had been returned from a delegate call to moduleLoaderDelegate with its identefier as url. This mirrors the JavaScript dynamic import operation. >+ */ >+- (JSValue *)evaluateJSScript:(JSScript *)script withSourceURL:(NSURL *)url; >+ > @end > > #endif >diff --git a/Source/JavaScriptCore/API/JSScript.h b/Source/JavaScriptCore/API/JSScript.h >index 4aaa8998bbc1843603f8ab58949a7165c497606f..e6a779a5c0e74e40eb31dac3804dfc45acc8f70f 100644 >--- a/Source/JavaScriptCore/API/JSScript.h >+++ b/Source/JavaScriptCore/API/JSScript.h >@@ -31,6 +31,18 @@ NS_ASSUME_NONNULL_BEGIN > > @class JSVirtualMachine; > >+/*! >+ @enum JSScriptType >+ @abstract A constant identifying the execution type of a JSScript. >+ @constant kJSScriptTypeProgram The type of a normal JavaScript program. >+ @constant kJSScriptTypeModule The type of a module JavaScript program. >+ */ >+typedef NS_ENUM(NSInteger, JSScriptType) { >+ kJSScriptTypeProgram, >+ kJSScriptTypeModule, >+}; >+ >+ > JSC_CLASS_AVAILABLE(macosx(JSC_MAC_TBA), ios(JSC_IOS_TBA)) > @interface JSScript : NSObject > >@@ -41,7 +53,7 @@ JSC_CLASS_AVAILABLE(macosx(JSC_MAC_TBA), ios(JSC_IOS_TBA)) > @param vm The JSVirtualMachine the script can be evaluated in. > @result The new script. > */ >-+ (nullable instancetype)scriptWithSource:(NSString *)source inVirtualMachine:(JSVirtualMachine *)vm; >++ (nullable instancetype)scriptWithSource:(NSString *)source inVirtualMachine:(JSVirtualMachine *)vm JSC_API_DEPRECATED(macosx(JSC_MAC_TBA), ios(JSC_IOS_TBA)); > > /*! > @method >@@ -55,13 +67,44 @@ JSC_CLASS_AVAILABLE(macosx(JSC_MAC_TBA), ios(JSC_IOS_TBA)) > > If the file at filePath is not ascii this method will return nil. > */ >-+ (nullable instancetype)scriptFromASCIIFile:(NSURL *)filePath inVirtualMachine:(JSVirtualMachine *)vm withCodeSigning:(nullable NSURL *)codeSigningPath andBytecodeCache:(nullable NSURL *)cachePath; >- >++ (nullable instancetype)scriptFromASCIIFile:(NSURL *)filePath inVirtualMachine:(JSVirtualMachine *)vm withCodeSigning:(nullable NSURL *)codeSigningPath andBytecodeCache:(nullable NSURL *)cachePath JSC_API_DEPRECATED(macosx(JSC_MAC_TBA), ios(JSC_IOS_TBA)); > > /*! > This is deprecated and is equivalent to scriptFromASCIIFile:inVirtualMachine:withCodeSigning:andBytecodeCache:. > */ >-+ (nullable instancetype)scriptFromUTF8File:(NSURL *)filePath inVirtualMachine:(JSVirtualMachine *)vm withCodeSigning:(nullable NSURL *)codeSigningPath andBytecodeCache:(nullable NSURL *)cachePath; >++ (nullable instancetype)scriptFromUTF8File:(NSURL *)filePath inVirtualMachine:(JSVirtualMachine *)vm withCodeSigning:(nullable NSURL *)codeSigningPath andBytecodeCache:(nullable NSURL *)cachePath JSC_API_DEPRECATED(macosx(JSC_MAC_TBA), ios(JSC_IOS_TBA)); >+ >+/*! >+ @method >+ @abstract Create a JSScript for the specified virtual machine. >+ @param type The type of JavaScript source. >+ @param source The source code to use when the script is evaluated by the JS vm. >+ @param vm The JSVirtualMachine the script can be evaluated in. >+ @param cachePath A URL containing the path where the VM should cache for future execution. >+ @param error A description of why the script could not be created if the result is nil. >+ @result The new script. >+ */ >++ (nullable instancetype)scriptOfType:(JSScriptType)type withSource:(NSString *)source inVirtualMachine:(JSVirtualMachine *)vm andBytecodeCache:(nullable NSURL *)cachePath error:(out NSError * _Nullable * _Nullable)error; >+ >+/*! >+ @method >+ @abstract Create a JSScript for the specified virtual machine with a path to a codesigning and bytecode caching. >+ @param type The type of JavaScript source. >+ @param filePath A URL containing the path to a JS source code file on disk. >+ @param vm The JSVirtualMachine the script can be evaluated in. >+ @param cachePath A URL containing the path where the VM should cache for future execution. >+ @param error A description of why the script could not be created if the result is nil. >+ @result The new script. >+ @discussion The files at filePath and cachePath should not be externally modified for the lifecycle of vm. This method will file back the memory for the source. >+ >+ If the file at filePath is not ascii this method will return nil. >+ */ >++ (nullable instancetype)scriptOfType:(JSScriptType)type memoryMappedFromASCIIFile:(NSURL *)filePath inVirtualMachine:(JSVirtualMachine *)vm andBytecodeCache:(nullable NSURL *)cachePath error:(out NSError * _Nullable * _Nullable)error; >+ >+/*! @abstract The type of script provided during creation. */ >+@property (readonly) JSScriptType type; >+ >+- (BOOL)cacheBytecodeWithError:(out NSError * _Nullable * _Nullable)error; > > @end > >diff --git a/Source/JavaScriptCore/API/JSScript.mm b/Source/JavaScriptCore/API/JSScript.mm >index fef446dedf86b2450aa7f83f2ba3ee70a8852fe0..d2ce9d3ae28b4a99c283005f6ea8097cc17148ee 100644 >--- a/Source/JavaScriptCore/API/JSScript.mm >+++ b/Source/JavaScriptCore/API/JSScript.mm >@@ -37,15 +37,21 @@ > #import "Symbol.h" > #include <sys/stat.h> > >+#include <wtf/FileSystem.h> >+ > #if JSC_OBJC_API_ENABLED > >+static NSString *JSScriptErrorDomain = @"JSScriptErrorDomain"; >+static NSString *messageNSString = @"message"; >+ > @implementation JSScript { > __weak JSVirtualMachine* m_virtualMachine; >+ JSScriptType m_type; >+ FileSystem::MappedFileData m_mappedSource; > String m_source; >- NSURL* m_cachePath; >+ NSURL *m_cachePath; > JSC::CachedBytecode m_cachedBytecode; > JSC::Strong<JSC::JSSourceCode> m_jsSourceCode; >- UniquedStringImpl* m_moduleKey; > } > > + (instancetype)scriptWithSource:(NSString *)source inVirtualMachine:(JSVirtualMachine *)vm >@@ -116,6 +122,51 @@ static bool fillBufferWithContentsOfFile(const String& fileName, Vector<LChar>& > return [JSScript scriptFromASCIIFile:filePath inVirtualMachine:vm withCodeSigning:codeSigningPath andBytecodeCache:cachePath]; > } > >+static JSScript *createError(NSString *message, NSError** error) >+{ >+ if (error) >+ *error = [NSError errorWithDomain:JSScriptErrorDomain code:1 userInfo:@{ messageNSString: message }]; >+ return nil; >+} >+ >++ (instancetype)scriptOfType:(JSScriptType)type withSource:(NSString *)source inVirtualMachine:(JSVirtualMachine *)vm andBytecodeCache:(NSURL *)cachePath error:(NSError **)error >+{ >+ UNUSED_PARAM(error); >+ JSScript *result = [[[JSScript alloc] init] autorelease]; >+ result->m_virtualMachine = vm; >+ result->m_type = type; >+ result->m_source = source; >+ result->m_cachePath = cachePath; >+ return result; >+} >+ >++ (instancetype)scriptOfType:(JSScriptType)type memoryMappedFromASCIIFile:(NSURL *)filePath inVirtualMachine:(JSVirtualMachine *)vm andBytecodeCache:(NSURL *)cachePath error:(NSError **)error >+{ >+ UNUSED_PARAM(error); >+ URL filePathURL([filePath absoluteURL]); >+ if (!filePathURL.isLocalFile()) >+ return createError([NSString stringWithFormat:@"File path %@ is not a local file", filePathURL.operator NSString *()], error); >+ >+ bool success = false; >+ String systemPath = filePathURL.fileSystemPath(); >+ FileSystem::MappedFileData fileData(systemPath, success); >+ if (!success) >+ return createError([NSString stringWithFormat:@"File at path %@ could not be mapped.", systemPath.operator NSString *()], error); >+ >+ if (!charactersAreAllASCII(reinterpret_cast<const LChar*>(fileData.data()), fileData.size())) { >+ return createError([NSString stringWithFormat:@"Not all characters in file at %@ are ASCII.", systemPath.operator NSString *()], error); >+ } >+ >+ JSScript *result = [[[JSScript alloc] init] autorelease]; >+ result->m_virtualMachine = vm; >+ result->m_type = type; >+ result->m_source = String(StringImpl::createWithoutCopying(reinterpret_cast<const LChar*>(fileData.data()), fileData.size())); >+ result->m_mappedSource = WTFMove(fileData); >+ result->m_cachePath = cachePath; >+ [result readCache]; >+ return result; >+} >+ > - (void)dealloc > { > if (m_cachedBytecode.size() && !m_cachedBytecode.owned()) >@@ -152,22 +203,14 @@ static bool fillBufferWithContentsOfFile(const String& fileName, Vector<LChar>& > m_cachedBytecode = JSC::CachedBytecode { buffer, size }; > } > >-- (void)writeCache >+- (BOOL)cacheBytecodeWithError:(NSError **)error > { >- if (m_cachedBytecode.size() || !m_cachePath) >- return; >+ String errorString { }; >+ [self writeCache:errorString]; >+ if (!errorString.isNull()) >+ return !!createError(errorString, error); > >- 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); >+ return YES; > } > > @end >@@ -191,10 +234,8 @@ static bool fillBufferWithContentsOfFile(const String& fileName, Vector<LChar>& > > - (JSC::JSSourceCode*)jsSourceCode:(const JSC::Identifier&)moduleKey > { >- if (m_jsSourceCode) { >- ASSERT(moduleKey.impl() == m_moduleKey); >+ if (m_jsSourceCode) > return m_jsSourceCode.get(); >- } > > JSC::VM& vm = m_virtualMachine.vm; > TextPosition startPosition { }; >@@ -202,10 +243,40 @@ static bool fillBufferWithContentsOfFile(const String& fileName, Vector<LChar>& > 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; > } > >+- (BOOL)writeCache:(String&)error >+{ >+ >+ if (m_cachedBytecode.size()) >+ return YES; >+ >+ if (!m_cachePath) { >+ error = "no cache path provided"; >+ return NO; >+ \\dh >+ >+ JSC::ParserError parserError; >+ auto key = JSC::Identifier::fromString(&m_virtualMachine.vm, "API Placeholder string"_s); >+ m_cachedBytecode = JSC::generateModuleBytecode(m_virtualMachine.vm, [self jsSourceCode:key]->sourceCode(), parserError); >+ if (parserError.isValid()) { >+ error = "unable to generate complete bytecode"; >+ return NO; >+ } >+ int fd = open(m_cachePath.path.UTF8String, O_CREAT | O_WRONLY, 0666); >+ if (fd == -1) { >+ error = makeString("Unable to open file: ", m_cachePath.path.UTF8String, " due to error: ", strerror(errno)); >+ return NO; >+ } >+ int returnCode = flock(fd, LOCK_EX | LOCK_NB); >+ if (returnCode) >+ error = "Unable to lock the cache file; it may already be in use."; >+ else >+ write(fd, m_cachedBytecode.data(), m_cachedBytecode.size()); >+ close(fd); >+ return !returnCode; >+} > @end > > >diff --git a/Source/JavaScriptCore/API/JSScriptInternal.h b/Source/JavaScriptCore/API/JSScriptInternal.h >index 66a75e26e52a76bd2d088981fca0b8c1c9455402..37f7517429feb3abc10ae09b8612da27f7067360 100644 >--- a/Source/JavaScriptCore/API/JSScriptInternal.h >+++ b/Source/JavaScriptCore/API/JSScriptInternal.h >@@ -48,6 +48,7 @@ class String; > - (const WTF::String&)source; > - (const JSC::CachedBytecode*)cachedBytecode; > - (JSC::JSSourceCode*)jsSourceCode:(const JSC::Identifier&)moduleKey; >+- (BOOL)writeCache:(String&)error; > > @end > >diff --git a/Source/JavaScriptCore/API/JSValue.h b/Source/JavaScriptCore/API/JSValue.h >index aa3ae51c096add6654e4bc24c1d8fc15bb8bb77c..cdad97da253b0d63e94064fdb9674377c116b6c9 100644 >--- a/Source/JavaScriptCore/API/JSValue.h >+++ b/Source/JavaScriptCore/API/JSValue.h >@@ -1,4 +1,4 @@ >-/* >+O/* > * Copyright (C) 2013 Apple Inc. All rights reserved. > * > * Redistribution and use in source and binary forms, with or without >diff --git a/Source/JavaScriptCore/API/tests/testIncludes.m b/Source/JavaScriptCore/API/tests/testIncludes.m >index 61f05dab1272f3f7ac7b7be72dd47a20d97c83be..06d3f8c68b468968a1d9990dff5d400fe37dbbca 100644 >--- a/Source/JavaScriptCore/API/tests/testIncludes.m >+++ b/Source/JavaScriptCore/API/tests/testIncludes.m >@@ -27,6 +27,7 @@ > // Since we include files that haven't passed through the rewriter we need to handle the non-rewritten values... > #define JSC_API_AVAILABLE(...) > #define JSC_CLASS_AVAILABLE(...) >+#define JSC_API_DEPRECATED(...) > #define JSC_MAC_VERSION_TBA 0 > #define JSC_IOS_VERSION_TBA 0 > >diff --git a/Source/JavaScriptCore/API/tests/testapi.c b/Source/JavaScriptCore/API/tests/testapi.c >index 01f94cd3bbe0bc8a4013530a39a4c50533e9fcba..28d0287ad9535284ccfacd6884af9d04fb8d8e3e 100644 >--- a/Source/JavaScriptCore/API/tests/testapi.c >+++ b/Source/JavaScriptCore/API/tests/testapi.c >@@ -67,7 +67,7 @@ > #endif > > #if JSC_OBJC_API_ENABLED >-void testObjectiveCAPI(void); >+void testObjectiveCAPI(const char*); > #endif > > int testCAPIViaCpp(const char* filter); >@@ -1380,11 +1380,11 @@ int main(int argc, char* argv[]) > SetErrorMode(0); > #endif > >+ const char* filter = argc > 1 ? argv[1] : NULL; > #if JSC_OBJC_API_ENABLED >- testObjectiveCAPI(); >+ testObjectiveCAPI(filter); > #endif > >- const char* filter = argc > 1 ? argv[1] : NULL; > RELEASE_ASSERT(!testCAPIViaCpp(filter)); > if (filter) > return 0; >diff --git a/Source/JavaScriptCore/API/tests/testapi.mm b/Source/JavaScriptCore/API/tests/testapi.mm >index 834913161bce57daf23cd882747dc49ad3261c2a..0470fbe7f45b4334cc074068ef8cee8cdda1b60d 100644 >--- a/Source/JavaScriptCore/API/tests/testapi.mm >+++ b/Source/JavaScriptCore/API/tests/testapi.mm >@@ -41,12 +41,14 @@ > #import "Regress141275.h" > #import "Regress141809.h" > >+#import <libproc.h> > #import <pthread.h> > #import <vector> > #import <wtf/MemoryFootprint.h> > #import <wtf/Optional.h> > #import <wtf/DataLog.h> > >+ > extern "C" void JSSynchronousGarbageCollectForDebugging(JSContextRef); > extern "C" void JSSynchronousEdenCollectForDebugging(JSContextRef); > >@@ -54,7 +56,7 @@ extern "C" bool _Block_has_signature(id); > extern "C" const char * _Block_signature(id); > > extern int failed; >-extern "C" void testObjectiveCAPI(void); >+extern "C" void testObjectiveCAPI(const char*); > extern "C" void checkResult(NSString *, bool); > > #if JSC_OBJC_API_ENABLED >@@ -1985,9 +1987,9 @@ 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;"; >+ NSString* fooSource = @"import \"otherDirectory/baz.js\"; export let n = null;"; >+ NSString* barSource = @"import { n } from \"../foo.js\"; export let foo = () => n;"; >+ 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"]; >@@ -2002,18 +2004,37 @@ static void testBytecodeCache() > [bazSource writeToURL:bazPath atomically:NO encoding:NSASCIIStringEncoding error:nil]; > > auto block = ^(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 >+ JSC::Options::forceDiskCache() = true; >+ JSScript *result = nil; >+ if ([identifier isEqualToObject:@"file:///directory/bar.js"]) { >+ NSError *error = nil; >+ auto source = [NSString stringWithContentsOfURL:barPath encoding:NSASCIIStringEncoding error:&error]; >+ checkResult(@"opening the file source file should succeed", source && !error); >+ result = [JSScript scriptOfType:kJSScriptTypeModule withSource:source inVirtualMachine:context.virtualMachine andBytecodeCache:barCachePath error:nil]; >+ } else if ([identifier isEqualToObject:@"file:///foo.js"]) { >+ NSError *error = nil; >+ auto source = [NSString stringWithContentsOfURL:fooPath encoding:NSASCIIStringEncoding error:&error]; >+ checkResult(@"opening the file source file should succeed", source && !error); >+ result = [JSScript scriptOfType:kJSScriptTypeModule withSource:source inVirtualMachine:context.virtualMachine andBytecodeCache:fooCachePath error:nil]; >+ } else if ([identifier isEqualToObject:@"file:///otherDirectory/baz.js"]) { >+ NSError *error = nil; >+ auto source = [NSString stringWithContentsOfURL:bazPath encoding:NSASCIIStringEncoding error:&error]; >+ checkResult(@"opening the file source file should succeed", source && !error); >+ result = [JSScript scriptOfType:kJSScriptTypeModule withSource:source inVirtualMachine:context.virtualMachine andBytecodeCache:bazCachePath error:nil]; >+ } >+ >+ if (!result) { > [reject callWithArguments:@[[JSValue valueWithNewErrorFromMessage:@"Weird path" inContext:context]]]; >+ return; >+ } >+ >+ NSError *error = nil; >+ BOOL success = [result cacheBytecodeWithError:&error]; >+ checkResult(@"Bytecode was cached correctly", success && !error); >+ [resolve callWithArguments:@[result]]; > }; > > @autoreleasepool { >- JSC::Options::forceDiskCache() = true; > auto *context = [JSContextFetchDelegate contextWithBlockForFetch:block]; > context.moduleLoaderDelegate = context; > JSValue *promise = [context evaluateScript:@"import('../otherDirectory/baz.js');" withSourceURL:[NSURL fileURLWithPath:@"/directory" isDirectory:YES]]; >@@ -2023,12 +2044,14 @@ static void testBytecodeCache() > } > > 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]; >+ BOOL removedAll = true; >+ removedAll &= [fileManager removeItemAtURL:fooPath error:nil]; >+ removedAll &= [fileManager removeItemAtURL:barPath error:nil]; >+ removedAll &= [fileManager removeItemAtURL:bazPath error:nil]; >+ removedAll &= [fileManager removeItemAtURL:fooCachePath error:nil]; >+ removedAll &= [fileManager removeItemAtURL:barCachePath error:nil]; >+ removedAll &= [fileManager removeItemAtURL:bazCachePath error:nil]; >+ checkResult(@"Removed all temp files created", removedAll); > } > } > >@@ -2078,7 +2101,7 @@ static NSURL *resolvePathToScripts() > > @end > >-static void testLoadBasicFile() >+static void testLoadBasicFileLegacySPI() > { > @autoreleasepool { > auto *context = [JSContextFileLoaderDelegate newContext]; >@@ -2089,34 +2112,118 @@ static void testLoadBasicFile() > } > } > >-void testObjectiveCAPI() >+ >+@interface JSContextMemoryMappedLoaderDelegate : JSContext <JSModuleLoaderDelegate> >+ >++ (instancetype)newContext; >+ >+@end >+ >+@implementation JSContextMemoryMappedLoaderDelegate { >+} >+ >++ (instancetype)newContext >+{ >+ auto *result = [[JSContextMemoryMappedLoaderDelegate alloc] init]; >+ return result; >+} >+ >+- (void)context:(JSContext *)context fetchModuleForIdentifier:(JSValue *)identifier withResolveHandler:(JSValue *)resolve andRejectHandler:(JSValue *)reject >+{ >+ NSURL *filePath = [NSURL URLWithString:[identifier toString]]; >+ auto *script = [JSScript scriptOfType:kJSScriptTypeModule memoryMappedFromASCIIFile:filePath inVirtualMachine:context.virtualMachine andBytecodeCache:nil error:nil]; >+ if (script) >+ [resolve callWithArguments:@[script]]; >+ else >+ [reject callWithArguments:@[[JSValue valueWithNewErrorFromMessage:@"Unable to create Script" inContext:context]]]; >+} >+ >+@end >+ >+static void testLoadBasicFile() >+{ >+ size_t count = proc_pidinfo(getpid(), PROC_PIDLISTFDS, 0, 0, 0); >+ @autoreleasepool { >+ auto *context = [JSContextMemoryMappedLoaderDelegate newContext]; >+ context.moduleLoaderDelegate = context; >+ JSValue *promise = [context evaluateScript:@"import('./basic.js');" withSourceURL:resolvePathToScripts()]; >+ JSValue *null = [JSValue valueWithNullInContext:context]; >+ size_t afterCount = proc_pidinfo(getpid(), PROC_PIDLISTFDS, 0, 0, 0); >+ checkResult(@"JSScript should not hold a file descriptor", count == afterCount); >+ checkModuleCodeRan(context, promise, null); >+ } >+ size_t after = proc_pidinfo(getpid(), PROC_PIDLISTFDS, 0, 0, 0); >+ checkResult(@"File descriptor count sholudn't change after context is dealloced", count == after); >+} >+ >+static void testJSScriptURL() >+{ >+ @autoreleasepool { >+ auto *context = [JSContextMemoryMappedLoaderDelegate newContext]; >+ context.moduleLoaderDelegate = context; >+ NSURL *url = [NSURL URLWithString:@"./basic.js" relativeToURL:resolvePathToScripts()]; >+ JSScript *script = [JSScript scriptOfType:kJSScriptTypeModule memoryMappedFromASCIIFile:url inVirtualMachine:context.virtualMachine andBytecodeCache:nil error:nil]; >+ >+ JSValue *result1 = [context evaluateJSScript:script withSourceURL:[NSURL fileURLWithPath:@"/foo/bar.js"]]; >+ JSValue *null = [JSValue valueWithNullInContext:context]; >+ checkModuleCodeRan(context, result1, null); >+ >+ JSValue *result2 = [context evaluateJSScript:script withSourceURL:[NSURL fileURLWithPath:@"/foo/baz.js"]]; >+ >+ __block bool wasRejected = false; >+ [result2 invokeMethod:@"catch" withArguments:@[^(JSValue *reason) { >+ wasRejected = [reason isObject]; >+ }]]; >+ >+ checkResult(@"Module JSScript imported with different identifiers is rejected", wasRejected); >+ } >+} >+ >+#define RUN(test) do { \ >+ if (!shouldRun(#test)) \ >+ break; \ >+ NSLog(@"%s...\n", #test); \ >+ test; \ >+ NSLog(@"%s: done.\n", #test); \ >+ } while (false) >+ >+void testObjectiveCAPI(const char* filter) > { > NSLog(@"Testing Objective-C API"); > >- checkNegativeNSIntegers(); >- runJITThreadLimitTests(); >+ auto shouldRun = [&] (const char* test) -> bool { >+ if (filter) >+ return strcasestr(test, filter); >+ return true; >+ }; >+ >+ RUN(checkNegativeNSIntegers()); >+ RUN(runJITThreadLimitTests()); >+ >+ RUN(testLoaderResolvesAbsoluteScriptURL()); >+ RUN(testFetch()); >+ RUN(testFetchWithTwoCycle()); >+ RUN(testFetchWithThreeCycle()); >+ RUN(testImportModuleTwice()); >+ RUN(testBytecodeCache()); > >- testLoaderResolvesAbsoluteScriptURL(); >- testFetch(); >- testFetchWithTwoCycle(); >- testFetchWithThreeCycle(); >- testImportModuleTwice(); >- testBytecodeCache(); >+ RUN(testLoaderRejectsNilScriptURL()); >+ RUN(testLoaderRejectsFailedFetch()); > >- testLoaderRejectsNilScriptURL(); >- testLoaderRejectsFailedFetch(); >+ RUN(testJSScriptURL()); > > // File loading >- testLoadBasicFile(); >- >- promiseWithExecutor(Resolution::ResolveEager); >- promiseWithExecutor(Resolution::RejectEager); >- promiseWithExecutor(Resolution::ResolveLate); >- promiseWithExecutor(Resolution::RejectLate); >- promiseRejectOnJSException(); >- promiseCreateResolved(); >- promiseCreateRejected(); >- parallelPromiseResolveTest(); >+ RUN(testLoadBasicFileLegacySPI()); >+ RUN(testLoadBasicFile()); >+ >+ RUN(promiseWithExecutor(Resolution::ResolveEager)); >+ RUN(promiseWithExecutor(Resolution::RejectEager)); >+ RUN(promiseWithExecutor(Resolution::ResolveLate)); >+ RUN(promiseWithExecutor(Resolution::RejectLate)); >+ RUN(promiseRejectOnJSException()); >+ RUN(promiseCreateResolved()); >+ RUN(promiseCreateRejected()); >+ RUN(parallelPromiseResolveTest()); > > testObjectiveCAPIMain(); > } >diff --git a/Source/JavaScriptCore/config.h b/Source/JavaScriptCore/config.h >index e364390fdd0f7d4577dce1e46883b7e127ea5c0c..fa1b8a97fd9e47ad4bc250b0569daa8f0b79757a 100644 >--- a/Source/JavaScriptCore/config.h >+++ b/Source/JavaScriptCore/config.h >@@ -25,6 +25,7 @@ > > #define JSC_API_AVAILABLE(...) > #define JSC_CLASS_AVAILABLE(...) JS_EXPORT >+#define JSC_API_DEPRECATED(...) > // Use zero since it will be less than any possible version number. > #define JSC_MAC_VERSION_TBA 0 > #define JSC_IOS_VERSION_TBA 0 >diff --git a/Source/JavaScriptCore/runtime/CachedTypes.cpp b/Source/JavaScriptCore/runtime/CachedTypes.cpp >index 05e8f0786320522d682e7de9569e30a0a2fbab72..5353a4af2e759f8e2753c80632c3fac22fadc87c 100644 >--- a/Source/JavaScriptCore/runtime/CachedTypes.cpp >+++ b/Source/JavaScriptCore/runtime/CachedTypes.cpp >@@ -213,9 +213,10 @@ class Decoder { > WTF_FORBID_HEAP_ALLOCATION; > > public: >- Decoder(VM& vm, const void* baseAddress, size_t size) >+ Decoder(VM& vm, const void* baseAddress, size_t size, URL&& sourceURLOverride) > : m_vm(vm) > , m_baseAddress(reinterpret_cast<const uint8_t*>(baseAddress)) >+ , m_sourceURLOverride(WTFMove(sourceURLOverride)) > #ifndef NDEBUG > , m_size(size) > #endif >@@ -257,9 +258,12 @@ public: > m_finalizers.add(offset, fn); > } > >+ const URL& sourceURLOverride() { return m_sourceURLOverride; } >+ > private: > VM& m_vm; > const uint8_t* m_baseAddress; >+ URL m_sourceURLOverride; > #ifndef NDEBUG > size_t m_size; > #endif >@@ -1258,10 +1262,16 @@ public: > { > String decodedSource = m_source.decode(decoder); > SourceOrigin decodedSourceOrigin = m_sourceOrigin.decode(decoder); >- String decodedURL = m_url.decode(decoder); >+ String decodedURLString = m_url.decode(decoder); >+ URL sourceURL; >+ if (decoder.sourceURLOverride()) { >+ decodedSourceOrigin = SourceOrigin { decoder.sourceURLOverride() }; >+ sourceURL = decoder.sourceURLOverride(); >+ } else >+ sourceURL = URL(URL(), decodedURLString); > TextPosition decodedStartPosition = m_startPosition.decode(decoder); > >- Ref<StringSourceProvider> sourceProvider = StringSourceProvider::create(decodedSource, decodedSourceOrigin, URL(URL(), decodedURL), decodedStartPosition, sourceType); >+ Ref<StringSourceProvider> sourceProvider = StringSourceProvider::create(decodedSource, decodedSourceOrigin, WTFMove(sourceURL), decodedStartPosition, sourceType); > Base::decode(decoder, sourceProvider.get()); > return &sourceProvider.leakRef(); > } >@@ -2000,10 +2010,10 @@ std::pair<MallocPtr<uint8_t>, size_t> encodeCodeBlock(VM& vm, const SourceCodeKe > return encoder.release(); > } > >-UnlinkedCodeBlock* decodeCodeBlockImpl(VM& vm, const SourceCodeKey& key, const void* buffer, size_t size) >+UnlinkedCodeBlock* decodeCodeBlockImpl(VM& vm, const SourceCodeKey& key, const void* buffer, size_t size, URL&& sourceURLOverride) > { > const auto* cachedEntry = reinterpret_cast<const GenericCacheEntry*>(buffer); >- Decoder decoder(vm, buffer, size); >+ Decoder decoder(vm, buffer, size, WTFMove(sourceURLOverride)); > std::pair<SourceCodeKey, UnlinkedCodeBlock*> entry; > { > DeferGC deferGC(vm.heap); >diff --git a/Source/JavaScriptCore/runtime/CachedTypes.h b/Source/JavaScriptCore/runtime/CachedTypes.h >index bcb8acb6ce570e9726389c26d70bcba21da8d4ad..2befaf910296c31601eae66f4f9d48107a538849 100644 >--- a/Source/JavaScriptCore/runtime/CachedTypes.h >+++ b/Source/JavaScriptCore/runtime/CachedTypes.h >@@ -27,6 +27,7 @@ > > #include "JSCast.h" > #include <wtf/MallocPtr.h> >+#include <wtf/URL.h> > > namespace JSC { > >@@ -34,13 +35,13 @@ class SourceCodeKey; > class UnlinkedCodeBlock; > > std::pair<MallocPtr<uint8_t>, size_t> encodeCodeBlock(VM&, const SourceCodeKey&, const UnlinkedCodeBlock*); >-UnlinkedCodeBlock* decodeCodeBlockImpl(VM&, const SourceCodeKey&, const void*, size_t); >+UnlinkedCodeBlock* decodeCodeBlockImpl(VM&, const SourceCodeKey&, const void*, size_t, URL&&); > > > template<typename UnlinkedCodeBlockType> >-UnlinkedCodeBlockType* decodeCodeBlock(VM& vm, const SourceCodeKey& key, const void* buffer, size_t size) >+UnlinkedCodeBlockType* decodeCodeBlock(VM& vm, const SourceCodeKey& key, const void* buffer, size_t size, URL&& sourceURLOverride = URL()) > { >- return jsCast<UnlinkedCodeBlockType*>(decodeCodeBlockImpl(vm, key, buffer, size)); >+ return jsCast<UnlinkedCodeBlockType*>(decodeCodeBlockImpl(vm, key, buffer, size, WTFMove(sourceURLOverride))); > } > > } // namespace JSC
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 194517
:
361720
|
361924
|
362351
|
362364
|
362365
|
362414
|
362464
|
362473
|
362579
|
362626
|
362635
|
362644
|
362653
|
362654
|
362656
|
362657
|
362663