فهرست منبع

Separate WebAssembly.compile/instantiate for streaming api in WebAssembly.compileStreaming and WebAssembly.instantiateStreaming respectively.
Fixes #3231

Michael Ferris 8 سال پیش
والد
کامیت
e866ab35da

+ 2 - 0
lib/Runtime/Base/JnDirectFields.h

@@ -289,7 +289,9 @@ ENTRY(CompileError)
 ENTRY(RuntimeError)
 ENTRY(LinkError)
 ENTRY(validate)
+ENTRY(compileStreaming)
 ENTRY(instantiate)
+ENTRY(instantiateStreaming)
 ENTRY(grow)
 ENTRY(module)
 ENTRY(instance)

+ 2 - 0
lib/Runtime/Library/JavascriptBuiltInFunctionList.h

@@ -308,8 +308,10 @@ BUILTIN(Math, Clz32, Clz32, FunctionInfo::ErrorOnNew)
 // Wasm entry points
 #ifdef ENABLE_WASM
 BUILTIN(WebAssembly, Compile, EntryCompile, FunctionInfo::ErrorOnNew)
+BUILTIN(WebAssembly, CompileStreaming, EntryCompileStreaming, FunctionInfo::ErrorOnNew)
 BUILTIN(WebAssembly, Validate, EntryValidate, FunctionInfo::ErrorOnNew)
 BUILTIN(WebAssembly, Instantiate, EntryInstantiate, FunctionInfo::ErrorOnNew)
+BUILTIN(WebAssembly, InstantiateStreaming, EntryInstantiateStreaming, FunctionInfo::ErrorOnNew)
 BUILTIN(WebAssembly, InstantiateBound, EntryInstantiateBound, FunctionInfo::ErrorOnNew)
 BUILTIN(WebAssembly, QueryResponse, EntryQueryResponse, FunctionInfo::ErrorOnNew)
 BUILTIN(WebAssemblyModule, NewInstance, NewInstance, FunctionInfo::SkipDefaultNewObject)

+ 2 - 0
lib/Runtime/Library/JavascriptLibrary.cpp

@@ -2937,8 +2937,10 @@ namespace Js
 #endif
         library->webAssemblyCompileFunction =
             library->AddFunctionToLibraryObject(webAssemblyObject, PropertyIds::compile, &WebAssembly::EntryInfo::Compile, 1);
+        library->AddFunctionToLibraryObject(webAssemblyObject, PropertyIds::compileStreaming, &WebAssembly::EntryInfo::CompileStreaming, 1);
         library->AddFunctionToLibraryObject(webAssemblyObject, PropertyIds::validate, &WebAssembly::EntryInfo::Validate, 1);
         library->AddFunctionToLibraryObject(webAssemblyObject, PropertyIds::instantiate, &WebAssembly::EntryInfo::Instantiate, 1);
+        library->AddFunctionToLibraryObject(webAssemblyObject, PropertyIds::instantiateStreaming, &WebAssembly::EntryInfo::InstantiateStreaming, 1);
         library->webAssemblyQueryResponseFunction = library->DefaultCreateFunction(&WebAssembly::EntryInfo::QueryResponse, 1, nullptr, nullptr, PropertyIds::undefined);
         library->webAssemblyInstantiateBoundFunction = library->DefaultCreateFunction(&WebAssembly::EntryInfo::InstantiateBound, 1, nullptr, nullptr, PropertyIds::undefined);
 

+ 72 - 20
lib/Runtime/Library/WebAssembly.cpp

@@ -17,7 +17,6 @@ Var WebAssembly::EntryCompile(RecyclableObject* function, CallInfo callInfo, ...
     ARGUMENTS(args, callInfo);
     AssertMsg(args.Info.Count > 0, "Should always have implicit 'this'");
     ScriptContext* scriptContext = function->GetScriptContext();
-    JavascriptLibrary* library = scriptContext->GetLibrary();
 
     Assert(!(callInfo.Flags & CallFlags_New));
     try
@@ -27,17 +26,41 @@ Var WebAssembly::EntryCompile(RecyclableObject* function, CallInfo callInfo, ...
             JavascriptError::ThrowTypeError(scriptContext, WASMERR_NeedBufferSource);
         }
 
+        WebAssemblySource src(args[1], true, scriptContext);
+        WebAssemblyModule* wasmModule = WebAssemblyModule::CreateModule(scriptContext, &src);
+        return JavascriptPromise::CreateResolvedPromise(wasmModule, scriptContext);
+    }
+    catch (JavascriptException & e)
+    {
+        return JavascriptPromise::CreateRejectedPromise(e.GetAndClear()->GetThrownObject(scriptContext), scriptContext);
+    }
+}
+
+Var WebAssembly::EntryCompileStreaming(RecyclableObject* function, CallInfo callInfo, ...)
+{
+    PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
+
+    ARGUMENTS(args, callInfo);
+    AssertMsg(args.Info.Count > 0, "Should always have implicit 'this'");
+    ScriptContext* scriptContext = function->GetScriptContext();
+    JavascriptLibrary* library = scriptContext->GetLibrary();
+
+    Assert(!(callInfo.Flags & CallFlags_New));
+    try
+    {
+        if (args.Info.Count < 2)
+        {
+            JavascriptError::ThrowTypeError(scriptContext, WASMERR_NeedResponse);
+        }
+
         // Check to see if it was a response object
         Var responsePromise = TryResolveResponse(function, args[0], args[1]);
         if (responsePromise)
         {
-            // Once we've resolved everything, come back here and create the module
+            // Once we've resolved everything, create the module
             return JavascriptPromise::CreateThenPromise((JavascriptPromise*)responsePromise, library->GetWebAssemblyCompileFunction(), library->GetThrowerFunction(), scriptContext);
         }
-
-        WebAssemblySource src(args[1], true, scriptContext);
-        WebAssemblyModule* wasmModule = WebAssemblyModule::CreateModule(scriptContext, &src);
-        return JavascriptPromise::CreateResolvedPromise(wasmModule, scriptContext);
+        JavascriptError::ThrowTypeError(scriptContext, WASMERR_NeedResponse);
     }
     catch (JavascriptException & e)
     {
@@ -52,7 +75,6 @@ Var WebAssembly::EntryInstantiate(RecyclableObject* function, CallInfo callInfo,
     ARGUMENTS(args, callInfo);
     AssertMsg(args.Info.Count > 0, "Should always have implicit 'this'");
     ScriptContext* scriptContext = function->GetScriptContext();
-    JavascriptLibrary* library = scriptContext->GetLibrary();
 
     Assert(!(callInfo.Flags & CallFlags_New));
 
@@ -70,19 +92,6 @@ Var WebAssembly::EntryInstantiate(RecyclableObject* function, CallInfo callInfo,
             importObject = args[2];
         }
 
-        // Check to see if it was a response object
-        Var responsePromise = TryResolveResponse(function, args[0], args[1]);
-        if (responsePromise)
-        {
-            // Since instantiate takes extra arguments, we have to create a bound function to carry the importsObject until the response is resolved
-            // Because function::bind() binds arguments from the left first, we have to calback a different function to reverse the order of the arguments
-            Var boundArgs[] = { library->GetWebAssemblyInstantiateBoundFunction(), args[0], importObject };
-            CallInfo boundCallInfo(CallFlags_Value, 3);
-            ArgumentReader myargs(&boundCallInfo, boundArgs);
-            RecyclableObject* boundFunction = BoundFunction::New(scriptContext, myargs);
-            return JavascriptPromise::CreateThenPromise((JavascriptPromise*)responsePromise, boundFunction, library->GetThrowerFunction(), scriptContext);
-        }
-
         if (WebAssemblyModule::Is(args[1]))
         {
             resultObject = WebAssemblyInstance::CreateInstance(WebAssemblyModule::FromVar(args[1]), importObject);
@@ -107,6 +116,49 @@ Var WebAssembly::EntryInstantiate(RecyclableObject* function, CallInfo callInfo,
     }
 }
 
+Var WebAssembly::EntryInstantiateStreaming(RecyclableObject* function, CallInfo callInfo, ...)
+{
+    PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
+
+    ARGUMENTS(args, callInfo);
+    AssertMsg(args.Info.Count > 0, "Should always have implicit 'this'");
+    ScriptContext* scriptContext = function->GetScriptContext();
+    JavascriptLibrary* library = scriptContext->GetLibrary();
+
+    Assert(!(callInfo.Flags & CallFlags_New));
+
+    try
+    {
+        if (args.Info.Count < 2)
+        {
+            JavascriptError::ThrowTypeError(scriptContext, WASMERR_NeedResponse);
+        }
+
+        // Check to see if it was a response object
+        Var responsePromise = TryResolveResponse(function, args[0], args[1]);
+        if (responsePromise)
+        {
+            Var importObject = scriptContext->GetLibrary()->GetUndefined();
+            if (args.Info.Count >= 3)
+            {
+                importObject = args[2];
+            }
+            // Since instantiate takes extra arguments, we have to create a bound function to carry the importsObject until the response is resolved
+            // Because function::bind() binds arguments from the left first, we have to calback a different function to reverse the order of the arguments
+            Var boundArgs[] = { library->GetWebAssemblyInstantiateBoundFunction(), args[0], importObject };
+            CallInfo boundCallInfo(CallFlags_Value, 3);
+            ArgumentReader myargs(&boundCallInfo, boundArgs);
+            RecyclableObject* boundFunction = BoundFunction::New(scriptContext, myargs);
+            return JavascriptPromise::CreateThenPromise((JavascriptPromise*)responsePromise, boundFunction, library->GetThrowerFunction(), scriptContext);
+        }
+        JavascriptError::ThrowTypeError(scriptContext, WASMERR_NeedResponse);
+    }
+    catch (JavascriptException & e)
+    {
+        return JavascriptPromise::CreateRejectedPromise(e.GetAndClear()->GetThrownObject(scriptContext), scriptContext);
+    }
+}
+
 Var WebAssembly::EntryInstantiateBound(RecyclableObject* function, CallInfo callInfo, ...)
 {
     PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);

+ 4 - 0
lib/Runtime/Library/WebAssembly.h

@@ -18,14 +18,18 @@ public:
     {
     public:
         static FunctionInfo Compile;
+        static FunctionInfo CompileStreaming;
         static FunctionInfo Validate;
         static FunctionInfo Instantiate;
+        static FunctionInfo InstantiateStreaming;
         static FunctionInfo InstantiateBound;
         static FunctionInfo QueryResponse;
     };
     static Var EntryCompile(RecyclableObject* function, CallInfo callInfo, ...);
+    static Var EntryCompileStreaming(RecyclableObject* function, CallInfo callInfo, ...);
     static Var EntryValidate(RecyclableObject* function, CallInfo callInfo, ...);
     static Var EntryInstantiate(RecyclableObject* function, CallInfo callInfo, ...);
+    static Var EntryInstantiateStreaming(RecyclableObject* function, CallInfo callInfo, ...);
     // The import object is the first argument, then the buffer source
     static Var EntryInstantiateBound(RecyclableObject* function, CallInfo callInfo, ...);
     static Var EntryQueryResponse(RecyclableObject* function, CallInfo callInfo, ...);

+ 38 - 32
test/wasm/response.js

@@ -101,7 +101,7 @@ function test(fn, description) {
     }).then(done);
   } catch (e) {
     // If fn doesn't return a Promise we will throw here
-    // WebAssembly.compile should always return a Promise
+    // WebAssembly.compileStreaming should always return a Promise
     testInfo.result = "Failed";
     testInfo.error = e;
     done();
@@ -114,81 +114,87 @@ function shouldThrow() {
 function ignoreError() {}
 
 test(() =>
-  WebAssembly.compile(defaultModule)
-    .then(validateDefaultCompile),
-  "WebAssembly.compile(buffer => defaultModule)"
+  WebAssembly.compileStreaming(defaultModule)
+    .then(shouldThrow, ignoreError),
+  "WebAssembly.compileStreaming(buffer => Error)"
 );
 test(() =>
-  WebAssembly.compile(new Promise((resolve, reject) => setTimeout(() => reject(new Error("Some Error")), 100)))
+  WebAssembly.compileStreaming(new Promise((resolve, reject) => setTimeout(() => reject(new Error("Some Error")), 100)))
     .then(shouldThrow, ignoreError),
-  "WebAssembly.compile(Promise => timeout Error)"
+  "WebAssembly.compileStreaming(Promise => timeout Error)"
 );
 test(() =>
-  WebAssembly.compile(Promise.reject())
+  WebAssembly.compileStreaming(Promise.reject())
     .then(shouldThrow, ignoreError),
-  "WebAssembly.compile(Promise => Empty Error)"
+  "WebAssembly.compileStreaming(Promise => Empty Error)"
 );
 test(() =>
-  WebAssembly.compile(Promise.reject(new Error("Promise.reject(new Error()")))
+  WebAssembly.compileStreaming(Promise.reject(new Error("Promise.reject(new Error()")))
     .then(shouldThrow, ignoreError),
-  "WebAssembly.compile(Promise => Error)"
+  "WebAssembly.compileStreaming(Promise => Error)"
 );
 test(() =>
-  WebAssembly.compile(Promise.resolve("Wrong type"))
+  WebAssembly.compileStreaming(Promise.resolve("Wrong type"))
     .then(shouldThrow, ignoreError),
-  "WebAssembly.compile(Promise => string)"
+  "WebAssembly.compileStreaming(Promise => string)"
 );
 test(() =>
-  WebAssembly.compile(fetch(() => defaultModule))
+  WebAssembly.compileStreaming(fetch(() => defaultModule))
     .then(validateDefaultCompile),
-  "WebAssembly.compile(fetch => defaultModule)"
+  "WebAssembly.compileStreaming(fetch => defaultModule)"
 );
 test(() =>
-  WebAssembly.compile(fetch(() => {throw new Error("Failed to fetch");}))
+  WebAssembly.compileStreaming(fetch(() => {throw new Error("Failed to fetch");}))
     .then(shouldThrow, ignoreError),
-  "WebAssembly.compile(fetch => Error)"
+  "WebAssembly.compileStreaming(fetch => Error)"
 );
 test(() =>
-  WebAssembly.compile(new Response(defaultModule))
+  WebAssembly.compileStreaming(new Response(defaultModule))
     .then(validateDefaultCompile),
-  "WebAssembly.compile(Response => defaultModule)"
+  "WebAssembly.compileStreaming(Response => defaultModule)"
 );
 test(() =>
-  WebAssembly.compile(new Response(defaultModule, true))
+  WebAssembly.compileStreaming(new Response(defaultModule, true))
     .then(shouldThrow, ignoreError),
-  "WebAssembly.compile(Response => Error)"
+  "WebAssembly.compileStreaming(Response => Error)"
 );
 
+
+test(() =>
+  WebAssembly.instantiateStreaming(defaultModule)
+    .then(shouldThrow, ignoreError),
+  "WebAssembly.instantiateStreaming(defaultModule => Error)"
+);
 test(() =>
-  WebAssembly.instantiate(fetch(() => defaultModule))
+  WebAssembly.instantiateStreaming(fetch(() => defaultModule))
     .then(validateDefaultInstantiate),
-  "WebAssembly.instantiate(fetch => defaultModule)"
+  "WebAssembly.instantiateStreaming(fetch => defaultModule)"
 );
 test(() =>
-  WebAssembly.instantiate(fetch(() => {throw new Error("Failed to fetch");}))
+  WebAssembly.instantiateStreaming(fetch(() => {throw new Error("Failed to fetch");}))
     .then(shouldThrow, ignoreError),
-  "WebAssembly.instantiate(fetch => Error)"
+  "WebAssembly.instantiateStreaming(fetch => Error)"
 );
 test(() =>
-  WebAssembly.instantiate(new Response(defaultModule))
+  WebAssembly.instantiateStreaming(new Response(defaultModule))
     .then(validateDefaultInstantiate),
-  "WebAssembly.instantiate(Response => defaultModule)"
+  "WebAssembly.instantiateStreaming(Response => defaultModule)"
 );
 test(() =>
-  WebAssembly.instantiate(new Response(defaultModule, true))
+  WebAssembly.instantiateStreaming(new Response(defaultModule, true))
     .then(shouldThrow, ignoreError),
-  "WebAssembly.instantiate(Response => Error)"
+  "WebAssembly.instantiateStreaming(Response => Error)"
 );
 
 test(() =>
-  WebAssembly.instantiate(fetch(() => defaultImportModule), defaultImportObject)
+  WebAssembly.instantiateStreaming(fetch(() => defaultImportModule), defaultImportObject)
     .then(validateDefaultImportInstantiate),
-  "WebAssembly.instantiate(fetch => defaultImportModule, defaultImportObject)"
+  "WebAssembly.instantiateStreaming(fetch => defaultImportModule, defaultImportObject)"
 );
 test(() =>
-  WebAssembly.instantiate(new Response(defaultImportModule), defaultImportObject)
+  WebAssembly.instantiateStreaming(new Response(defaultImportModule), defaultImportObject)
     .then(validateDefaultImportInstantiate),
-  "WebAssembly.instantiate(Response => defaultImportModule, defaultImportObject)"
+  "WebAssembly.instantiateStreaming(Response => defaultImportModule, defaultImportObject)"
 );
 
 allTestsQueued = true;