WebAssembly: Make calling Wasm functions that returns or takes an i64 as a parameter...
authorsbarati@apple.com <sbarati@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 23 Dec 2016 01:32:30 +0000 (01:32 +0000)
committersbarati@apple.com <sbarati@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 23 Dec 2016 01:32:30 +0000 (01:32 +0000)
https://bugs.webkit.org/show_bug.cgi?id=166437
<rdar://problem/29793949>

Reviewed by Keith Miller.

JSTests:

* wasm.yaml:
* wasm/function-tests/i64-from-js-exceptions.js: Added.
(const.imp.import.sideEffects):
(assert.throws.instance.exports.foo.valueOf):

Source/JavaScriptCore:

This patch makes it so that we throw an exception before we do
anything else if we call a wasm function that either takes an
i64 as an argument or returns an i64.

* wasm/js/WebAssemblyFunction.cpp:
(JSC::callWebAssemblyFunction):
(JSC::WebAssemblyFunction::WebAssemblyFunction):
(JSC::WebAssemblyFunction::call): Deleted.
* wasm/js/WebAssemblyFunction.h:
(JSC::WebAssemblyFunction::signatureIndex):
(JSC::WebAssemblyFunction::jsEntrypoint):

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@210126 268f45cc-cd09-0410-ab3c-d52691b4dbfc

JSTests/ChangeLog
JSTests/wasm.yaml
JSTests/wasm/function-tests/i64-from-js-exceptions.js [new file with mode: 0644]
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/wasm/js/WebAssemblyFunction.cpp
Source/JavaScriptCore/wasm/js/WebAssemblyFunction.h

index 038f57f..8578ab8 100644 (file)
@@ -1,3 +1,16 @@
+2016-12-22  Saam Barati  <sbarati@apple.com>
+
+        WebAssembly: Make calling Wasm functions that returns or takes an i64 as a parameter an early exception
+        https://bugs.webkit.org/show_bug.cgi?id=166437
+        <rdar://problem/29793949>
+
+        Reviewed by Keith Miller.
+
+        * wasm.yaml:
+        * wasm/function-tests/i64-from-js-exceptions.js: Added.
+        (const.imp.import.sideEffects):
+        (assert.throws.instance.exports.foo.valueOf):
+
 2016-12-22  Mark Lam  <mark.lam@apple.com>
 
         De-duplicate finally blocks.
index c4764b6..b476371 100644 (file)
   cmd: runWebAssemblySpecTest :normal
 
 - path: wasm/spec-tests/unreachable.wast.js
-  cmd: runWebAssemblySpecTest :skip
+  cmd: runWebAssemblySpecTest :normal
 
 - path: wasm/spec-tests/unwind.wast.js
   cmd: runWebAssemblySpecTest :skip
diff --git a/JSTests/wasm/function-tests/i64-from-js-exceptions.js b/JSTests/wasm/function-tests/i64-from-js-exceptions.js
new file mode 100644 (file)
index 0000000..4cd9cfc
--- /dev/null
@@ -0,0 +1,40 @@
+import Builder from '../Builder.js'
+import * as assert from '../assert.js'
+
+const builder = (new Builder())
+    .Type().End()
+    .Import()
+        .Function("import", "sideEffects", {params: [], ret: "void"})
+    .End()
+    .Function().End()
+    .Export()
+        .Function("foo")
+        .Function("bar")
+    .End()
+    .Code()
+        .Function("foo", {params: ["i64"], ret: "void"})
+            .Call(0)
+            .Return()
+        .End()
+        .Function("bar", {params: [], ret: "i64"})
+            .Call(0)
+            .I32Const(25)
+            .I64ExtendUI32()
+            .Return()
+        .End()
+    .End();
+
+const bin = builder.WebAssembly().get();
+const module = new WebAssembly.Module(bin);
+let called = false;
+const imp = {
+    import: { 
+        sideEffects() { called = true; }
+    }
+};
+
+const instance = new WebAssembly.Instance(module, imp);
+assert.throws(() => instance.exports.foo(20), WebAssembly.RuntimeError, "WebAssembly function with an i64 argument can't be called from JavaScript");
+assert.throws(() => instance.exports.foo({valueOf() { throw new Error("Should not be called!"); }}), WebAssembly.RuntimeError, "WebAssembly function with an i64 argument can't be called from JavaScript");
+assert.throws(() => instance.exports.bar(), WebAssembly.RuntimeError, "WebAssembly function that returns i64 can't be called from JavaScript");
+assert.eq(called, false);
index b421ed8..1c17124 100644 (file)
@@ -1,3 +1,23 @@
+2016-12-22  Saam Barati  <sbarati@apple.com>
+
+        WebAssembly: Make calling Wasm functions that returns or takes an i64 as a parameter an early exception
+        https://bugs.webkit.org/show_bug.cgi?id=166437
+        <rdar://problem/29793949>
+
+        Reviewed by Keith Miller.
+
+        This patch makes it so that we throw an exception before we do
+        anything else if we call a wasm function that either takes an
+        i64 as an argument or returns an i64.
+
+        * wasm/js/WebAssemblyFunction.cpp:
+        (JSC::callWebAssemblyFunction):
+        (JSC::WebAssemblyFunction::WebAssemblyFunction):
+        (JSC::WebAssemblyFunction::call): Deleted.
+        * wasm/js/WebAssemblyFunction.h:
+        (JSC::WebAssemblyFunction::signatureIndex):
+        (JSC::WebAssemblyFunction::jsEntrypoint):
+
 2016-12-22  Keith Miller  <keith_miller@apple.com>
 
         Add BitOr for floating points to B3
index 4f0d7a8..0d51e02 100644 (file)
@@ -35,6 +35,7 @@
 #include "JSWebAssemblyCallee.h"
 #include "JSWebAssemblyInstance.h"
 #include "JSWebAssemblyMemory.h"
+#include "JSWebAssemblyRuntimeError.h"
 #include "LLIntThunks.h"
 #include "ProtoCallFrame.h"
 #include "VM.h"
@@ -59,9 +60,27 @@ static EncodedJSValue JSC_HOST_CALL callWebAssemblyFunction(ExecState* exec)
     if (exec->argumentCount() != signature->argumentCount())
         return JSValue::encode(throwException(exec, scope, createNotEnoughArgumentsError(exec, defaultSourceAppender)));
 
+    {
+        // Check if we have a disallowed I64 use.
+
+        for (unsigned argIndex = 0; argIndex < signature->argumentCount(); ++argIndex) {
+            if (signature->argument(argIndex) == Wasm::I64) {
+                JSWebAssemblyRuntimeError* error = JSWebAssemblyRuntimeError::create(exec, vm, exec->lexicalGlobalObject()->WebAssemblyRuntimeErrorStructure(),
+                    "WebAssembly function with an i64 argument can't be called from JavaScript");
+                return JSValue::encode(throwException(exec, scope, error));
+            }
+        }
+
+        if (signature->returnType() == Wasm::I64) {
+            JSWebAssemblyRuntimeError* error = JSWebAssemblyRuntimeError::create(exec, vm, exec->lexicalGlobalObject()->WebAssemblyRuntimeErrorStructure(),
+                "WebAssembly function that returns i64 can't be called from JavaScript");
+            return JSValue::encode(throwException(exec, scope, error));
+        }
+    }
+
     // FIXME is this boxing correct? https://bugs.webkit.org/show_bug.cgi?id=164876
     Vector<JSValue> boxedArgs;
-    for (unsigned argIndex = 0; argIndex < exec->argumentCount(); ++argIndex) {
+    for (unsigned argIndex = 0; argIndex < signature->argumentCount(); ++argIndex) {
         JSValue arg = exec->uncheckedArgument(argIndex);
         switch (signature->argument(argIndex)) {
         case Wasm::I32:
@@ -100,13 +119,7 @@ static EncodedJSValue JSC_HOST_CALL callWebAssemblyFunction(ExecState* exec)
     ProtoCallFrame protoCallFrame;
     protoCallFrame.init(nullptr, wasmFunction, firstArgument, argCount, remainingArgs);
 
-    return wasmFunction->call(vm, &protoCallFrame);
-}
-
-EncodedJSValue WebAssemblyFunction::call(VM& vm, ProtoCallFrame* protoCallFrame)
-{
-    // Setup the memory that the entrance loads.
-    if (JSWebAssemblyMemory* memory = instance()->memory()) {
+    if (JSWebAssemblyMemory* memory = wasmFunction->instance()->memory()) {
         Wasm::Memory* wasmMemory = memory->memory();
         vm.topWasmMemoryPointer = wasmMemory->memory();
         vm.topWasmMemorySize = wasmMemory->size();
@@ -116,28 +129,28 @@ EncodedJSValue WebAssemblyFunction::call(VM& vm, ProtoCallFrame* protoCallFrame)
     }
 
     JSWebAssemblyInstance* prevJSWebAssemblyInstance = vm.topJSWebAssemblyInstance;
-    vm.topJSWebAssemblyInstance = instance();
-    ASSERT(instance());
-    EncodedJSValue rawResult = vmEntryToWasm(m_jsEntrypoint->entrypoint(), &vm, protoCallFrame);
+    vm.topJSWebAssemblyInstance = wasmFunction->instance();
+    ASSERT(wasmFunction->instance());
+    EncodedJSValue rawResult = vmEntryToWasm(wasmFunction->jsEntrypoint(), &vm, &protoCallFrame);
     vm.topJSWebAssemblyInstance = prevJSWebAssemblyInstance;
+    RETURN_IF_EXCEPTION(scope, { });
 
     // FIXME is this correct? https://bugs.webkit.org/show_bug.cgi?id=164876
-    switch (m_returnType) {
+    switch (signature->returnType()) {
     case Wasm::Void:
         return JSValue::encode(jsUndefined());
     case Wasm::I32:
-        return JSValue::encode(JSValue(static_cast<int32_t>(rawResult)));
+        return JSValue::encode(jsNumber(static_cast<int32_t>(rawResult)));
     case Wasm::F32:
-        return JSValue::encode(JSValue(bitwise_cast<float>(static_cast<int32_t>(rawResult))));
+        return JSValue::encode(jsNumber(purifyNaN(static_cast<double>(bitwise_cast<float>(static_cast<int32_t>(rawResult))))));
     case Wasm::F64:
-        return JSValue::encode(JSValue(bitwise_cast<double>(rawResult)));
+        return JSValue::encode(jsNumber(purifyNaN(bitwise_cast<double>(rawResult))));
     case Wasm::I64:
     case Wasm::Func:
     case Wasm::Anyfunc:
-        break;
+        RELEASE_ASSERT_NOT_REACHED();
     }
 
-    RELEASE_ASSERT_NOT_REACHED();
     return EncodedJSValue();
 }
 
@@ -159,11 +172,7 @@ Structure* WebAssemblyFunction::createStructure(VM& vm, JSGlobalObject* globalOb
 WebAssemblyFunction::WebAssemblyFunction(VM& vm, JSGlobalObject* globalObject, Structure* structure, Wasm::SignatureIndex signatureIndex)
     : Base(vm, globalObject, structure)
     , m_signatureIndex(signatureIndex)
-{
-    // Don't cache the signature pointer: it's a global on VM and can change as new WebAssembly.Module are created.
-    const Wasm::Signature* signature = Wasm::SignatureInformation::get(&vm, m_signatureIndex);
-    m_returnType = signature->returnType();
-}
+{ }
 
 void WebAssemblyFunction::visitChildren(JSCell* cell, SlotVisitor& visitor)
 {
index 2805753..3490502 100644 (file)
@@ -54,8 +54,8 @@ public:
 
     JSWebAssemblyInstance* instance() const { return m_instance.get(); }
     Wasm::SignatureIndex signatureIndex() const { return m_signatureIndex; }
-    EncodedJSValue call(VM&, ProtoCallFrame*);
     void* wasmEntrypoint() { return m_wasmEntrypoint->entrypoint(); }
+    void* jsEntrypoint() { return m_jsEntrypoint->entrypoint(); }
 
 protected:
     static void visitChildren(JSCell*, SlotVisitor&);
@@ -69,7 +69,6 @@ private:
     WriteBarrier<JSWebAssemblyCallee> m_jsEntrypoint;
     WriteBarrier<JSWebAssemblyCallee> m_wasmEntrypoint;
     Wasm::SignatureIndex m_signatureIndex;
-    Wasm::Type m_returnType;
 };
 
 } // namespace JSC