+2017-11-17 JF Bastien <jfbastien@apple.com>
+
+ 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 <dabates@apple.com>
Add feature define for alternative presentation button element
#include "ObjectConstructor.h"
#include "PromiseDeferredTimer.h"
#include "StrongInlines.h"
+#include "ThrowScope.h"
#include "WasmBBQPlan.h"
#include "WasmToJS.h"
#include "WasmWorklist.h"
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());
-
- Vector<Strong<JSCell>> dependencies;
- dependencies.append(Strong<JSCell>(vm, globalObject));
- vm.promiseDeferredTimer->addPendingPromise(promise, WTFMove(dependencies));
+ RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
+
+ {
+ auto catchScope = DECLARE_CATCH_SCOPE(vm);
+
+ Vector<Strong<JSCell>> dependencies;
+ dependencies.append(Strong<JSCell>(vm, globalObject));
+ vm.promiseDeferredTimer->addPendingPromise(promise, WTFMove(dependencies));
+
+ Vector<uint8_t> source = createSourceBufferFromValue(vm, exec, exec->argument(0));
+
+ 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());
+ });
+ }));
+ }
- Vector<uint8_t> source = createSourceBufferFromValue(vm, exec, exec->argument(0));
-
- 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;
- }
-
- 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 };
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);
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());
+
+ {
+ 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);
+ }
- 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());
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)