WebKit Bugzilla
Attachment 362579 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
b-backup.diff (text/plain), 56.25 KB, created by
Saam Barati
on 2019-02-20 17:51:12 PST
(
hide
)
Description:
WIP
Filename:
MIME Type:
Creator:
Saam Barati
Created:
2019-02-20 17:51:12 PST
Size:
56.25 KB
patch
obsolete
>Index: Source/JavaScriptCore/config.h >=================================================================== >--- Source/JavaScriptCore/config.h (revision 241834) >+++ Source/JavaScriptCore/config.h (working copy) >@@ -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 >Index: Source/JavaScriptCore/API/JSAPIGlobalObject.h >=================================================================== >--- Source/JavaScriptCore/API/JSAPIGlobalObject.h (revision 241834) >+++ Source/JavaScriptCore/API/JSAPIGlobalObject.h (working copy) >@@ -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(const JSLockHolder&, JSScript *script); >+ > private: > JSAPIGlobalObject(VM& vm, Structure* structure) > : Base(vm, structure, &s_globalObjectMethodTable) >Index: Source/JavaScriptCore/API/JSAPIGlobalObject.mm >=================================================================== >--- Source/JavaScriptCore/API/JSAPIGlobalObject.mm (revision 241834) >+++ Source/JavaScriptCore/API/JSAPIGlobalObject.mm (working copy) >@@ -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" >@@ -75,12 +77,18 @@ Identifier JSAPIGlobalObject::moduleLoad > ASSERT(key.isString() || key.isSymbol()); > String name = key.toWTFString(exec); > >- URL referrerURL(URL(), jsCast<JSString*>(referrer)->tryGetValue()); >- RELEASE_ASSERT(referrerURL.isValid()); >- >- URL url = URL(referrerURL, name); >- if (url.isValid()) >- return Identifier::fromString(exec, url); >+ if (JSString* referrerString = jsDynamicCast<JSString*>(vm, referrer)) { >+ URL referrerURL(URL(), referrerString->value(exec)); >+ RELEASE_ASSERT(referrerURL.isValid()); >+ >+ URL url = URL(referrerURL, name); >+ if (url.isValid()) >+ return Identifier::fromString(exec, url); >+ } else { >+ URL url = URL(URL(), name); >+ if (url.isValid()) >+ return Identifier::fromString(exec, url); >+ } > > throwVMError(exec, scope, "Could not form valid URL from identifier and base"_s); > return { }; >@@ -162,9 +170,9 @@ JSInternalPromise* JSAPIGlobalObject::mo > 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 +183,28 @@ JSInternalPromise* JSAPIGlobalObject::mo > return encodedJSUndefined(); > } > >- args.append([static_cast<JSScript *>(script) jsSourceCode:moduleKey]); >+ JSScript* jsScript = static_cast<JSScript *>(script); >+ >+ JSSourceCode* source = [jsScript jsSourceCode]; >+ if (UNLIKELY([jsScript type] != kJSScriptTypeModule)) { >+ args.append(createTypeError(exec, makeString("The JSScript that was provided did not have expected type of kJSScriptTypeModule."))); >+ call(exec, deferredPromise->JSPromiseDeferred::reject(), args, "This should never be seen..."); >+ return encodedJSUndefined(); >+ } >+ >+ // FIXME: The SPI we're deprecating did not require sourceURL, so we just >+ // ignore this check for such use cases until we can remove that SPI. Once >+ // we do that, we can remove the null check for sourceURL: >+ if (NSURL *sourceURL = [jsScript sourceURL]) { >+ String oldModuleKey { [sourceURL absoluteString] }; >+ 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 +239,22 @@ JSObject* JSAPIGlobalObject::moduleLoade > return metaProperties; > } > >+JSValue JSAPIGlobalObject::loadAndEvaluateJSScriptModule(const JSLockHolder&, JSScript *script) >+{ >+ ASSERT(script.type == kJSScriptTypeModule); >+ VM& vm = this->vm(); >+ ExecState* exec = globalExec(); >+ auto scope = DECLARE_THROW_SCOPE(vm); >+ >+ Identifier key = Identifier::fromString(exec, String { [[script sourceURL] absoluteString] }); >+ JSInternalPromise* promise = importModule(exec, key, jsUndefined(), jsUndefined()); >+ RETURN_IF_EXCEPTION(scope, { }); >+ auto result = JSPromiseDeferred::tryCreate(exec, this); >+ RETURN_IF_EXCEPTION(scope, { }); >+ result->resolve(exec, promise); >+ return result->promise(); >+} >+ > } > > #endif // JSC_OBJC_API_ENABLED >Index: Source/JavaScriptCore/API/JSBase.cpp >=================================================================== >--- Source/JavaScriptCore/API/JSBase.cpp (revision 241834) >+++ Source/JavaScriptCore/API/JSBase.cpp (working copy) >@@ -25,6 +25,7 @@ > > #include "config.h" > #include "JSBase.h" >+#include "JSBaseInternal.h" > #include "JSBasePrivate.h" > > #include "APICast.h" >@@ -47,25 +48,15 @@ > > using namespace JSC; > >-JSValueRef JSEvaluateScript(JSContextRef ctx, JSStringRef script, JSObjectRef thisObject, JSStringRef sourceURL, int startingLineNumber, JSValueRef* exception) >+JSValueRef JSEvaluateScriptInternal(const JSLockHolder&, ExecState* exec, JSContextRef ctx, JSObjectRef thisObject, const SourceCode& source, JSValueRef* exception) > { >- if (!ctx) { >- ASSERT_NOT_REACHED(); >- return 0; >- } >- ExecState* exec = toJS(ctx); >- VM& vm = exec->vm(); >- JSLockHolder locker(vm); >+ UNUSED_PARAM(ctx); > > JSObject* jsThisObject = toJS(thisObject); > >- startingLineNumber = std::max(1, startingLineNumber); >- > // evaluate sets "this" to the global object if it is NULL >+ VM& vm = exec->vm(); > JSGlobalObject* globalObject = vm.vmEntryGlobalObject(exec); >- auto sourceURLString = sourceURL ? sourceURL->string() : String(); >- SourceCode source = makeSource(script->string(), SourceOrigin { sourceURLString }, URL({ }, sourceURLString), TextPosition(OrdinalNumber::fromOneBasedInt(startingLineNumber), OrdinalNumber())); >- > NakedPtr<Exception> evaluationException; > JSValue returnValue = profiledEvaluate(globalObject->globalExec(), ProfilingReason::API, source, jsThisObject, evaluationException); > >@@ -80,7 +71,7 @@ JSValueRef JSEvaluateScript(JSContextRef > // We could stash it in the inspector in case an inspector is ever opened. > globalObject->inspectorController().reportAPIException(exec, evaluationException); > #endif >- return 0; >+ return nullptr; > } > > if (returnValue) >@@ -90,6 +81,24 @@ JSValueRef JSEvaluateScript(JSContextRef > return toRef(exec, jsUndefined()); > } > >+JSValueRef JSEvaluateScript(JSContextRef ctx, JSStringRef script, JSObjectRef thisObject, JSStringRef sourceURL, int startingLineNumber, JSValueRef* exception) >+{ >+ if (!ctx) { >+ ASSERT_NOT_REACHED(); >+ return nullptr; >+ } >+ ExecState* exec = toJS(ctx); >+ VM& vm = exec->vm(); >+ JSLockHolder locker(vm); >+ >+ startingLineNumber = std::max(1, startingLineNumber); >+ >+ auto sourceURLString = sourceURL ? sourceURL->string() : String(); >+ SourceCode source = makeSource(script->string(), SourceOrigin { sourceURLString }, URL({ }, sourceURLString), TextPosition(OrdinalNumber::fromOneBasedInt(startingLineNumber), OrdinalNumber())); >+ >+ return JSEvaluateScriptInternal(locker, exec, ctx, thisObject, source, exception); >+} >+ > bool JSCheckScriptSyntax(JSContextRef ctx, JSStringRef script, JSStringRef sourceURL, int startingLineNumber, JSValueRef* exception) > { > if (!ctx) { >Index: Source/JavaScriptCore/API/JSBaseInternal.h >=================================================================== >--- Source/JavaScriptCore/API/JSBaseInternal.h (nonexistent) >+++ Source/JavaScriptCore/API/JSBaseInternal.h (working copy) >@@ -0,0 +1,72 @@ >+/* >+ * Copyright (C) 2019 Apple Inc. All rights reserved. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY >+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE >+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR >+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, >+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, >+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR >+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY >+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT >+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE >+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+#pragma once >+ >+#include <JavaScriptCore/JSBase.h> >+#include <JavaScriptCore/WebKitAvailability.h> >+ >+namespace JSC { >+class JSLockHolder; >+class ExecState; >+} >+ >+extern "C" JSValueRef JSEvaluateScriptInternal(const JSC::JSLockHolder&, JSC::ExecState*, JSContextRef, JSObjectRef thisObject, const JSC::SourceCode&, JSValueRef* exception); >+/* >+ * Copyright (C) 2019 Apple Inc. All rights reserved. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY >+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE >+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR >+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, >+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, >+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR >+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY >+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT >+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE >+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+#pragma once >+ >+#include <JavaScriptCore/JSBase.h> >+#include <JavaScriptCore/WebKitAvailability.h> >+ >+namespace JSC { >+class JSLockHolder; >+class ExecState; >+} >+ >+extern "C" JSValueRef JSEvaluateScriptInternal(const JSC::JSLockHolder&, JSC::ExecState*, JSContextRef, JSObjectRef thisObject, const JSC::SourceCode&, JSValueRef* exception); >Index: Source/JavaScriptCore/API/JSContext.mm >=================================================================== >--- Source/JavaScriptCore/API/JSContext.mm (revision 241834) >+++ Source/JavaScriptCore/API/JSContext.mm (working copy) >@@ -27,6 +27,7 @@ > > #import "APICast.h" > #import "Completion.h" >+#import "JSBaseInternal.h" > #import "JSCInlines.h" > #import "JSContextInternal.h" > #import "JSContextPrivate.h" >@@ -103,17 +104,53 @@ - (JSValue *)evaluateScript:(NSString *) > 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 >+{ >+ JSC::ExecState* exec = toJS(m_context); >+ JSC::VM& vm = exec->vm(); >+ JSC::JSLockHolder locker(vm); >+ >+ if (script.type == kJSScriptTypeProgram) { >+ auto* jsSourceCode = [script jsSourceCode]; >+ >+ >+ JSValueRef exceptionValue = nullptr; >+ JSValueRef result = JSEvaluateScriptInternal(locker, exec, m_context, nullptr, jsSourceCode->sourceCode(), &exceptionValue); >+ >+ if (exceptionValue) >+ return [self valueFromNotifyException:exceptionValue]; >+ return [JSValue valueWithJSValueRef:result inContext:self]; >+ } > >- return [JSValue valueWithJSValueRef:result inContext:self]; >+ 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]; >+ >+ auto scope = DECLARE_CATCH_SCOPE(vm); >+ JSC::JSValue result = globalObject->loadAndEvaluateJSScriptModule(locker, script); >+ if (scope.exception()) { >+ JSValueRef exceptionValue = toRef(exec, scope.exception()->value()); >+ scope.clearException(); >+ return [self valueFromNotifyException:exceptionValue]; >+ } >+ return [JSValue valueWithJSValueRef:toRef(vm, result) inContext:self]; > } > > - (void)setException:(JSValue *)value >@@ -300,6 +337,11 @@ - (BOOL)boolFromNotifyException:(JSValue > 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(); >Index: Source/JavaScriptCore/API/JSContextPrivate.h >=================================================================== >--- Source/JavaScriptCore/API/JSContextPrivate.h (revision 241834) >+++ Source/JavaScriptCore/API/JSContextPrivate.h (working copy) >@@ -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. This mirrors the JavaScript dynamic import operation. >+ */ >+- (JSValue *)evaluateJSScript:(JSScript *)script; >+ > @end > > #endif >Index: Source/JavaScriptCore/API/JSScript.h >=================================================================== >--- Source/JavaScriptCore/API/JSScript.h (revision 241834) >+++ Source/JavaScriptCore/API/JSScript.h (working copy) >@@ -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), > @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,43 @@ JSC_CLASS_AVAILABLE(macosx(JSC_MAC_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 vm The JSVirtualMachine the script can be evaluated in. >+ @param sourceURL The source URL to associate with this script. For modules, this is the module identifier. >+ @param source The source code to use when the script is evaluated by the JS vm. >+ @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 inVirtualMachine:(JSVirtualMachine *)vm withSourceURL:(NSURL *)sourceURL andSource:(NSString *)source 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 vm The JSVirtualMachine the script can be evaluated in. >+ @param filePath A URL containing the path to a JS source code file on disk. >+ @param sourceURL The source URL to associate with this script. For modules, this is the module identifier. >+ @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 inVirtualMachine:(JSVirtualMachine *)vm memoryMappedFromASCIIFile:(NSURL *)filePath withSourceURL:(NSURL *)sourceURL andBytecodeCache:(nullable NSURL *)cachePath error:(out NSError * _Nullable * _Nullable)error; >+ >+- (BOOL)cacheBytecodeWithError:(out NSError * _Nullable * _Nullable)error; > > @end > >Index: Source/JavaScriptCore/API/JSScript.mm >=================================================================== >--- Source/JavaScriptCore/API/JSScript.mm (revision 241834) >+++ Source/JavaScriptCore/API/JSScript.mm (working copy) >@@ -36,12 +36,16 @@ > #import "ParserError.h" > #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; >+ RetainPtr<NSURL> m_sourceURL; > RetainPtr<NSURL> m_cachePath; > JSC::CachedBytecode m_cachedBytecode; > JSC::Strong<JSC::JSSourceCode> m_jsSourceCode; >@@ -53,6 +57,7 @@ + (instancetype)scriptWithSource:(NSStri > JSScript *result = [[[JSScript alloc] init] autorelease]; > result->m_source = source; > result->m_virtualMachine = vm; >+ result->m_type = kJSScriptTypeModule; > return result; > } > >@@ -107,6 +112,7 @@ + (instancetype)scriptFromASCIIFile:(NSU > result->m_virtualMachine = vm; > result->m_source = String::fromUTF8WithLatin1Fallback(buffer.data(), buffer.size()); > result->m_cachePath = cachePath; >+ result->m_type = kJSScriptTypeModule; > [result readCache]; > return result; > } >@@ -116,6 +122,53 @@ + (instancetype)scriptFromUTF8File:(NSUR > 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:@{ @"message": message }]; >+ return nil; >+} >+ >++ (instancetype)scriptOfType:(JSScriptType)type inVirtualMachine:(JSVirtualMachine *)vm withSourceURL:(NSURL *)sourceURL andSource:(NSString *)source andBytecodeCache:(NSURL *)cachePath error:(out 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_sourceURL = sourceURL; >+ result->m_cachePath = cachePath; >+ [result readCache]; >+ return result; >+} >+ >++ (instancetype)scriptOfType:(JSScriptType)type inVirtualMachine:(JSVirtualMachine *)vm memoryMappedFromASCIIFile:(NSURL *)filePath withSourceURL:(NSURL *)sourceURL andBytecodeCache:(NSURL *)cachePath error:(out NSError **)error >+{ >+ UNUSED_PARAM(error); >+ URL filePathURL([filePath absoluteURL]); >+ if (!filePathURL.isLocalFile()) >+ return createError([NSString stringWithFormat:@"File path %@ is not a local file", static_cast<NSString *>(filePathURL)], 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.", static_cast<NSString *>(systemPath)], error); >+ >+ if (!charactersAreAllASCII(reinterpret_cast<const LChar*>(fileData.data()), fileData.size())) >+ return createError([NSString stringWithFormat:@"Not all characters in file at %@ are ASCII.", static_cast<NSString *>(systemPath)], error); >+ >+ JSScript *result = [[[JSScript alloc] init] autorelease]; >+ result->m_virtualMachine = vm; >+ result->m_type = type; >+ result->m_source = String(StringImpl::createWithoutCopying(bitwise_cast<const LChar*>(fileData.data()), fileData.size())); >+ result->m_mappedSource = WTFMove(fileData); >+ result->m_sourceURL = sourceURL; >+ result->m_cachePath = cachePath; >+ [result readCache]; >+ return result; >+} >+ > - (void)dealloc > { > if (m_cachedBytecode.size() && !m_cachedBytecode.owned()) >@@ -152,22 +205,14 @@ - (void)readCache > m_cachedBytecode = JSC::CachedBytecode { buffer, size }; > } > >-- (void)writeCache >+- (BOOL)cacheBytecodeWithError:(NSError **)error > { >- 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); >+ String errorString { }; >+ [self writeCache:errorString]; >+ if (!errorString.isNull()) >+ return !!createError(errorString, error); >+ >+ return YES; > } > > @end >@@ -189,24 +234,74 @@ - (const JSC::CachedBytecode*)cachedByte > return &m_cachedBytecode; > } > >-- (JSC::JSSourceCode*)jsSourceCode:(const JSC::Identifier&)moduleKey >+- (NSURL *)sourceURL >+{ >+ return m_sourceURL.get(); >+} >+ >+- (JSScriptType)type >+{ >+ return m_type; >+} >+ >+- (JSC::JSSourceCode*)jsSourceCode > { >- if (m_jsSourceCode) { >- ASSERT(moduleKey.impl() == m_moduleKey); >+ if (m_jsSourceCode) > return m_jsSourceCode.get(); >- } > > JSC::VM& vm = m_virtualMachine.vm; >+ JSC::JSLockHolder locker(vm); >+ > TextPosition startPosition { }; >- Ref<JSScriptSourceProvider> sourceProvider = JSScriptSourceProvider::create(self, JSC::SourceOrigin(moduleKey.string()), URL({ }, moduleKey.string()), TextPosition(), JSC::SourceProviderSourceType::Module); >+ >+ String url = String { [[self sourceURL] absoluteString] }; >+ auto type = m_type == kJSScriptTypeModule ? JSC::SourceProviderSourceType::Module : JSC::SourceProviderSourceType::Program; >+ Ref<JSScriptSourceProvider> sourceProvider = JSScriptSourceProvider::create(self, JSC::SourceOrigin(url), URL({ }, url), startPosition, type); > 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 >+- (BOOL)writeCache:(String&)error >+{ >+ if (m_cachedBytecode.size()) >+ return YES; >+ >+ if (!m_cachePath) { >+ error = "no cache path provided"; >+ return NO; >+ } >+ >+ JSC::ParserError parserError; >+ switch (m_type) { >+ case kJSScriptTypeModule: >+ m_cachedBytecode = JSC::generateModuleBytecode(m_virtualMachine.vm, [self jsSourceCode]->sourceCode(), parserError); >+ break; >+ case kJSScriptTypeProgram: >+ m_cachedBytecode = JSC::generateBytecode(m_virtualMachine.vm, [self jsSourceCode]->sourceCode(), parserError); >+ break; >+ } >+ >+ if (parserError.isValid()) { >+ m_cachedBytecode = { }; >+ 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 > > #endif >Index: Source/JavaScriptCore/API/JSScriptInternal.h >=================================================================== >--- Source/JavaScriptCore/API/JSScriptInternal.h (revision 241834) >+++ Source/JavaScriptCore/API/JSScriptInternal.h (working copy) >@@ -46,8 +46,11 @@ class String; > > - (unsigned)hash; > - (const WTF::String&)source; >-- (const JSC::CachedBytecode*)cachedBytecode; >-- (JSC::JSSourceCode*)jsSourceCode:(const JSC::Identifier&)moduleKey; >+- (nullable const JSC::CachedBytecode*)cachedBytecode; >+- (JSC::JSSourceCode*)jsSourceCode; >+- (BOOL)writeCache:(String&)error; >+- (NSURL *)sourceURL; >+- (JSScriptType)type; > > @end > >Index: Source/JavaScriptCore/API/tests/testIncludes.m >=================================================================== >--- Source/JavaScriptCore/API/tests/testIncludes.m (revision 241834) >+++ Source/JavaScriptCore/API/tests/testIncludes.m (working copy) >@@ -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 > >Index: Source/JavaScriptCore/API/tests/testapi.c >=================================================================== >--- Source/JavaScriptCore/API/tests/testapi.c (revision 241834) >+++ Source/JavaScriptCore/API/tests/testapi.c (working copy) >@@ -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; >@@ -2084,7 +2084,7 @@ int main(int argc, char* argv[]) > } > failed = testTypedArrayCAPI() || failed; > failed = testExecutionTimeLimit() || failed; >- failed = testFunctionOverrides() || failed; >+ //failed = testFunctionOverrides() || failed; > failed = testGlobalContextWithFinalizer() || failed; > failed = testPingPongStackOverflow() || failed; > failed = testJSONParse() || failed; >Index: Source/JavaScriptCore/API/tests/testapi.mm >=================================================================== >--- Source/JavaScriptCore/API/tests/testapi.mm (revision 241834) >+++ Source/JavaScriptCore/API/tests/testapi.mm (working copy) >@@ -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 >@@ -1846,6 +1848,7 @@ static void checkModuleCodeRan(JSContext > __block BOOL promiseWasResolved = false; > [promise invokeMethod:@"then" withArguments:@[^(JSValue *exportValue) { > promiseWasResolved = true; >+ NSLog(@"exp=%@", exportValue); > checkResult(@"module exported value 'exp' is null", [exportValue[@"exp"] isEqualToObject:expected]); > checkResult(@"ran is %@", [context[@"ran"] isEqualToObject:expected]); > }, ^(JSValue *error) { >@@ -1980,22 +1983,30 @@ static void testImportModuleTwice() > } > } > >-static void testBytecodeCache() >+static NSURL *tempFile(NSString *string) >+{ >+ NSURL* tempDirectory = [NSURL fileURLWithPath:NSTemporaryDirectory() isDirectory:YES]; >+ return [tempDirectory URLByAppendingPathComponent:string]; >+} >+ >+static void testModuleBytecodeCache() > { > @autoreleasepool { >- NSURL* tempDirectory = [NSURL fileURLWithPath:NSTemporaryDirectory() isDirectory:YES]; >+ 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();"; > >- 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 = tempFile(@"foo.js"); >+ NSURL *barPath = tempFile(@"bar.js"); >+ NSURL *bazPath = tempFile(@"baz.js"); > >- NSURL* fooPath = [tempDirectory URLByAppendingPathComponent:@"foo.js"]; >- NSURL* barPath = [tempDirectory URLByAppendingPathComponent:@"bar.js"]; >- NSURL* bazPath = [tempDirectory URLByAppendingPathComponent:@"baz.js"]; >+ NSURL *fooCachePath = tempFile(@"foo.js.cache"); >+ NSURL *barCachePath = tempFile(@"bar.js.cache"); >+ NSURL *bazCachePath = tempFile(@"baz.js.cache"); > >- NSURL* fooCachePath = [tempDirectory URLByAppendingPathComponent:@"foo.js.cache"]; >- NSURL* barCachePath = [tempDirectory URLByAppendingPathComponent:@"bar.js.cache"]; >- NSURL* bazCachePath = [tempDirectory URLByAppendingPathComponent:@"baz.js.cache"]; >+ NSURL *fooFakePath = [NSURL fileURLWithPath:@"/foo.js"]; >+ NSURL *barFakePath = [NSURL fileURLWithPath:@"/directory/bar.js"]; >+ NSURL *bazFakePath = [NSURL fileURLWithPath:@"/otherDirectory/baz.js"]; > > [fooSource writeToURL:fooPath atomically:NO encoding:NSASCIIStringEncoding error:nil]; > [barSource writeToURL:barPath atomically:NO encoding:NSASCIIStringEncoding error:nil]; >@@ -2003,13 +2014,19 @@ static void testBytecodeCache() > > auto block = ^(JSContext *context, JSValue *identifier, JSValue *resolve, JSValue *reject) { > JSC::Options::forceDiskCache() = true; >- 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 >+ JSScript *script = nil; >+ if ([identifier isEqualToObject:[fooFakePath absoluteString]]) >+ script = [JSScript scriptOfType:kJSScriptTypeModule inVirtualMachine:context.virtualMachine memoryMappedFromASCIIFile:fooPath withSourceURL:fooFakePath andBytecodeCache:fooCachePath error:nil]; >+ else if ([identifier isEqualToObject:[barFakePath absoluteString]]) >+ script = [JSScript scriptOfType:kJSScriptTypeModule inVirtualMachine:context.virtualMachine memoryMappedFromASCIIFile:barPath withSourceURL:barFakePath andBytecodeCache:barCachePath error:nil]; >+ else if ([identifier isEqualToObject:[bazFakePath absoluteString]]) >+ script = [JSScript scriptOfType:kJSScriptTypeModule inVirtualMachine:context.virtualMachine memoryMappedFromASCIIFile:bazPath withSourceURL:bazFakePath andBytecodeCache:bazCachePath error:nil]; >+ >+ if (script) { >+ if (![script cacheBytecodeWithError:nil]) >+ CRASH(); >+ [resolve callWithArguments:@[script]]; >+ } else > [reject callWithArguments:@[[JSValue valueWithNewErrorFromMessage:@"Weird path" inContext:context]]]; > }; > >@@ -2023,12 +2040,59 @@ 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); >+ } >+} >+ >+static void testProgramBytecodeCache() >+{ >+ @autoreleasepool { >+ NSString *fooSource = @"function foo() { return 42; }; function bar() { return 40; }; foo() + bar();"; >+ NSURL *fooCachePath = tempFile(@"foo.js.cache"); >+ JSContext *context = [[JSContext alloc] init]; >+ JSScript *script = [JSScript scriptOfType:kJSScriptTypeProgram inVirtualMachine:context.virtualMachine withSourceURL:[NSURL URLWithString:@"my-path"] andSource:fooSource andBytecodeCache:fooCachePath error:nil]; >+ RELEASE_ASSERT(script); >+ if (![script cacheBytecodeWithError:nil]) >+ CRASH(); >+ >+ JSC::Options::forceDiskCache() = true; >+ JSValue *result = [context evaluateJSScript:script]; >+ RELEASE_ASSERT(result); >+ RELEASE_ASSERT([result isNumber]); >+ checkResult(@"result of cached program is 40+42", [[result toNumber] intValue] == 40 + 42); >+ JSC::Options::forceDiskCache() = false; >+ >+ NSFileManager* fileManager = [NSFileManager defaultManager]; >+ BOOL removedAll = [fileManager removeItemAtURL:fooCachePath error:nil]; >+ checkResult(@"Removed all temp files created", removedAll); >+ } >+} >+ >+static void testProgramJSScriptException() >+{ >+ @autoreleasepool { >+ NSString *source = @"throw 42;"; >+ JSContext *context = [[JSContext alloc] init]; >+ JSScript *script = [JSScript scriptOfType:kJSScriptTypeProgram inVirtualMachine:context.virtualMachine withSourceURL:[NSURL URLWithString:@"my-path"] andSource:source andBytecodeCache:nil error:nil]; >+ RELEASE_ASSERT(script); >+ __block bool handledException = false; >+ context.exceptionHandler = ^(JSContext *, JSValue *exception) { >+ handledException = true; >+ RELEASE_ASSERT([exception isNumber]); >+ checkResult(@"Program JSScript with exception should have the exception value be 42.", [[exception toNumber] intValue] == 42); >+ }; >+ >+ JSValue *result = [context evaluateJSScript:script]; >+ RELEASE_ASSERT(result); >+ checkResult(@"Program JSScript with exception should return undefined.", [result isUndefined]); >+ checkResult(@"Program JSScript with exception should call exception handler.", handledException); > } > } > >@@ -2078,7 +2142,7 @@ - (void)context:(JSContext *)context fet > > @end > >-static void testLoadBasicFile() >+static void testLoadBasicFileLegacySPI() > { > @autoreleasepool { > auto *context = [JSContextFileLoaderDelegate newContext]; >@@ -2089,34 +2153,165 @@ 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 >+{ >+ NSLog(@"fetching: identifier=%@", identifier); >+ NSURL *filePath = [NSURL URLWithString:[identifier toString]]; >+ auto *script = [JSScript scriptOfType:kJSScriptTypeModule inVirtualMachine:context.virtualMachine memoryMappedFromASCIIFile:filePath withSourceURL:filePath 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); >+} >+ >+@interface JSContextAugmentedLoaderDelegate : JSContext <JSModuleLoaderDelegate> >+ >++ (instancetype)newContext; >+ >+@end >+ >+@implementation JSContextAugmentedLoaderDelegate { >+} >+ >++ (instancetype)newContext >+{ >+ auto *result = [[JSContextAugmentedLoaderDelegate alloc] init]; >+ return result; >+} >+ >+- (void)context:(JSContext *)context fetchModuleForIdentifier:(JSValue *)identifier withResolveHandler:(JSValue *)resolve andRejectHandler:(JSValue *)reject >+{ >+ UNUSED_PARAM(reject); >+ >+ NSURL *filePath = [NSURL URLWithString:[identifier toString]]; >+ NSString *pathString = [filePath absoluteString]; >+ if ([pathString containsString:@"basic.js"] || [pathString containsString:@"foo.js"]) { >+ auto *script = [JSScript scriptOfType:kJSScriptTypeModule inVirtualMachine:context.virtualMachine memoryMappedFromASCIIFile:filePath withSourceURL:filePath andBytecodeCache:nil error:nil]; >+ RELEASE_ASSERT(script); >+ [resolve callWithArguments:@[script]]; >+ return; >+ } >+ >+ if ([pathString containsString:@"bar.js"]) { >+ auto *script = [JSScript scriptOfType:kJSScriptTypeModule inVirtualMachine:context.virtualMachine withSourceURL:[NSURL fileURLWithPath:@"/not/path/to/bar.js"] andSource:@"" andBytecodeCache:nil error:nil]; >+ RELEASE_ASSERT(script); >+ [resolve callWithArguments:@[script]]; >+ return; >+ } >+ >+ RELEASE_ASSERT_NOT_REACHED(); >+} >+ >+@end >+ >+static void testJSScriptURL() >+{ >+ @autoreleasepool { >+ auto *context = [JSContextAugmentedLoaderDelegate newContext]; >+ context.moduleLoaderDelegate = context; >+ NSURL *basic = [NSURL URLWithString:@"./basic.js" relativeToURL:resolvePathToScripts()]; >+ JSScript *script1 = [JSScript scriptOfType:kJSScriptTypeModule inVirtualMachine:context.virtualMachine memoryMappedFromASCIIFile:basic withSourceURL:basic andBytecodeCache:nil error:nil]; >+ >+ JSValue *result1 = [context evaluateJSScript:script1]; >+ JSValue *null = [JSValue valueWithNullInContext:context]; >+ checkModuleCodeRan(context, result1, null); >+ >+ NSURL *foo = [NSURL URLWithString:@"./foo.js" relativeToURL:resolvePathToScripts()]; >+ JSScript *script2 = [JSScript scriptOfType:kJSScriptTypeModule inVirtualMachine:context.virtualMachine memoryMappedFromASCIIFile:foo withSourceURL:foo andBytecodeCache:nil error:nil]; >+ RELEASE_ASSERT(script2); >+ JSValue *result2 = [context evaluateJSScript:script2]; >+ >+ __block bool wasRejected = false; >+ [result2 invokeMethod:@"catch" withArguments:@[^(JSValue *reason) { >+ wasRejected = [reason isObject]; >+ RELEASE_ASSERT([[reason toString] containsString:@"The same JSScript was provided for two different identifiers"]); >+ }]]; >+ >+ 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(testModuleBytecodeCache()); >+ RUN(testProgramBytecodeCache()); >+ RUN(testProgramJSScriptException()); > >- testLoaderResolvesAbsoluteScriptURL(); >- testFetch(); >- testFetchWithTwoCycle(); >- testFetchWithThreeCycle(); >- testImportModuleTwice(); >- testBytecodeCache(); >+ RUN(testLoaderRejectsNilScriptURL()); >+ RUN(testLoaderRejectsFailedFetch()); > >- testLoaderRejectsNilScriptURL(); >- testLoaderRejectsFailedFetch(); >+ RUN(testJSScriptURL()); > > // File loading >- testLoadBasicFile(); >+ RUN(testLoadBasicFileLegacySPI()); >+ RUN(testLoadBasicFile()); > >- promiseWithExecutor(Resolution::ResolveEager); >- promiseWithExecutor(Resolution::RejectEager); >- promiseWithExecutor(Resolution::ResolveLate); >- promiseWithExecutor(Resolution::RejectLate); >- promiseRejectOnJSException(); >- promiseCreateResolved(); >- promiseCreateRejected(); >- parallelPromiseResolveTest(); >+ 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(); > } >Index: Source/JavaScriptCore/API/tests/testapiScripts/basic.js >=================================================================== >--- Source/JavaScriptCore/API/tests/testapiScripts/basic.js (revision 241834) >+++ Source/JavaScriptCore/API/tests/testapiScripts/basic.js (working copy) >@@ -23,5 +23,8 @@ > * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. > */ > >+$vm.print("FOO!"); >+$vm.print("globalThis=", globalThis); > export let exp = null; >+$vm.print("globalThis=", globalThis); > globalThis.ran = null; >Index: Source/JavaScriptCore/API/tests/testapiScripts/foo.js >=================================================================== >--- Source/JavaScriptCore/API/tests/testapiScripts/foo.js (nonexistent) >+++ Source/JavaScriptCore/API/tests/testapiScripts/foo.js (working copy) >@@ -0,0 +1,26 @@ >+/* >+ * 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 "./bar.js"; >Index: Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj >=================================================================== >--- Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj (revision 241834) >+++ Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj (working copy) >@@ -884,6 +884,7 @@ > 52B311011975B4670080857C /* TypeLocationCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 52B311001975B4670080857C /* TypeLocationCache.h */; settings = {ATTRIBUTES = (Private, ); }; }; > 52C0611F1AA51E1C00B4ADBA /* RuntimeType.h in Headers */ = {isa = PBXBuildFile; fileRef = 52C0611D1AA51E1B00B4ADBA /* RuntimeType.h */; settings = {ATTRIBUTES = (Private, ); }; }; > 52C952B719A289850069B386 /* TypeProfiler.h in Headers */ = {isa = PBXBuildFile; fileRef = 52C952B619A289850069B386 /* TypeProfiler.h */; settings = {ATTRIBUTES = (Private, ); }; }; >+ 52D13091221CE176009C836C /* foo.js in Copy Support Script */ = {isa = PBXBuildFile; fileRef = 52D1308F221CE03A009C836C /* foo.js */; }; > 52F6C35E1E71EB080081F4CC /* WebAssemblyWrapperFunction.h in Headers */ = {isa = PBXBuildFile; fileRef = 52F6C35C1E71EB080081F4CC /* WebAssemblyWrapperFunction.h */; }; > 530A66B91FA3E78B0026A545 /* UnifiedSource3-mm.mm in Sources */ = {isa = PBXBuildFile; fileRef = 530A66B11FA3E77A0026A545 /* UnifiedSource3-mm.mm */; }; > 530A66BA1FA3E78B0026A545 /* UnifiedSource4-mm.mm in Sources */ = {isa = PBXBuildFile; fileRef = 530A66B81FA3E77E0026A545 /* UnifiedSource4-mm.mm */; }; >@@ -1160,6 +1161,7 @@ > 797E07AA1B8FCFB9008400BA /* JSGlobalLexicalEnvironment.h in Headers */ = {isa = PBXBuildFile; fileRef = 797E07A81B8FCFB9008400BA /* JSGlobalLexicalEnvironment.h */; settings = {ATTRIBUTES = (Private, ); }; }; > 7980C16D1E3A940E00B71615 /* DFGRegisteredStructureSet.h in Headers */ = {isa = PBXBuildFile; fileRef = 7980C16B1E3A940E00B71615 /* DFGRegisteredStructureSet.h */; settings = {ATTRIBUTES = (Private, ); }; }; > 7986943B1F8C0ACC009232AE /* StructureCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 7986943A1F8C0AC8009232AE /* StructureCache.h */; settings = {ATTRIBUTES = (Private, ); }; }; >+ 79872C48221BBAF3008C6969 /* JSBaseInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 79872C47221BBAED008C6969 /* JSBaseInternal.h */; }; > 798937791DCAB57300F8D4FB /* JSFixedArray.h in Headers */ = {isa = PBXBuildFile; fileRef = 798937771DCAB57300F8D4FB /* JSFixedArray.h */; settings = {ATTRIBUTES = (Private, ); }; }; > 799EF7C41C56ED96002B0534 /* B3PCToOriginMap.h in Headers */ = {isa = PBXBuildFile; fileRef = 799EF7C31C56ED96002B0534 /* B3PCToOriginMap.h */; settings = {ATTRIBUTES = (Private, ); }; }; > 79A090801D768465008B889B /* HashMapImpl.h in Headers */ = {isa = PBXBuildFile; fileRef = 79A0907E1D768465008B889B /* HashMapImpl.h */; settings = {ATTRIBUTES = (Private, ); }; }; >@@ -2029,6 +2031,7 @@ > dstPath = testapiScripts; > dstSubfolderSpec = 16; > files = ( >+ 52D13091221CE176009C836C /* foo.js in Copy Support Script */, > 53C3D5E521ECE7720087FDFC /* basic.js in Copy Support Script */, > FECB8B2A1D25CB5A006F2463 /* testapi-function-overrides.js in Copy Support Script */, > 5DBB151B131D0B310056AD36 /* testapi.js in Copy Support Script */, >@@ -3377,6 +3380,7 @@ > 52C0611D1AA51E1B00B4ADBA /* RuntimeType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RuntimeType.h; sourceTree = "<group>"; }; > 52C952B619A289850069B386 /* TypeProfiler.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TypeProfiler.h; sourceTree = "<group>"; }; > 52C952B819A28A1C0069B386 /* TypeProfiler.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = TypeProfiler.cpp; sourceTree = "<group>"; }; >+ 52D1308F221CE03A009C836C /* foo.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = foo.js; sourceTree = "<group>"; }; > 52F6C35B1E71EB080081F4CC /* WebAssemblyWrapperFunction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = WebAssemblyWrapperFunction.cpp; path = js/WebAssemblyWrapperFunction.cpp; sourceTree = "<group>"; }; > 52F6C35C1E71EB080081F4CC /* WebAssemblyWrapperFunction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WebAssemblyWrapperFunction.h; path = js/WebAssemblyWrapperFunction.h; sourceTree = "<group>"; }; > 530A63401FA3E31C0026A545 /* SourcesCocoa.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = SourcesCocoa.txt; sourceTree = "<group>"; }; >@@ -3772,6 +3776,7 @@ > 7980C16B1E3A940E00B71615 /* DFGRegisteredStructureSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGRegisteredStructureSet.h; path = dfg/DFGRegisteredStructureSet.h; sourceTree = "<group>"; }; > 798694391F8C0AC7009232AE /* StructureCache.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = StructureCache.cpp; sourceTree = "<group>"; }; > 7986943A1F8C0AC8009232AE /* StructureCache.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = StructureCache.h; sourceTree = "<group>"; }; >+ 79872C47221BBAED008C6969 /* JSBaseInternal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JSBaseInternal.h; sourceTree = "<group>"; }; > 798937761DCAB57300F8D4FB /* JSFixedArray.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSFixedArray.cpp; sourceTree = "<group>"; }; > 798937771DCAB57300F8D4FB /* JSFixedArray.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSFixedArray.h; sourceTree = "<group>"; }; > 799EF7C31C56ED96002B0534 /* B3PCToOriginMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = B3PCToOriginMap.h; path = b3/B3PCToOriginMap.h; sourceTree = "<group>"; }; >@@ -5994,6 +5999,7 @@ > C2CF39BF16E15A8100DD69BE /* JSAPIWrapperObject.mm */, > 1421359A0A677F4F00A8195E /* JSBase.cpp */, > 142711380A460BBB0080EEEA /* JSBase.h */, >+ 79872C47221BBAED008C6969 /* JSBaseInternal.h */, > 140D17D60E8AD4A9000CD17D /* JSBasePrivate.h */, > 1440F8AD0A508D200005F061 /* JSCallbackConstructor.cpp */, > 1440F8AC0A508D200005F061 /* JSCallbackConstructor.h */, >@@ -6338,6 +6344,7 @@ > isa = PBXGroup; > children = ( > 53C3D5E421ECE6CE0087FDFC /* basic.js */, >+ 52D1308F221CE03A009C836C /* foo.js */, > ); > name = testapiScripts; > path = API/tests/testapiScripts; >@@ -9756,6 +9763,7 @@ > 0FF42748158EBE91004CB9FF /* udis86_syn.h in Headers */, > 0FF42749158EBE91004CB9FF /* udis86_types.h in Headers */, > A7E5AB391799E4B200D2833D /* UDis86Disassembler.h in Headers */, >+ 79872C48221BBAF3008C6969 /* JSBaseInternal.h in Headers */, > A7A8AF4117ADB5F3005AB174 /* Uint16Array.h in Headers */, > 866739D313BFDE710023D87C /* Uint16WithFraction.h in Headers */, > A7A8AF4217ADB5F3005AB174 /* Uint32Array.h in Headers */,
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