WebKit Bugzilla
Attachment 362635 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
b-backup.diff (text/plain), 62.89 KB, created by
Saam Barati
on 2019-02-21 13:12:29 PST
(
hide
)
Description:
patch
Filename:
MIME Type:
Creator:
Saam Barati
Created:
2019-02-21 13:12:29 PST
Size:
62.89 KB
patch
obsolete
>Index: Source/JavaScriptCore/ChangeLog >=================================================================== >--- Source/JavaScriptCore/ChangeLog (revision 241874) >+++ Source/JavaScriptCore/ChangeLog (working copy) >@@ -1,3 +1,92 @@ >+2019-02-21 Saam Barati <sbarati@apple.com> >+ >+ Update JSScript SPI based on feedback >+ https://bugs.webkit.org/show_bug.cgi?id=194517 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ This patch updates the JSScript SPI in the following ways: >+ - JSScript can now represent both modules and programs. This is a property >+ of the script determined during creation. >+ - JSScript now takes a sourceURL during construction. For modules, this acts >+ as the module identifier. >+ - JSScript now has SPI for writing the cache out to disk. We don't do this >+ automatically. >+ - JSScript will load the bytecode cache on creation if it exists. >+ - We retrofit these new requirements on the prior JSScript SPI that >+ we're going to remove as soon as we can: https://bugs.webkit.org/show_bug.cgi?id=194909. >+ Previous SPI assumes all JSScripts are modules. Previous SPI also assigns >+ a sourceURL to the JSScript based on what the module loader decided the >+ identifier should be. We'll remove this once we remove the old SPI. >+ >+ This patch also adds SPI to JSContext to evaluate a JSScript. For modules, >+ this is like returning the result of doing dynamic import. For programs, >+ this does normal program evaluation. >+ >+ This patch also fixes a bug in generateBytecode/generateModuleBytecode where >+ we would try to cache the bytecode even if recursivelyGenerateUnlinkedCodeBlock >+ returned null. E.g, if the script had a syntax error. >+ >+ When writing tests, I also discovered that someone previously broke >+ testapi. This patch also fixes those failures. They were broken when >+ we switched to using a testapiScripts directory to hold our test .js >+ scripts. >+ >+ * API/JSAPIGlobalObject.h: >+ * API/JSAPIGlobalObject.mm: >+ (JSC::JSAPIGlobalObject::moduleLoaderResolve): >+ (JSC::JSAPIGlobalObject::moduleLoaderFetch): >+ (JSC::JSAPIGlobalObject::loadAndEvaluateJSScriptModule): >+ * API/JSBase.cpp: >+ (JSEvaluateScriptInternal): >+ (JSEvaluateScript): >+ * API/JSBaseInternal.h: Added. >+ * API/JSContext.mm: >+ (-[JSContext evaluateScript:withSourceURL:]): >+ (-[JSContext evaluateJSScript:]): >+ * API/JSContextPrivate.h: >+ * API/JSScript.h: >+ * API/JSScript.mm: >+ (+[JSScript scriptWithSource:inVirtualMachine:]): >+ (+[JSScript scriptFromASCIIFile:inVirtualMachine:withCodeSigning:andBytecodeCache:]): >+ (createError): >+ (+[JSScript scriptOfType:inVirtualMachine:withSourceURL:andSource:andBytecodeCache:error:]): >+ (+[JSScript scriptOfType:inVirtualMachine:memoryMappedFromASCIIFile:withSourceURL:andBytecodeCache:error:]): >+ (-[JSScript cacheBytecodeWithError:]): >+ (-[JSScript sourceURL]): >+ (-[JSScript type]): >+ (-[JSScript jsSourceCode]): >+ (-[JSScript writeCache:]): >+ (-[JSScript setSourceURL:]): >+ (-[JSScript forceRecreateJSSourceCode]): >+ (-[JSScript writeCache]): Deleted. >+ (-[JSScript jsSourceCode:]): Deleted. >+ * API/JSScriptInternal.h: >+ * API/tests/FunctionOverridesTest.cpp: >+ (testFunctionOverrides): >+ * API/tests/testapi.c: >+ (main): >+ * API/tests/testapi.mm: >+ (tempFile): >+ (testModuleBytecodeCache): >+ (testProgramBytecodeCache): >+ (testBytecodeCacheWithSyntaxError): >+ (testProgramJSScriptException): >+ (testLoadBasicFileLegacySPI): >+ (+[JSContextMemoryMappedLoaderDelegate newContext]): >+ (-[JSContextMemoryMappedLoaderDelegate context:fetchModuleForIdentifier:withResolveHandler:andRejectHandler:]): >+ (testLoadBasicFile): >+ (+[JSContextAugmentedLoaderDelegate newContext]): >+ (-[JSContextAugmentedLoaderDelegate context:fetchModuleForIdentifier:withResolveHandler:andRejectHandler:]): >+ (testJSScriptURL): >+ (testObjectiveCAPI): >+ (testBytecodeCache): Deleted. >+ * API/tests/testapiScripts/foo.js: Added. >+ * JavaScriptCore.xcodeproj/project.pbxproj: >+ * runtime/Completion.cpp: >+ (JSC::generateBytecode): >+ (JSC::generateModuleBytecode): >+ > 2019-02-20 Yusuke Suzuki <ysuzuki@apple.com> > > [JSC] Remove WatchpointSet creation for SymbolTable entries if VM::canUseJIT() returns false >Index: Source/JavaScriptCore/API/JSAPIGlobalObject.h >=================================================================== >--- Source/JavaScriptCore/API/JSAPIGlobalObject.h (revision 241869) >+++ Source/JavaScriptCore/API/JSAPIGlobalObject.h (working copy) >@@ -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(const JSLockHolder&, JSScript *); >+ > private: > JSAPIGlobalObject(VM& vm, Structure* structure) > : Base(vm, structure, &s_globalObjectMethodTable) >Index: Source/JavaScriptCore/API/JSAPIGlobalObject.mm >=================================================================== >--- Source/JavaScriptCore/API/JSAPIGlobalObject.mm (revision 241869) >+++ 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" >@@ -43,7 +45,6 @@ > #import "JavaScriptCore.h" > #import "ObjectConstructor.h" > #import "SourceOrigin.h" >- > #import <wtf/URL.h> > > namespace JSC { >@@ -75,12 +76,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 +169,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 +182,32 @@ 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: >+ // https://bugs.webkit.org/show_bug.cgi?id=194909 >+ 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(); >+ } >+ } else { >+ [jsScript setSourceURL:[NSURL URLWithString:static_cast<NSString *>(moduleKey.string())]]; >+ source = [jsScript forceRecreateJSSourceCode]; >+ } >+ >+ args.append(source); > call(exec, deferredPromise->JSPromiseDeferred::resolve(), args, "This should never be seen..."); > return encodedJSUndefined(); > }); >@@ -210,6 +242,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 241869) >+++ 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,36 @@ >+/* >+ * 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 241869) >+++ 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" >@@ -112,10 +113,38 @@ - (JSValue *)evaluateScript:(NSString *) > > if (exceptionValue) > return [self valueFromNotifyException:exceptionValue]; >- > return [JSValue valueWithJSValueRef:result inContext:self]; > } > >+- (JSValue *)evaluateJSScript:(JSScript *)script >+{ >+ JSC::ExecState* exec = toJS(m_context); >+ JSC::VM& vm = exec->vm(); >+ JSC::JSLockHolder locker(vm); >+ >+ if (script.type == kJSScriptTypeProgram) { >+ JSValueRef exceptionValue = nullptr; >+ JSValueRef result = JSEvaluateScriptInternal(locker, exec, m_context, nullptr, [script jsSourceCode]->sourceCode(), &exceptionValue); >+ >+ if (exceptionValue) >+ return [self valueFromNotifyException:exceptionValue]; >+ 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 [JSValue valueWithNewPromiseRejectedWithReason:[JSValue valueWithJSValueRef:exceptionValue inContext:self] inContext:self]; >+ } >+ return [JSValue valueWithJSValueRef:toRef(vm, result) inContext:self]; >+} >+ > - (void)setException:(JSValue *)value > { > JSC::ExecState* exec = toJS(m_context); >Index: Source/JavaScriptCore/API/JSContextPrivate.h >=================================================================== >--- Source/JavaScriptCore/API/JSContextPrivate.h (revision 241869) >+++ 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 241869) >+++ Source/JavaScriptCore/API/JSScript.h (working copy) >@@ -31,37 +31,84 @@ 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 > > /*! >+ This SPI is deprecated and should not be used. Use "scriptOfType:inVirtualMachine:withSourceURL:andSource:andBytecodeCache:error:" instead. >+ */ >++ (nullable instancetype)scriptWithSource:(NSString *)source inVirtualMachine:(JSVirtualMachine *)vm; >+ >+/*! >+ This SPI is deprecated and should not be used. Use "scriptOfType:inVirtualMachine:memoryMappedFromASCIIFile:withSourceURL:andBytecodeCache:error:" instead. >+ */ >++ (nullable instancetype)scriptFromASCIIFile:(NSURL *)filePath inVirtualMachine:(JSVirtualMachine *)vm withCodeSigning:(nullable NSURL *)codeSigningPath andBytecodeCache:(nullable NSURL *)cachePath; >+ >+/*! >+ This API is deprecated and should not be used. >+ */ >++ (nullable instancetype)scriptFromUTF8File:(NSURL *)filePath inVirtualMachine:(JSVirtualMachine *)vm withCodeSigning:(nullable NSURL *)codeSigningPath andBytecodeCache:(nullable NSURL *)cachePath; >+ >+/*! > @method > @abstract Create a JSScript for the specified virtual machine. >- @param source The source code to use when the script is evaluated by the JS vm. >+ @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. On creation, we use this path to load the cached bytecode off disk. If the cached bytecode at this location is stale, you should delete that file before calling this constructor. >+ @param error A description of why the script could not be created if the result is nil. > @result The new script. >+ @discussion The file at cachePath should not be externally modified for the lifecycle of vm. > */ >-+ (nullable instancetype)scriptWithSource:(NSString *)source inVirtualMachine:(JSVirtualMachine *)vm; >++ (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 filePath A URL containing the path to a JS source code file on disk. >+ @param type The type of JavaScript source. > @param vm The JSVirtualMachine the script can be evaluated in. >- @param codeSigningPath A URL containing the path to the codeSigning file for filePath on disk. >- @param cachePath A URL containing the path where the VM should cache for future execution. >+ @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. On creation, we use this path to load the cached bytecode off disk. If the cached bytecode at this location is stale, you should delete that file before calling this constructor. >+ @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, codeSigningPath, and cachePath should not be externally modified for the lifecycle of vm. Note that codeSigningPath and cachePath are not used currently, but that will change in the near future. >+ @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)scriptFromASCIIFile:(NSURL *)filePath inVirtualMachine:(JSVirtualMachine *)vm withCodeSigning:(nullable NSURL *)codeSigningPath andBytecodeCache:(nullable NSURL *)cachePath; >++ (nullable instancetype)scriptOfType:(JSScriptType)type inVirtualMachine:(JSVirtualMachine *)vm memoryMappedFromASCIIFile:(NSURL *)filePath withSourceURL:(NSURL *)sourceURL andBytecodeCache:(nullable NSURL *)cachePath error:(out NSError * _Nullable * _Nullable)error; > >+/*! >+ @method >+ @abstract Cache the bytecode for this JSScript to disk at the path passed in during creation. >+ @param error A description of why the script could not be cached if the result is FALSE. >+ */ >+- (BOOL)cacheBytecodeWithError:(out NSError * _Nullable * _Nullable)error; > > /*! >- This is deprecated and is equivalent to scriptFromASCIIFile:inVirtualMachine:withCodeSigning:andBytecodeCache:. >+ @method >+ @abstract Returns the JSScriptType of this JSScript. > */ >-+ (nullable instancetype)scriptFromUTF8File:(NSURL *)filePath inVirtualMachine:(JSVirtualMachine *)vm withCodeSigning:(nullable NSURL *)codeSigningPath andBytecodeCache:(nullable NSURL *)cachePath; >+- (JSScriptType)type; >+ >+/*! >+ @method >+ @abstract Returns the sourceURL of this JSScript. >+ */ >+- (NSURL *)sourceURL; > > @end > >Index: Source/JavaScriptCore/API/JSScript.mm >=================================================================== >--- Source/JavaScriptCore/API/JSScript.mm (revision 241869) >+++ 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; > } > >@@ -90,12 +95,13 @@ static bool fillBufferWithContentsOfFile > > + (instancetype)scriptFromASCIIFile:(NSURL *)filePath inVirtualMachine:(JSVirtualMachine *)vm withCodeSigning:(NSURL *)codeSigningPath andBytecodeCache:(NSURL *)cachePath > { >- // FIXME: This should check codeSigning. > UNUSED_PARAM(codeSigningPath); >+ UNUSED_PARAM(cachePath); >+ > URL filePathURL([filePath absoluteURL]); > if (!filePathURL.isLocalFile()) > return nil; >- // FIXME: This should mmap the contents of the file instead of copying it into dirty memory. >+ > Vector<LChar> buffer; > if (!fillBufferWithContentsOfFile(filePathURL.fileSystemPath(), buffer)) > return nil; >@@ -106,8 +112,7 @@ + (instancetype)scriptFromASCIIFile:(NSU > JSScript *result = [[[JSScript alloc] init] autorelease]; > result->m_virtualMachine = vm; > result->m_source = String::fromUTF8WithLatin1Fallback(buffer.data(), buffer.size()); >- result->m_cachePath = cachePath; >- [result readCache]; >+ result->m_type = kJSScriptTypeModule; > return result; > } > >@@ -116,6 +121,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 +204,26 @@ - (void)readCache > 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()) { >+ createError(errorString, error); >+ return NO; >+ } > >- 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; >+} >+ >+- (NSURL *)sourceURL >+{ >+ return m_sourceURL.get(); >+} >+ >+- (JSScriptType)type >+{ >+ return m_type; > } > > @end >@@ -189,24 +245,75 @@ - (const JSC::CachedBytecode*)cachedByte > return &m_cachedBytecode; > } > >-- (JSC::JSSourceCode*)jsSourceCode:(const JSC::Identifier&)moduleKey >+- (JSC::JSSourceCode*)jsSourceCode > { >- if (m_jsSourceCode) { >- ASSERT(moduleKey.impl() == m_moduleKey); >+ if (m_jsSourceCode) > return m_jsSourceCode.get(); >+ >+ return [self forceRecreateJSSourceCode]; >+} >+ >+- (BOOL)writeCache:(String&)error >+{ >+ if (m_cachedBytecode.size()) >+ return YES; >+ >+ if (!m_cachePath) { >+ error = "No cache was path provided during construction of this JSScript."_s; >+ 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 = makeString("Unable to generate bytecode for this JSScript because of a parser error: ", parserError.message()); >+ 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."_s; >+ else >+ write(fd, m_cachedBytecode.data(), m_cachedBytecode.size()); >+ close(fd); >+ return !returnCode; >+} >+ >+- (void)setSourceURL:(NSURL *)url >+{ >+ m_sourceURL = url; >+} > >+- (JSC::JSSourceCode*)forceRecreateJSSourceCode >+{ > 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 > >- > #endif >Index: Source/JavaScriptCore/API/JSScriptInternal.h >=================================================================== >--- Source/JavaScriptCore/API/JSScriptInternal.h (revision 241869) >+++ Source/JavaScriptCore/API/JSScriptInternal.h (working copy) >@@ -46,8 +46,12 @@ 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; >+// FIXME: Remove this once we require sourceURL upon creation: https://bugs.webkit.org/show_bug.cgi?id=194909 >+- (JSC::JSSourceCode*)forceRecreateJSSourceCode; >+- (BOOL)writeCache:(String&)error; >+- (void)setSourceURL:(NSURL *)url; > > @end > >Index: Source/JavaScriptCore/API/tests/FunctionOverridesTest.cpp >=================================================================== >--- Source/JavaScriptCore/API/tests/FunctionOverridesTest.cpp (revision 241869) >+++ Source/JavaScriptCore/API/tests/FunctionOverridesTest.cpp (working copy) >@@ -44,7 +44,7 @@ int testFunctionOverrides() > > const char* oldFunctionOverrides = Options::functionOverrides(); > >- Options::functionOverrides() = "testapi-function-overrides.js"; >+ Options::functionOverrides() = "./testapiScripts/testapi-function-overrides.js"; > JSC::FunctionOverrides::reinstallOverrides(); > > JSGlobalContextRef context = JSGlobalContextCreateInGroup(nullptr, nullptr); >Index: Source/JavaScriptCore/API/tests/testapi.c >=================================================================== >--- Source/JavaScriptCore/API/tests/testapi.c (revision 241869) >+++ Source/JavaScriptCore/API/tests/testapi.c (working copy) >@@ -40,11 +40,18 @@ > #include "JSScriptRefPrivate.h" > #include "JSStringRefPrivate.h" > #include "JSWeakPrivate.h" >+#if !OS(WINDOWS) >+#include <libgen.h> >+#endif >+#include <limits.h> > #include <math.h> > #include <stdio.h> > #include <stdlib.h> > #include <string.h> > #include <time.h> >+#if !OS(WINDOWS) >+#include <unistd.h> >+#endif > #include <wtf/Assertions.h> > > #if OS(WINDOWS) >@@ -67,7 +74,7 @@ > #endif > > #if JSC_OBJC_API_ENABLED >-void testObjectiveCAPI(void); >+void testObjectiveCAPI(const char*); > #endif > > int testCAPIViaCpp(const char* filter); >@@ -1380,11 +1387,19 @@ int main(int argc, char* argv[]) > SetErrorMode(0); > #endif > >-#if JSC_OBJC_API_ENABLED >- testObjectiveCAPI(); >+#if !OS(WINDOWS) >+ char resolvedPath[PATH_MAX]; >+ realpath(argv[0], resolvedPath); >+ char* newCWD = dirname(resolvedPath); >+ if (chdir(newCWD)) >+ fprintf(stdout, "Could not chdir to: %s\n", newCWD); > #endif > > const char* filter = argc > 1 ? argv[1] : NULL; >+#if JSC_OBJC_API_ENABLED >+ testObjectiveCAPI(filter); >+#endif >+ > RELEASE_ASSERT(!testCAPIViaCpp(filter)); > if (filter) > return 0; >@@ -1979,7 +1994,7 @@ int main(int argc, char* argv[]) > JSObjectMakeConstructor(context, nullClass, 0); > JSClassRelease(nullClass); > >- const char* scriptPath = "testapi.js"; >+ const char* scriptPath = "./testapiScripts/testapi.js"; > char* scriptUTF8 = createStringWithContentsOfFile(scriptPath); > if (!scriptUTF8) { > printf("FAIL: Test script could not be loaded.\n"); >@@ -2082,13 +2097,13 @@ int main(int argc, char* argv[]) > } > JSGlobalContextRelease(context); > } >- failed = testTypedArrayCAPI() || failed; >- failed = testExecutionTimeLimit() || failed; >- failed = testFunctionOverrides() || failed; >- failed = testGlobalContextWithFinalizer() || failed; >- failed = testPingPongStackOverflow() || failed; >- failed = testJSONParse() || failed; >- failed = testJSObjectGetProxyTarget() || failed; >+ failed |= testTypedArrayCAPI(); >+ failed |= testExecutionTimeLimit(); >+ failed |= testFunctionOverrides(); >+ failed |= testGlobalContextWithFinalizer(); >+ failed |= testPingPongStackOverflow(); >+ failed |= testJSONParse(); >+ failed |= testJSObjectGetProxyTarget(); > > // Clear out local variables pointing at JSObjectRefs to allow their values to be collected > function = NULL; >Index: Source/JavaScriptCore/API/tests/testapi.mm >=================================================================== >--- Source/JavaScriptCore/API/tests/testapi.mm (revision 241869) >+++ Source/JavaScriptCore/API/tests/testapi.mm (working copy) >@@ -41,6 +41,12 @@ > #import "Regress141275.h" > #import "Regress141809.h" > >+#if __has_include(<libproc.h>) >+#define HAS_LIBPROC 1 >+#import <libproc.h> >+#else >+#define HAS_LIBPROC 0 >+#endif > #import <pthread.h> > #import <vector> > #import <wtf/MemoryFootprint.h> >@@ -54,7 +60,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 >@@ -1980,22 +1986,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 +2017,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 +2043,79 @@ 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 testBytecodeCacheWithSyntaxError() >+{ >+ auto test = [&] (auto type) { >+ @autoreleasepool { >+ NSString *fooSource = @"this is a syntax error"; >+ NSURL *fooCachePath = tempFile(@"foo.js.cache"); >+ JSContext *context = [[JSContext alloc] init]; >+ JSScript *script = [JSScript scriptOfType:type inVirtualMachine:context.virtualMachine withSourceURL:[NSURL URLWithString:@"my-path"] andSource:fooSource andBytecodeCache:fooCachePath error:nil]; >+ RELEASE_ASSERT(script); >+ NSError *error = nil; >+ if ([script cacheBytecodeWithError:&error]) >+ CRASH(); >+ RELEASE_ASSERT(error); >+ checkResult(@"Got error when trying to cache bytecode for a script with a syntax error.", [[error description] containsString:@"Unable to generate bytecode for this JSScript because of a parser error"]); >+ } >+ }; >+ test(kJSScriptTypeProgram); >+ test(kJSScriptTypeModule); >+} >+ >+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 +2165,7 @@ - (void)context:(JSContext *)context fet > > @end > >-static void testLoadBasicFile() >+static void testLoadBasicFileLegacySPI() > { > @autoreleasepool { > auto *context = [JSContextFileLoaderDelegate newContext]; >@@ -2089,34 +2176,169 @@ 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 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() >+{ >+#if HAS_LIBPROC >+ size_t count = proc_pidinfo(getpid(), PROC_PIDLISTFDS, 0, 0, 0); >+#endif >+ @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); >+ } >+#if HAS_LIBPROC >+ size_t after = proc_pidinfo(getpid(), PROC_PIDLISTFDS, 0, 0, 0); >+ checkResult(@"File descriptor count sholudn't change after context is dealloced", count == after); >+#endif >+} >+ >+@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(testBytecodeCacheWithSyntaxError()); >+ 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/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 241869) >+++ 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>"; }; >@@ -5995,6 +6000,7 @@ > C2CF39BF16E15A8100DD69BE /* JSAPIWrapperObject.mm */, > 1421359A0A677F4F00A8195E /* JSBase.cpp */, > 142711380A460BBB0080EEEA /* JSBase.h */, >+ 79872C47221BBAED008C6969 /* JSBaseInternal.h */, > 140D17D60E8AD4A9000CD17D /* JSBasePrivate.h */, > 1440F8AD0A508D200005F061 /* JSCallbackConstructor.cpp */, > 1440F8AC0A508D200005F061 /* JSCallbackConstructor.h */, >@@ -6340,6 +6346,7 @@ > isa = PBXGroup; > children = ( > 53C3D5E421ECE6CE0087FDFC /* basic.js */, >+ 52D1308F221CE03A009C836C /* foo.js */, > ); > name = testapiScripts; > path = API/tests/testapiScripts; >@@ -9758,6 +9765,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 */, >Index: Source/JavaScriptCore/runtime/Completion.cpp >=================================================================== >--- Source/JavaScriptCore/runtime/Completion.cpp (revision 241869) >+++ Source/JavaScriptCore/runtime/Completion.cpp (working copy) >@@ -103,6 +103,8 @@ CachedBytecode generateBytecode(VM& vm, > EvalContextType evalContextType = EvalContextType::None; > > UnlinkedCodeBlock* unlinkedCodeBlock = recursivelyGenerateUnlinkedCodeBlock<UnlinkedProgramCodeBlock>(vm, source, strictMode, scriptMode, debuggerMode, error, evalContextType, &variablesUnderTDZ); >+ if (!unlinkedCodeBlock) >+ return { }; > return serializeBytecode(vm, unlinkedCodeBlock, source, SourceCodeType::ProgramType, strictMode, scriptMode, debuggerMode); > } > >@@ -118,6 +120,8 @@ CachedBytecode generateModuleBytecode(VM > EvalContextType evalContextType = EvalContextType::None; > > UnlinkedCodeBlock* unlinkedCodeBlock = recursivelyGenerateUnlinkedCodeBlock<UnlinkedModuleProgramCodeBlock>(vm, source, strictMode, scriptMode, debuggerMode, error, evalContextType, &variablesUnderTDZ); >+ if (!unlinkedCodeBlock) >+ return { }; > return serializeBytecode(vm, unlinkedCodeBlock, source, SourceCodeType::ModuleType, strictMode, scriptMode, debuggerMode); > } >
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