WebKit Bugzilla
Attachment 361720 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]
Patch
bug-194517-20190211153623.patch (text/plain), 34.78 KB, created by
Keith Miller
on 2019-02-11 15:36:24 PST
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Keith Miller
Created:
2019-02-11 15:36:24 PST
Size:
34.78 KB
patch
obsolete
>Subversion Revision: 240795 >diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog >index 9596453cd3469bcdaf7c94b39dce5e554229a58c..ee7752b5d5486301b69989cac33ec453db78e990 100644 >--- a/Source/JavaScriptCore/ChangeLog >+++ b/Source/JavaScriptCore/ChangeLog >@@ -1,3 +1,43 @@ >+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!). >+ >+ * 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..a1214e7229a7bf325f311fef3c734eaff51d797f 100644 >--- a/Source/JavaScriptCore/API/JSAPIGlobalObject.h >+++ b/Source/JavaScriptCore/API/JSAPIGlobalObject.h >@@ -27,6 +27,8 @@ > > #include "JSGlobalObject.h" > >+OBJC_CLASS JSScript; >+ > namespace JSC { > > class JSAPIGlobalObject : public JSGlobalObject { >@@ -55,6 +57,8 @@ public: > static JSInternalPromise* moduleLoaderFetch(JSGlobalObject*, ExecState*, JSModuleLoader*, JSValue, JSValue, JSValue); > static JSObject* moduleLoaderCreateImportMetaProperties(JSGlobalObject*, ExecState*, JSModuleLoader*, JSValue, JSModuleRecord*, JSValue); > >+ JSValue loadAndEvaluateJSScriptModule(JSScript *script); >+ > 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..0aeaf0124bd317b34e2f1bcdd6b4db77daa73590 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) >+{ >+ ASSERT(script.type == kJSScriptTypeModule); >+ VM& vm = this->vm(); >+ auto scope = DECLARE_THROW_SCOPE(vm); >+ >+ auto key = Identifier::fromString(&vm, [[script 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..ea61a750a5507f2ec9371c8dca2e599f290c5510 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 >+{ >+ if (script.type == kJSScriptTypeProgram) { >+ String source = [script source]; >+ return evaluateScript(self, OpaqueJSString::tryCreate(WTFMove(source)), OpaqueJSString::tryCreate([[script url] absoluteString])); >+ } > >- return [JSValue valueWithJSValueRef:result inContext:self]; >+ 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:toRef(vm, globalObject->loadAndEvaluateJSScriptModule(script)) inContext:self]; > } > > - (void)setException:(JSValue *)value >@@ -244,6 +264,19 @@ > m_moduleLoaderDelegate = moduleLoaderDelegate; > } > >+- (BOOL)cacheBytecodeForJSScript:(JSScript *)script recursivelyCacheModuleDependencies:(BOOL)recursive >+{ >+ if (recursive) >+ return [self boolFromNotifyException:[[JSValue valueWithNewErrorFromMessage:@"caching bytecode recursively is not supported yet!" inContext:self] JSValueRef]]; >+ >+ String error { }; >+ [script writeCache:error]; >+ if (!error.isNull()) >+ return [self boolFromNotifyException:[[JSValue valueWithNewErrorFromMessage:error inContext:self] JSValueRef]]; >+ >+ return YES; >+} >+ > @end > > @implementation JSContext(SubscriptSupport) >@@ -300,6 +333,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..918c317f918cd68317e55c307a5f4c76260e10d2 100644 >--- a/Source/JavaScriptCore/API/JSContextPrivate.h >+++ b/Source/JavaScriptCore/API/JSContextPrivate.h >@@ -74,6 +74,25 @@ > /*! @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 Cache the bytecode for a JSScript. >+ @param script The JSScript to cache. >+ @param recursive Whether caching should also cache any dependencies of a module JSScript. >+ @discussion If there was a problem caching the bytecode this method will return false and an exception will be set on the context. >+ */ >+- (BOOL)cacheBytecodeForJSScript:(JSScript *)script recursivelyCacheModuleDependencies:(BOOL)recursive; >+ >+/*! >+ @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 set to the result of <code>[script url]</code>. This mirrors the JavaScript dynamic import operation. >+ */ >+- (JSValue *)evaluateJSScript:(JSScript *)script; >+ > @end > > #endif >diff --git a/Source/JavaScriptCore/API/JSScript.h b/Source/JavaScriptCore/API/JSScript.h >index 4aaa8998bbc1843603f8ab58949a7165c497606f..ce76e195f909d464b755916f983d9ef4d1e2280a 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,14 +67,48 @@ 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 url The URL that should be used to reference this JSScript. >+ @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 withURL:(NSURL *)url 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 url The URL that should be used to reference this JSScript. >+ @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 withURL:(NSURL *)url inVirtualMachine:(JSVirtualMachine *)vm andBytecodeCache:(nullable NSURL *)cachePath error:(out NSError * _Nullable * _Nullable)error; >+ >+/*! @abstract The url provided for the source of the JSScript during creation. */ >+@property (readonly) NSURL *url; > >+/*! @abstract The type of script provided during creation. */ >+@property (readonly) JSScriptType type; > @end > > NS_ASSUME_NONNULL_END >diff --git a/Source/JavaScriptCore/API/JSScript.mm b/Source/JavaScriptCore/API/JSScript.mm >index fef446dedf86b2450aa7f83f2ba3ee70a8852fe0..6274a0a44f92350d68c2856e410a0bb7e7079659 100644 >--- a/Source/JavaScriptCore/API/JSScript.mm >+++ b/Source/JavaScriptCore/API/JSScript.mm >@@ -37,15 +37,19 @@ > #import "Symbol.h" > #include <sys/stat.h> > >+#include <wtf/FileSystem.h> >+ > #if JSC_OBJC_API_ENABLED > > @implementation JSScript { > __weak JSVirtualMachine* m_virtualMachine; >+ JSScriptType m_type; >+ FileSystem::MappedFileData m_mappedSource; > String m_source; >- NSURL* m_cachePath; >+ NSURL *m_url; >+ 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 +120,49 @@ static bool fillBufferWithContentsOfFile(const String& fileName, Vector<LChar>& > return [JSScript scriptFromASCIIFile:filePath inVirtualMachine:vm withCodeSigning:codeSigningPath andBytecodeCache:cachePath]; > } > >++ (instancetype)scriptOfType:(JSScriptType)type withSource:(NSString *)source withURL:(NSURL *)url 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_url = [url absoluteURL]; >+ result->m_cachePath = cachePath; >+ return result; >+} >+ >++ (instancetype)scriptOfType:(JSScriptType)type memoryMappedFromASCIIFile:(NSURL *)filePath withURL:(NSURL *)url inVirtualMachine:(JSVirtualMachine *)vm andBytecodeCache:(NSURL *)cachePath error:(NSError **)error >+{ >+ UNUSED_PARAM(error); >+ URL filePathURL([filePath absoluteURL]); >+ if (!filePathURL.isLocalFile()) >+ return nil; >+ >+ bool success = false; >+ FileSystem::MappedFileData fileData(filePathURL.fileSystemPath(), success); >+ if (!success) >+ return nil; >+ >+ if (!charactersAreAllASCII(reinterpret_cast<const LChar*>(fileData.data()), fileData.size())) >+ return nil; >+ >+ 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_url = url; >+ result->m_cachePath = cachePath; >+ [result readCache]; >+ return result; >+} >+ >+- (NSURL *)url >+{ >+ return m_url; >+} >+ > - (void)dealloc > { > if (m_cachedBytecode.size() && !m_cachedBytecode.owned()) >@@ -151,25 +198,6 @@ static bool fillBufferWithContentsOfFile(const String& fileName, Vector<LChar>& > > 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) >@@ -191,10 +219,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 +228,41 @@ 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; >+ } >+ >+ JSC::ParserError parserError; >+ auto key = JSC::Identifier::fromString(&m_virtualMachine.vm, [[self url] absoluteString]); >+ 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/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..48566fb21f92699bd7c0fe0859b1e9dabef6e4a6 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,34 @@ 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 withURL:[NSURL URLWithString:@"file:///directory/bar.js"] 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 withURL:[NSURL URLWithString:@"file:///foo.js"] 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 withURL:[NSURL URLWithString:@"file:///otherDirectory/baz.js"] inVirtualMachine:context.virtualMachine andBytecodeCache:bazCachePath error:nil]; >+ } >+ >+ if (!result) { > [reject callWithArguments:@[[JSValue valueWithNewErrorFromMessage:@"Weird path" inContext:context]]]; >+ return; >+ } >+ [context cacheBytecodeForJSScript:result recursivelyCacheModuleDependencies:NO]; >+ [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,15 +2041,19 @@ 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); > } > } > >+ >+ > @interface JSContextFileLoaderDelegate : JSContext <JSModuleLoaderDelegate> > > + (instancetype)newContext; >@@ -2078,7 +2100,7 @@ static NSURL *resolvePathToScripts() > > @end > >-static void testLoadBasicFile() >+static void testLoadBasicFileLegacySPI() > { > @autoreleasepool { > auto *context = [JSContextFileLoaderDelegate newContext]; >@@ -2089,34 +2111,109 @@ 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 withURL: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 *vm = [[JSVirtualMachine alloc] init]; >+ NSURL *url = resolvePathToScripts(); >+ auto *script = [JSScript scriptOfType:kJSScriptTypeProgram withSource:@"" withURL:url inVirtualMachine:vm andBytecodeCache:nil error:nil]; >+ checkResult(@"JSScript from source should use the URL provided.", [[script.url absoluteString] compare:[url absoluteString]] == NSOrderedSame); >+ >+ >+ script = [JSScript scriptOfType:kJSScriptTypeModule memoryMappedFromASCIIFile:[url URLByAppendingPathComponent:@"./basic.js" isDirectory:NO] withURL:url inVirtualMachine:vm andBytecodeCache:nil error:nil]; >+ checkResult(@"JSScript from mapped file should use the URL provided.", [[script.url absoluteString] compare:[url absoluteString]] == NSOrderedSame); >+ } >+} >+ >+#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
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