Title: [224985] trunk
Revision
224985
Author
[email protected]
Date
2017-11-17 13:57:09 -0800 (Fri, 17 Nov 2017)

Log Message

WebAssembly JS API: throw when a promise can't be created
https://bugs.webkit.org/show_bug.cgi?id=179826
<rdar://problem/35455813>

Reviewed by Mark Lam.

JSTests:

Test WebAssembly.{compile,instantiate} where promise creation
fails because of a stack overflow.

* wasm/js-api/promise-stack-overflow.js: Added.
(const.runNearStackLimit.f.const.t):
(async.testCompile):
(async.testInstantiate):

Source/_javascript_Core:

Failure *in* a promise causes rejection, but failure to create a
promise (because of stack overflow) isn't really spec'd (as all
stack things JS). This applies to WebAssembly.compile and
WebAssembly.instantiate.

Dan's current proposal says:

    https://littledan.github.io/spec/document/js-api/index.html#stack-overflow

    Whenever a stack overflow occurs in WebAssembly code, the same
    class of exception is thrown as for a stack overflow in
    _javascript_. The particular exception here is
    implementation-defined in both cases.

    Note: ECMAScript doesn’t specify any sort of behavior on stack
    overflow; implementations have been observed to throw RangeError,
    InternalError or Error. Any is valid here.

This is for general stack overflow within WebAssembly, not
specifically for promise creation within _javascript_, but it seems
like a stack overflow in promise creation should follow the same
rule instead of, say, swallowing the overflow and returning
undefined.

* wasm/js/WebAssemblyPrototype.cpp:
(JSC::webAssemblyCompileFunc):
(JSC::webAssemblyInstantiateFunc):

Modified Paths

Added Paths

Diff

Modified: trunk/JSTests/ChangeLog (224984 => 224985)


--- trunk/JSTests/ChangeLog	2017-11-17 21:38:11 UTC (rev 224984)
+++ trunk/JSTests/ChangeLog	2017-11-17 21:57:09 UTC (rev 224985)
@@ -1,3 +1,19 @@
+2017-11-17  JF Bastien  <[email protected]>
+
+        WebAssembly JS API: throw when a promise can't be created
+        https://bugs.webkit.org/show_bug.cgi?id=179826
+        <rdar://problem/35455813>
+
+        Reviewed by Mark Lam.
+
+        Test WebAssembly.{compile,instantiate} where promise creation
+        fails because of a stack overflow.
+
+        * wasm/js-api/promise-stack-overflow.js: Added.
+        (const.runNearStackLimit.f.const.t):
+        (async.testCompile):
+        (async.testInstantiate):
+
 2017-11-16  Yusuke Suzuki  <[email protected]>
 
         Unreviewed, mark regress-178385.js as memory exhausting

Added: trunk/JSTests/wasm/js-api/promise-stack-overflow.js (0 => 224985)


--- trunk/JSTests/wasm/js-api/promise-stack-overflow.js	                        (rev 0)
+++ trunk/JSTests/wasm/js-api/promise-stack-overflow.js	2017-11-17 21:57:09 UTC (rev 224985)
@@ -0,0 +1,37 @@
+import * as assert from '../assert.js';
+
+const module = Uint8Array.of(0x0, 0x61, 0x73, 0x6d, 0x1, 0x00, 0x00, 0x00);
+
+let promises = [];
+
+const runNearStackLimit = f => {
+    const t = () => {
+        try {
+            return t();
+        } catch (e) {
+            return f();
+        }
+    };
+    return t();
+};
+
+const touchArgument = arg => promises.push(arg);
+
+const compileMe = () => touchArgument(WebAssembly.compile(module));
+
+async function testCompile() {
+    await touchArgument(async function() {
+        runNearStackLimit(compileMe);
+    }());
+}
+
+const instantiateMe = () => touchArgument(WebAssembly.instantiate(module));
+
+async function testInstantiate() {
+    await touchArgument(async function() {
+        runNearStackLimit(instantiateMe);
+    }());
+}
+
+assert.asyncTest(testCompile());
+assert.asyncTest(testInstantiate());

Modified: trunk/Source/_javascript_Core/ChangeLog (224984 => 224985)


--- trunk/Source/_javascript_Core/ChangeLog	2017-11-17 21:38:11 UTC (rev 224984)
+++ trunk/Source/_javascript_Core/ChangeLog	2017-11-17 21:57:09 UTC (rev 224985)
@@ -1,3 +1,39 @@
+2017-11-17  JF Bastien  <[email protected]>
+
+        WebAssembly JS API: throw when a promise can't be created
+        https://bugs.webkit.org/show_bug.cgi?id=179826
+        <rdar://problem/35455813>
+
+        Reviewed by Mark Lam.
+
+        Failure *in* a promise causes rejection, but failure to create a
+        promise (because of stack overflow) isn't really spec'd (as all
+        stack things JS). This applies to WebAssembly.compile and
+        WebAssembly.instantiate.
+
+        Dan's current proposal says:
+
+            https://littledan.github.io/spec/document/js-api/index.html#stack-overflow
+
+            Whenever a stack overflow occurs in WebAssembly code, the same
+            class of exception is thrown as for a stack overflow in
+            _javascript_. The particular exception here is
+            implementation-defined in both cases.
+
+            Note: ECMAScript doesn’t specify any sort of behavior on stack
+            overflow; implementations have been observed to throw RangeError,
+            InternalError or Error. Any is valid here.
+
+        This is for general stack overflow within WebAssembly, not
+        specifically for promise creation within _javascript_, but it seems
+        like a stack overflow in promise creation should follow the same
+        rule instead of, say, swallowing the overflow and returning
+        undefined.
+
+        * wasm/js/WebAssemblyPrototype.cpp:
+        (JSC::webAssemblyCompileFunc):
+        (JSC::webAssemblyInstantiateFunc):
+
 2017-11-16  Daniel Bates  <[email protected]>
 
         Add feature define for alternative presentation button element

Modified: trunk/Source/_javascript_Core/wasm/js/WebAssemblyPrototype.cpp (224984 => 224985)


--- trunk/Source/_javascript_Core/wasm/js/WebAssemblyPrototype.cpp	2017-11-17 21:38:11 UTC (rev 224984)
+++ trunk/Source/_javascript_Core/wasm/js/WebAssemblyPrototype.cpp	2017-11-17 21:57:09 UTC (rev 224985)
@@ -40,6 +40,7 @@
 #include "ObjectConstructor.h"
 #include "PromiseDeferredTimer.h"
 #include "StrongInlines.h"
+#include "ThrowScope.h"
 #include "WasmBBQPlan.h"
 #include "WasmToJS.h"
 #include "WasmWorklist.h"
@@ -81,38 +82,42 @@
 static EncodedJSValue JSC_HOST_CALL webAssemblyCompileFunc(ExecState* exec)
 {
     VM& vm = exec->vm();
-    auto scope = DECLARE_CATCH_SCOPE(vm);
+    auto throwScope = DECLARE_THROW_SCOPE(vm);
     auto* globalObject = exec->lexicalGlobalObject();
 
     JSPromiseDeferred* promise = JSPromiseDeferred::create(exec, globalObject);
-    CLEAR_AND_RETURN_IF_EXCEPTION(scope, encodedJSValue());
+    RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
 
-    Vector<Strong<JSCell>> dependencies;
-    dependencies.append(Strong<JSCell>(vm, globalObject));
-    vm.promiseDeferredTimer->addPendingPromise(promise, WTFMove(dependencies));
+    {
+        auto catchScope = DECLARE_CATCH_SCOPE(vm);
 
-    Vector<uint8_t> source = createSourceBufferFromValue(vm, exec, exec->argument(0));
+        Vector<Strong<JSCell>> dependencies;
+        dependencies.append(Strong<JSCell>(vm, globalObject));
+        vm.promiseDeferredTimer->addPendingPromise(promise, WTFMove(dependencies));
 
-    if (UNLIKELY(scope.exception()))
-        reject(exec, scope, promise);
-    else {
-        Wasm::Module::validateAsync(&vm.wasmContext, WTFMove(source), createSharedTask<Wasm::Module::CallbackType>([promise, globalObject, &vm] (Wasm::Module::ValidationResult&& result) mutable {
-            vm.promiseDeferredTimer->scheduleWorkSoon(promise, [promise, globalObject, result = WTFMove(result), &vm] () mutable {
-                auto scope = DECLARE_CATCH_SCOPE(vm);
-                ExecState* exec = globalObject->globalExec();
-                JSValue module = JSWebAssemblyModule::createStub(vm, exec, globalObject->WebAssemblyModuleStructure(), WTFMove(result));
-                if (UNLIKELY(scope.exception())) {
-                    reject(exec, scope, promise);
-                    return;
-                }
+        Vector<uint8_t> source = createSourceBufferFromValue(vm, exec, exec->argument(0));
 
-                promise->resolve(exec, module);
-                CLEAR_AND_RETURN_IF_EXCEPTION(scope, void());
-            });
-        }));
+        if (UNLIKELY(catchScope.exception()))
+            reject(exec, catchScope, promise);
+        else {
+            Wasm::Module::validateAsync(&vm.wasmContext, WTFMove(source), createSharedTask<Wasm::Module::CallbackType>([promise, globalObject, &vm] (Wasm::Module::ValidationResult&& result) mutable {
+                vm.promiseDeferredTimer->scheduleWorkSoon(promise, [promise, globalObject, result = WTFMove(result), &vm] () mutable {
+                    auto scope = DECLARE_CATCH_SCOPE(vm);
+                    ExecState* exec = globalObject->globalExec();
+                    JSValue module = JSWebAssemblyModule::createStub(vm, exec, globalObject->WebAssemblyModuleStructure(), WTFMove(result));
+                    if (UNLIKELY(scope.exception())) {
+                        reject(exec, scope, promise);
+                        return;
+                    }
+
+                    promise->resolve(exec, module);
+                    CLEAR_AND_RETURN_IF_EXCEPTION(scope, void());
+                });
+            }));
+        }
+
+        return JSValue::encode(promise->promise());
     }
-
-    return JSValue::encode(promise->promise());
 }
 
 enum class Resolve { WithInstance, WithModuleAndInstance };
@@ -172,7 +177,7 @@
             auto scope = DECLARE_CATCH_SCOPE(vm);
             ExecState* exec = globalObject->globalExec();
             JSWebAssemblyModule* module = JSWebAssemblyModule::createStub(vm, exec, globalObject->WebAssemblyModuleStructure(), WTFMove(result));
-            if (scope.exception())
+            if (UNLIKELY(scope.exception()))
                 return reject(exec, scope, promise);
 
             instantiate(vm, exec, promise, module, importObject, Resolve::WithModuleAndInstance);
@@ -183,27 +188,31 @@
 static EncodedJSValue JSC_HOST_CALL webAssemblyInstantiateFunc(ExecState* exec)
 {
     VM& vm = exec->vm();
-    auto scope = DECLARE_CATCH_SCOPE(vm);
+    auto throwScope = DECLARE_THROW_SCOPE(vm);
+    auto* globalObject = exec->lexicalGlobalObject();
 
-    JSPromiseDeferred* promise = JSPromiseDeferred::create(exec, exec->lexicalGlobalObject());
-    CLEAR_AND_RETURN_IF_EXCEPTION(scope, encodedJSValue());
+    JSPromiseDeferred* promise = JSPromiseDeferred::create(exec, globalObject);
+    RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
 
-    JSValue importArgument = exec->argument(1);
-    JSObject* importObject = importArgument.getObject();
-    if (!importArgument.isUndefined() && !importObject) {
-        promise->reject(exec, createTypeError(exec,
-            ASCIILiteral("second argument to WebAssembly.instantiate must be undefined or an Object"), defaultSourceAppender, runtimeTypeForValue(importArgument)));
-        CLEAR_AND_RETURN_IF_EXCEPTION(scope, encodedJSValue());
+    {
+        auto catchScope = DECLARE_CATCH_SCOPE(vm);
+
+        JSValue importArgument = exec->argument(1);
+        JSObject* importObject = importArgument.getObject();
+        if (UNLIKELY(!importArgument.isUndefined() && !importObject)) {
+            promise->reject(exec, createTypeError(exec,
+                ASCIILiteral("second argument to WebAssembly.instantiate must be undefined or an Object"), defaultSourceAppender, runtimeTypeForValue(importArgument)));
+            CLEAR_AND_RETURN_IF_EXCEPTION(catchScope, JSValue::encode(promise->promise()));
+        } else {
+            JSValue firstArgument = exec->argument(0);
+            if (auto* module = jsDynamicCast<JSWebAssemblyModule*>(vm, firstArgument))
+                instantiate(vm, exec, promise, module, importObject, Resolve::WithInstance);
+            else
+                compileAndInstantiate(vm, exec, promise, firstArgument, importObject);
+        }
+
         return JSValue::encode(promise->promise());
     }
-
-    JSValue firstArgument = exec->argument(0);
-    if (auto* module = jsDynamicCast<JSWebAssemblyModule*>(vm, firstArgument))
-        instantiate(vm, exec, promise, module, importObject, Resolve::WithInstance);
-    else
-        compileAndInstantiate(vm, exec, promise, firstArgument, importObject);
-
-    return JSValue::encode(promise->promise());
 }
 
 static EncodedJSValue JSC_HOST_CALL webAssemblyValidateFunc(ExecState* exec)
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to