WebAssembly: test imports and exports with 16-bit characters
authorjfbastien@apple.com <jfbastien@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 8 Jun 2017 04:43:51 +0000 (04:43 +0000)
committerjfbastien@apple.com <jfbastien@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 8 Jun 2017 04:43:51 +0000 (04:43 +0000)
https://bugs.webkit.org/show_bug.cgi?id=165977
<rdar://problem/29760130>

Reviewed by Saam Barati.

JSTests:

The output for import failure was improved, so many tests need to
be updated here. Only one has new tests as noted below.

* wasm/function-tests/memory-import-and-grow.js:
* wasm/js-api/Instance.imports.exports.unicode.js: Added. Main new test.
(idxModule):
* wasm/js-api/global-error.js:
(new.Number):
(assert.throws):
* wasm/js-api/table.js:
(assert.throws):
(new.WebAssembly.Table):
* wasm/js-api/test_memory.js:
(test):
* wasm/js-api/wasm-to-wasm-bad-signature.js:
(BadSignatureDropStartParams.):
(BadSignatureDropStartParams):
(BadSignatureDropEndParams.):
(BadSignatureSwapParam.):
(BadSignatureRet.):
* wasm/js-api/web-assembly-instantiate.js:
(assert.asyncTest.async.test):
(assert.asyncTest):
* wasm/js-api/wrapper-function.js:
(return.new.WebAssembly.Module):

Source/JavaScriptCore:

Add the missing UTF-8 conversions. Improve import failure error
messages, otherwise it's hard to figure out which import is wrong.

* wasm/js/JSWebAssemblyInstance.cpp:
(JSC::JSWebAssemblyInstance::create):
* wasm/js/WebAssemblyModuleRecord.cpp:
(JSC::WebAssemblyModuleRecord::finishCreation):
(JSC::WebAssemblyModuleRecord::link):

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

12 files changed:
JSTests/ChangeLog
JSTests/wasm/function-tests/memory-import-and-grow.js
JSTests/wasm/js-api/Instance.imports.exports.unicode.js [new file with mode: 0644]
JSTests/wasm/js-api/global-error.js
JSTests/wasm/js-api/table.js
JSTests/wasm/js-api/test_memory.js
JSTests/wasm/js-api/wasm-to-wasm-bad-signature.js
JSTests/wasm/js-api/web-assembly-instantiate.js
JSTests/wasm/js-api/wrapper-function.js
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/wasm/js/JSWebAssemblyInstance.cpp
Source/JavaScriptCore/wasm/js/WebAssemblyModuleRecord.cpp

index 1efc0ed..0c9a93e 100644 (file)
@@ -1,3 +1,37 @@
+2017-06-07  JF Bastien  <jfbastien@apple.com>
+
+        WebAssembly: test imports and exports with 16-bit characters
+        https://bugs.webkit.org/show_bug.cgi?id=165977
+        <rdar://problem/29760130>
+
+        Reviewed by Saam Barati.
+
+        The output for import failure was improved, so many tests need to
+        be updated here. Only one has new tests as noted below.
+
+        * wasm/function-tests/memory-import-and-grow.js:
+        * wasm/js-api/Instance.imports.exports.unicode.js: Added. Main new test.
+        (idxModule):
+        * wasm/js-api/global-error.js:
+        (new.Number):
+        (assert.throws):
+        * wasm/js-api/table.js:
+        (assert.throws):
+        (new.WebAssembly.Table):
+        * wasm/js-api/test_memory.js:
+        (test):
+        * wasm/js-api/wasm-to-wasm-bad-signature.js:
+        (BadSignatureDropStartParams.):
+        (BadSignatureDropStartParams):
+        (BadSignatureDropEndParams.):
+        (BadSignatureSwapParam.):
+        (BadSignatureRet.):
+        * wasm/js-api/web-assembly-instantiate.js:
+        (assert.asyncTest.async.test):
+        (assert.asyncTest):
+        * wasm/js-api/wrapper-function.js:
+        (return.new.WebAssembly.Module):
+
 2017-06-07  Mark Lam  <mark.lam@apple.com>
 
         Restrict the regress-173035.js test to only run on Darwin x86-64.
index 34ce59d..1398d92 100644 (file)
@@ -121,11 +121,11 @@ test({ initial: 2, maximum: 2 }, { initial: 2, maximum: 4 }, u, 1, 2);
 test({ initial: 2, maximum: 4 }, { initial: 2 }, 0, u, 2);
 
 // Disallowed: imported initial is lesser than declared.
-assert.throws(() => test({ initial: 1, maximum: 4 }, { initial: 2, maximum: 4 }, u, u, 2), WebAssembly.LinkError, `Memory import provided an 'initial' that is smaller than the module's declared 'initial' import memory size`);
-assert.throws(() => test({ initial: 0, maximum: 4 }, { initial: 2, maximum: 4 }, u, u, 2), WebAssembly.LinkError, `Memory import provided an 'initial' that is smaller than the module's declared 'initial' import memory size`);
+assert.throws(() => test({ initial: 1, maximum: 4 }, { initial: 2, maximum: 4 }, u, u, 2), WebAssembly.LinkError, `Memory import imp:memory provided an 'initial' that is smaller than the module's declared 'initial' import memory size`);
+assert.throws(() => test({ initial: 0, maximum: 4 }, { initial: 2, maximum: 4 }, u, u, 2), WebAssembly.LinkError, `Memory import imp:memory provided an 'initial' that is smaller than the module's declared 'initial' import memory size`);
 
 // Disallowed: imported maximum is greater than declared.
-assert.throws(() => test({ initial: 2, maximum: 5 }, { initial: 2, maximum: 4 }, u, u, 2), WebAssembly.LinkError, `Memory import provided a 'maximum' that is larger than the module's declared 'maximum' import memory size`);
+assert.throws(() => test({ initial: 2, maximum: 5 }, { initial: 2, maximum: 4 }, u, u, 2), WebAssembly.LinkError, `Memory import imp:memory provided a 'maximum' that is larger than the module's declared 'maximum' import memory size`);
 
 // Disallowed: no imported maximum, same as above.
-assert.throws(() => test({ initial: 2 }, { initial: 2, maximum: 4 }, 0, u, 2), WebAssembly.LinkError, `Memory import did not have a 'maximum' but the module requires that it does`);
+assert.throws(() => test({ initial: 2 }, { initial: 2, maximum: 4 }, 0, u, 2), WebAssembly.LinkError, `Memory import imp:memory did not have a 'maximum' but the module requires that it does`);
diff --git a/JSTests/wasm/js-api/Instance.imports.exports.unicode.js b/JSTests/wasm/js-api/Instance.imports.exports.unicode.js
new file mode 100644 (file)
index 0000000..e86c209
--- /dev/null
@@ -0,0 +1,96 @@
+import Builder from '../Builder.js';
+import * as assert from '../assert.js';
+
+// Interesting Unicode corner cases.
+
+const names = [
+    "", // Empty string.
+    "\u0000", // NUL
+    "␀", // SYMBOL FOR NUL
+    "\ufeff", // BYTE ORDER MARK
+    "\ufffc", // OBJECT REPLACEMENT CHARACTER
+    "�", // REPLACEMENT CHARACTER in case anything gets substituted this would be a duplicate, which WebAssembly disallows.
+    "\ufffe", // NONCHARACTER-FFFE
+    "\uffff", // NONCHARACTER-FFFF
+    "\u200e", // LEFT-TO-RIGHT MARK
+    "\u200f", // RIGHT-TO-LEFT MARK
+    "\u202a", // LEFT-TO-RIGHT EMBEDDING
+    "\u202b", // RIGHT-TO-LEFT EMBEDDING
+    "\u202d", // LEFT-TO-RIGHT OVERRIDE
+    "\u202e", // RIGHT-TO-LEFT OVERRIDE
+    "\u202c", // POP DIRECTIONAL FORMATTING
+    "🇨🇦", // REGIONAL INDICATOR SYMBOL LETTER C + REGIONAL INDICATOR SYMBOL LETTER A
+    "🈹", // PLAYING CARD BLACK JOKER
+    "👨‍❤️‍💋‍👨", // Combine a bunch of emoji
+
+    // Duplicate entries are invalid, so normalization would cause issues. We want to catch those issues.
+    "한글",
+    "한글", // Normalized version of the above.
+    "Å", // LATIN CAPITAL LETTER A WITH RING ABOVE
+    "Å", // ANGSTROM SIGN
+    "Å", // LATIN CAPITAL LETTER A + COMBINING RING ABOVE
+    "À", // LATIN CAPITAL LETTER A + COMBINING GRAVE ACCENT
+    "À", // LATIN CAPITAL LETTER A WITH GRAVE
+    "ą̂́", // LATIN SMALL LETTER A WITH CIRCUMFLEX AND ACUTE + COMBINING OGONEK
+    "ą̂́", // LATIN SMALL LETTER A WITH OGONEK + COMBINING CIRCUMFLEX ACCENT + COMBINING ACUTE ACCENT
+    "Q̣̀", // LATIN CAPITAL LETTER Q + COMBINING GRAVE ACCENT + COMBINING DOT BELOW
+    "Q̣̀", // LATIN CAPITAL LETTER + COMBINING DOT BELOW + COMBINING GRAVE ACCENT
+
+    // Combine way too many things:
+
+
+
+    "Ĵ̸̨̛͙̙̱̯̺̖͔͎̣͓̬͉͓͙͔͈̥̖͎ͯ́̂͆̓̂̑ͥͧͤ͋̔ͥà̷̛̤̻̦͓͓̖̪̟͓͂ͫ̅ͦͦ̈̄̉̅̾̊̽͑ͬ̚͟͠v̡͙͕̟͎̰͆̿ͩ͗ͩ̀ͧ͂͆̾́͑ͦͭ̽ͦ̀͘a̧̻͖͓̗̻̩͌ͮ͗̈́͊̊̑̉̚̕S̡͖̱͈͚͉̩̺͎ͪͧ́͒̔̿̈ͫͥ̇ͦ̏͐̃ͭ́ͭ͢͝ç̧͎̮̤̙̗̻̯͖̮̙̰̞ͫ̽ͤ̓̊̇͆̀ͫ͂̒͐ͬ̇͂̉͒ͫ̚͘͞ͅṙ̷͓̹͈̮̪͔͓̫̓͛̅̑̉̏͂ͣ́̏͋́̓̚ͅȉͪͩ̍̽ͣ̊ͮ̚͞͏̴̵̯̹̠͖͈̠͎̦̀p͙̝̗̥̻̯̰͚̫̏̏ͯ͐ͧ͋̊̃̈̈́͢t̷͍͎̻̩̠̬̙̦̰͓̩̗̝̱̣̓̐ͫ̀̋̓͝",
+
+
+
+
+];
+
+// WebAssembly import objects have a two-level namespace with module and field. Both must be UTF-8.
+let importObject = {};
+for (let idxModule = 0; idxModule < names.length; ++idxModule) {
+    assert.falsy(importObject.hasOwnProperty(names[idxModule]));
+    importObject[names[idxModule]] = {};
+    for (let idxField = 0; idxField < names.length; ++idxField) {
+        assert.falsy(importObject[names[idxModule]].hasOwnProperty(names[idxField]));
+        importObject[names[idxModule]][names[idxField]] = () => 10000 * idxModule + idxField;
+    }
+}
+
+let b = (new Builder())
+    .Type().End();
+
+b = b.Import();
+for (let idxModule = 0; idxModule < names.length; ++idxModule)
+    for (let idxField = 0; idxField < names.length; ++idxField)
+        b = b.Function(names[idxModule], names[idxField], { params: [], ret: "i32" });
+b = b.End();
+
+b = b.Function().End();
+
+b = b.Export();
+for (let idx = 0; idx < names.length; ++idx)
+    b = b.Function(names[idx]);
+b = b.End();
+
+b = b.Code();
+for (let idx = 0; idx < names.length; ++idx)
+    b = b.Function(names[idx], { params: [], ret: "i32" }).I32Const(idx).Return().End();
+b = b.End();
+
+const module = new WebAssembly.Module(b.WebAssembly().get());
+
+for (let idxModule = 0; idxModule < names.length; ++idxModule)   
+    for (let idxField = 0; idxField < names.length; ++idxField) {
+        assert.eq(WebAssembly.Module.imports(module)[idxModule * names.length + idxField].module, names[idxModule]);
+        assert.eq(WebAssembly.Module.imports(module)[idxModule * names.length + idxField].name, names[idxField]);
+    }
+
+for (let idx = 0; idx < names.length; ++idx)
+    assert.eq(WebAssembly.Module.exports(module)[idx].name, names[idx]);
+
+const instance = new WebAssembly.Instance(module, importObject);
+
+for (let idx = 0; idx < names.length; ++idx)
+    assert.eq(instance.exports[names[idx]](), idx);
index aee7535..09f8d79 100644 (file)
@@ -185,7 +185,7 @@ for ( let imp of [undefined, null, {}, () => {}, "number", new Number(4)]) {
     bin.trim();
 
     const module = new WebAssembly.Module(bin.get());
-    assert.throws(() => new WebAssembly.Instance(module, { imp: { global: imp } }), WebAssembly.LinkError, "imported global must be a number (evaluating 'new WebAssembly.Instance(module, { imp: { global: imp } })')");
+    assert.throws(() => new WebAssembly.Instance(module, { imp: { global: imp } }), WebAssembly.LinkError, "imported global imp:global must be a number (evaluating 'new WebAssembly.Instance(module, { imp: { global: imp } })')");
 }
 
 {
@@ -208,5 +208,5 @@ for ( let imp of [undefined, null, {}, () => {}, "number", new Number(4)]) {
         .Function().End()
         .Global().GetGlobal("i64", 0, "immutable").End();
     const module = new WebAssembly.Module(builder.WebAssembly().get());
-    assert.throws(() => new WebAssembly.Instance(module, { imp: { global: undefined } }), WebAssembly.LinkError, "imported global cannot be an i64 (evaluating 'new WebAssembly.Instance(module, { imp: { global: undefined } })')");
+    assert.throws(() => new WebAssembly.Instance(module, { imp: { global: undefined } }), WebAssembly.LinkError, "imported global imp:global cannot be an i64 (evaluating 'new WebAssembly.Instance(module, { imp: { global: undefined } })')");
 }
index d55a350..391858f 100644 (file)
@@ -193,10 +193,10 @@ function assertBadTableImport(tableDescription, message) {
     }
 
     const badTables = [
-        [{initial: 100, maximum:100, element:"anyfunc"}, new WebAssembly.Table({initial:100, element: "anyfunc"}), "Table import does not have a 'maximum' but the module requires that it does (evaluating 'new WebAssembly.Instance(module, {imp: {table}})')"],
-        [{initial: 100, maximum:100, element:"anyfunc"}, new WebAssembly.Table({initial:100, maximum:101, element: "anyfunc"}), "Imported Table's 'maximum' is larger than the module's expected 'maximum' (evaluating 'new WebAssembly.Instance(module, {imp: {table}})')"],
-        [{initial: 100, element:"anyfunc"}, new WebAssembly.Table({initial:10, element: "anyfunc"}), "Table import provided an 'initial' that is too small (evaluating 'new WebAssembly.Instance(module, {imp: {table}})')"],
-        [{initial: 10, element:"anyfunc"}, new WebAssembly.Table({initial:9, element: "anyfunc"}), "Table import provided an 'initial' that is too small (evaluating 'new WebAssembly.Instance(module, {imp: {table}})')"],
+        [{initial: 100, maximum:100, element:"anyfunc"}, new WebAssembly.Table({initial:100, element: "anyfunc"}), "Table import imp:table does not have a 'maximum' but the module requires that it does (evaluating 'new WebAssembly.Instance(module, {imp: {table}})')"],
+        [{initial: 100, maximum:100, element:"anyfunc"}, new WebAssembly.Table({initial:100, maximum:101, element: "anyfunc"}), "Imported Table imp:table 'maximum' is larger than the module's expected 'maximum' (evaluating 'new WebAssembly.Instance(module, {imp: {table}})')"],
+        [{initial: 100, element:"anyfunc"}, new WebAssembly.Table({initial:10, element: "anyfunc"}), "Table import imp:table provided an 'initial' that is too small (evaluating 'new WebAssembly.Instance(module, {imp: {table}})')"],
+        [{initial: 10, element:"anyfunc"}, new WebAssembly.Table({initial:9, element: "anyfunc"}), "Table import imp:table provided an 'initial' that is too small (evaluating 'new WebAssembly.Instance(module, {imp: {table}})')"],
     ];
     for (const [d, t, m] of badTables) {
         assertBadTableInstance(d, t, m);
@@ -251,7 +251,7 @@ function assertBadTableImport(tableDescription, message) {
             .Code()
             .End();
         const module = new WebAssembly.Module(builder.WebAssembly().get());
-        assert.throws(() => new WebAssembly.Instance(module, {imp: {table}}), WebAssembly.LinkError, "Table import is not an instance of WebAssembly.Table (evaluating 'new WebAssembly.Instance(module, {imp: {table}})')");
+        assert.throws(() => new WebAssembly.Instance(module, {imp: {table}}), WebAssembly.LinkError, "Table import imp:table is not an instance of WebAssembly.Table (evaluating 'new WebAssembly.Instance(module, {imp: {table}})')");
     }
     assertBadTable(25);
     assertBadTable(new Object);
index e6d68c2..5205992 100644 (file)
@@ -318,13 +318,13 @@ test(function() {
     const module = new WebAssembly.Module(bin);
 
     assert.throws(() => new WebAssembly.Instance(module, 20), TypeError, `second argument to WebAssembly.Instance must be undefined or an Object`);
-    assert.throws(() => new WebAssembly.Instance(module, {}), TypeError, `import must be an object`);
-    assert.throws(() => new WebAssembly.Instance(module, {imp: { } }), WebAssembly.LinkError, `Memory import is not an instance of WebAssembly.Memory`);
-    assert.throws(() => new WebAssembly.Instance(module, {imp: { memory: 20 } }), WebAssembly.LinkError, `Memory import is not an instance of WebAssembly.Memory`);
-    assert.throws(() => new WebAssembly.Instance(module, {imp: { memory: [] } }), WebAssembly.LinkError, `Memory import is not an instance of WebAssembly.Memory`);
-    assert.throws(() => new WebAssembly.Instance(module, {imp: { memory: new WebAssembly.Memory({initial: 19, maximum: 25}) } }), WebAssembly.LinkError, `Memory import provided an 'initial' that is smaller than the module's declared 'initial' import memory size`);
-    assert.throws(() => new WebAssembly.Instance(module, {imp: { memory: new WebAssembly.Memory({initial: 20}) } }), WebAssembly.LinkError, `Memory import did not have a 'maximum' but the module requires that it does`);
-    assert.throws(() => new WebAssembly.Instance(module, {imp: { memory: new WebAssembly.Memory({initial: 20, maximum: 26}) } }), WebAssembly.LinkError, `Memory import provided a 'maximum' that is larger than the module's declared 'maximum' import memory size`);
+    assert.throws(() => new WebAssembly.Instance(module, {}), TypeError, `import imp:memory must be an object`);
+    assert.throws(() => new WebAssembly.Instance(module, {imp: { } }), WebAssembly.LinkError, `Memory import imp:memory is not an instance of WebAssembly.Memory`);
+    assert.throws(() => new WebAssembly.Instance(module, {imp: { memory: 20 } }), WebAssembly.LinkError, `Memory import imp:memory is not an instance of WebAssembly.Memory`);
+    assert.throws(() => new WebAssembly.Instance(module, {imp: { memory: [] } }), WebAssembly.LinkError, `Memory import imp:memory is not an instance of WebAssembly.Memory`);
+    assert.throws(() => new WebAssembly.Instance(module, {imp: { memory: new WebAssembly.Memory({initial: 19, maximum: 25}) } }), WebAssembly.LinkError, `Memory import imp:memory provided an 'initial' that is smaller than the module's declared 'initial' import memory size`);
+    assert.throws(() => new WebAssembly.Instance(module, {imp: { memory: new WebAssembly.Memory({initial: 20}) } }), WebAssembly.LinkError, `Memory import imp:memory did not have a 'maximum' but the module requires that it does`);
+    assert.throws(() => new WebAssembly.Instance(module, {imp: { memory: new WebAssembly.Memory({initial: 20, maximum: 26}) } }), WebAssembly.LinkError, `Memory import imp:memory provided a 'maximum' that is larger than the module's declared 'maximum' import memory size`);
 });
 
 test(function() {
@@ -354,8 +354,8 @@ test(function() {
         assert.throws(() => new WebAssembly.Instance(module, instanceObj), WebAssembly.LinkError, expectedError);
     }
 
-    testMemImportError({imp: { memory: new WebAssembly.Memory({initial: 19, maximum: 25}) } }, `Memory import provided an 'initial' that is smaller than the module's declared 'initial' import memory size`);
-    testMemImportError({imp: { memory: new WebAssembly.Memory({initial: 19}) } }, `Memory import provided an 'initial' that is smaller than the module's declared 'initial' import memory size`);
+    testMemImportError({imp: { memory: new WebAssembly.Memory({initial: 19, maximum: 25}) } }, `Memory import imp:memory provided an 'initial' that is smaller than the module's declared 'initial' import memory size`);
+    testMemImportError({imp: { memory: new WebAssembly.Memory({initial: 19}) } }, `Memory import imp:memory provided an 'initial' that is smaller than the module's declared 'initial' import memory size`);
 
     // This should not throw.
     new WebAssembly.Instance(module, {imp: {memory: new WebAssembly.Memory({initial:20})}});
index d69ba2c..169411b 100644 (file)
@@ -62,7 +62,7 @@ const makeImportee = signature => {
         for (let i = 1; i <= signature.params.length; ++i) {
             const badParamSignature = { params: signature.params.slice(i, signature.params.length), ret: signature.ret };
             const importer = makeImporter(badParamSignature);
-            assert.throws(() => new WebAssembly.Instance(importer, importee), WebAssembly.LinkError, `imported function's signature doesn't match the provided WebAssembly function's signature (evaluating 'new WebAssembly.Instance(importer, importee)')`);
+            assert.throws(() => new WebAssembly.Instance(importer, importee), WebAssembly.LinkError, `imported function exports:${importName} signature doesn't match the provided WebAssembly function's signature (evaluating 'new WebAssembly.Instance(importer, importee)')`);
         }
     }
 })();
@@ -73,7 +73,7 @@ const makeImportee = signature => {
         for (let i = 1; i < signature.params.length; ++i) {
             const badParamSignature = { params: signature.params.slice(0, i), ret: signature.ret };
             const importer = makeImporter(badParamSignature);
-            assert.throws(() => new WebAssembly.Instance(importer, importee), WebAssembly.LinkError, `imported function's signature doesn't match the provided WebAssembly function's signature (evaluating 'new WebAssembly.Instance(importer, importee)')`);
+            assert.throws(() => new WebAssembly.Instance(importer, importee), WebAssembly.LinkError, `imported function exports:${importName} signature doesn't match the provided WebAssembly function's signature (evaluating 'new WebAssembly.Instance(importer, importee)')`);
         }
     }
 })();
@@ -87,7 +87,7 @@ const makeImportee = signature => {
                 badParams[signatureIndex] = swapTypeNonVoid(badParams[signatureIndex], typeIndex);
                 const badParamSignature = { params: badParams, ret: signature.ret };
                 const importer = makeImporter(badParamSignature);
-                assert.throws(() => new WebAssembly.Instance(importer, importee), WebAssembly.LinkError, `imported function's signature doesn't match the provided WebAssembly function's signature (evaluating 'new WebAssembly.Instance(importer, importee)')`);
+                assert.throws(() => new WebAssembly.Instance(importer, importee), WebAssembly.LinkError, `imported function exports:${importName} signature doesn't match the provided WebAssembly function's signature (evaluating 'new WebAssembly.Instance(importer, importee)')`);
             }
         }
     }
@@ -99,7 +99,7 @@ const makeImportee = signature => {
         for (let typeIndex = 1; typeIndex < types.length; ++typeIndex) {
             const badParamSignature = { params: signature.params, ret: swapType(signature.ret, typeIndex) };
             const importer = makeImporter(badParamSignature);
-            assert.throws(() => new WebAssembly.Instance(importer, importee), WebAssembly.LinkError, `imported function's signature doesn't match the provided WebAssembly function's signature (evaluating 'new WebAssembly.Instance(importer, importee)')`);
+            assert.throws(() => new WebAssembly.Instance(importer, importee), WebAssembly.LinkError, `imported function exports:${importName} signature doesn't match the provided WebAssembly function's signature (evaluating 'new WebAssembly.Instance(importer, importee)')`);
         }
     }
 })();
index eb3e99b..f606725 100644 (file)
@@ -103,7 +103,7 @@ assert.eq(WebAssembly.instantiate.length, 1);
         try {
             let {module, instance} = await WebAssembly.instantiate(bin, {imp: {memory: 20}});
         } catch(e) {
-            assert.eq(e.message, "Memory import is not an instance of WebAssembly.Memory");
+            assert.eq(e.message, "Memory import imp:memory is not an instance of WebAssembly.Memory");
         }
     }
 
@@ -131,7 +131,7 @@ assert.eq(WebAssembly.instantiate.length, 1);
             const module = new WebAssembly.Module(bin);
             let instance = await WebAssembly.instantiate(bin, {imp: {memory: 20}});
         } catch(e) {
-            assert.eq(e.message, "Memory import is not an instance of WebAssembly.Memory");
+            assert.eq(e.message, "Memory import imp:memory is not an instance of WebAssembly.Memory");
         }
     }
 
index 71a50ee..46294e7 100644 (file)
@@ -45,7 +45,7 @@ function exportImport(type) {
             .Code().End();
         let module = new WebAssembly.Module(builder.WebAssembly().get());
         // This should not type check.
-        assert.throws(() => new WebAssembly.Instance(module, {imp: {f: instance.exports.func}}), WebAssembly.LinkError, "imported function's signature doesn't match the provided WebAssembly function's signature");
+        assert.throws(() => new WebAssembly.Instance(module, {imp: {f: instance.exports.func}}), WebAssembly.LinkError, "imported function imp:f signature doesn't match the provided WebAssembly function's signature");
     }
 
 }
index 1eca51b..2065da6 100644 (file)
@@ -1,3 +1,20 @@
+2017-06-07  JF Bastien  <jfbastien@apple.com>
+
+        WebAssembly: test imports and exports with 16-bit characters
+        https://bugs.webkit.org/show_bug.cgi?id=165977
+        <rdar://problem/29760130>
+
+        Reviewed by Saam Barati.
+
+        Add the missing UTF-8 conversions. Improve import failure error
+        messages, otherwise it's hard to figure out which import is wrong.
+
+        * wasm/js/JSWebAssemblyInstance.cpp:
+        (JSC::JSWebAssemblyInstance::create):
+        * wasm/js/WebAssemblyModuleRecord.cpp:
+        (JSC::WebAssemblyModuleRecord::finishCreation):
+        (JSC::WebAssemblyModuleRecord::link):
+
 2017-06-07  Devin Rousso  <drousso@apple.com>
 
         Web Inspector: Add ContextMenu item to log WebSocket object to console
index 3610db3..35a5b3c 100644 (file)
@@ -137,6 +137,10 @@ JSWebAssemblyInstance* JSWebAssemblyInstance::create(VM& vm, ExecState* exec, JS
         return nullptr;
     };
 
+    auto importFailMessage = [&] (const Wasm::Import& import, const char* before, const char* after) {
+        return makeString(before, " ", String::fromUTF8(import.module), ":", String::fromUTF8(import.field), " ", after);
+    };
+
     // If the list of module.imports is not empty and Type(importObject) is not Object, a TypeError is thrown.
     if (moduleInformation.imports.size() && !importObject)
         return exception(createTypeError(exec, ASCIILiteral("can't make WebAssembly.Instance because there is no imports Object and the WebAssembly.Module requires imports")));
@@ -161,15 +165,15 @@ JSWebAssemblyInstance* JSWebAssemblyInstance::create(VM& vm, ExecState* exec, JS
     // For each import i in module.imports:
     for (auto& import : moduleInformation.imports) {
         // 1. Let o be the resultant value of performing Get(importObject, i.module_name).
-        JSValue importModuleValue = importObject->get(exec, Identifier::fromString(&vm, import.module));
+        JSValue importModuleValue = importObject->get(exec, Identifier::fromString(&vm, String::fromUTF8(import.module)));
         RETURN_IF_EXCEPTION(throwScope, nullptr);
         // 2. If Type(o) is not Object, throw a TypeError.
         if (!importModuleValue.isObject())
-            return exception(createTypeError(exec, ASCIILiteral("import must be an object"), defaultSourceAppender, runtimeTypeForValue(importModuleValue)));
+            return exception(createTypeError(exec, importFailMessage(import, "import", "must be an object"), defaultSourceAppender, runtimeTypeForValue(importModuleValue)));
 
         // 3. Let v be the value of performing Get(o, i.item_name)
         JSObject* object = jsCast<JSObject*>(importModuleValue);
-        JSValue value = object->get(exec, Identifier::fromString(&vm, import.field));
+        JSValue value = object->get(exec, Identifier::fromString(&vm, String::fromUTF8(import.field)));
         RETURN_IF_EXCEPTION(throwScope, nullptr);
 
         switch (import.kind) {
@@ -177,7 +181,7 @@ JSWebAssemblyInstance* JSWebAssemblyInstance::create(VM& vm, ExecState* exec, JS
             // 4. If i is a function import:
             // i. If IsCallable(v) is false, throw a WebAssembly.LinkError.
             if (!value.isFunction())
-                return exception(createJSWebAssemblyLinkError(exec, vm, ASCIILiteral("import function must be callable")));
+                return exception(createJSWebAssemblyLinkError(exec, vm, importFailMessage(import, "import function", "must be callable")));
 
             JSObject* function = jsCast<JSObject*>(value);
             // ii. If v is an Exported Function Exotic Object:
@@ -195,7 +199,7 @@ JSWebAssemblyInstance* JSWebAssemblyInstance::create(VM& vm, ExecState* exec, JS
                 }
                 Wasm::SignatureIndex expectedSignatureIndex = moduleInformation.importFunctionSignatureIndices[import.kindIndex];
                 if (importedSignatureIndex != expectedSignatureIndex)
-                    return exception(createJSWebAssemblyLinkError(exec, vm, ASCIILiteral("imported function's signature doesn't match the provided WebAssembly function's signature")));
+                    return exception(createJSWebAssemblyLinkError(exec, vm, importFailMessage(import, "imported function", "signature doesn't match the provided WebAssembly function's signature")));
             }
             // iii. Otherwise:
             // a. Let closure be a new host function of the given signature which calls v by coercing WebAssembly arguments to JavaScript arguments via ToJSValue and returns the result, if any, by coercing via ToWebAssemblyValue.
@@ -215,19 +219,19 @@ JSWebAssemblyInstance* JSWebAssemblyInstance::create(VM& vm, ExecState* exec, JS
             JSWebAssemblyTable* table = jsDynamicCast<JSWebAssemblyTable*>(vm, value);
             // i. If v is not a WebAssembly.Table object, throw a WebAssembly.LinkError.
             if (!table)
-                return exception(createJSWebAssemblyLinkError(exec, vm, ASCIILiteral("Table import is not an instance of WebAssembly.Table")));
+                return exception(createJSWebAssemblyLinkError(exec, vm, importFailMessage(import, "Table import", "is not an instance of WebAssembly.Table")));
 
             uint32_t expectedInitial = moduleInformation.tableInformation.initial();
             uint32_t actualInitial = table->size();
             if (actualInitial < expectedInitial)
-                return exception(createJSWebAssemblyLinkError(exec, vm, ASCIILiteral("Table import provided an 'initial' that is too small")));
+                return exception(createJSWebAssemblyLinkError(exec, vm, importFailMessage(import, "Table import", "provided an 'initial' that is too small")));
 
             if (std::optional<uint32_t> expectedMaximum = moduleInformation.tableInformation.maximum()) {
                 std::optional<uint32_t> actualMaximum = table->maximum();
                 if (!actualMaximum)
-                    return exception(createJSWebAssemblyLinkError(exec, vm, ASCIILiteral("Table import does not have a 'maximum' but the module requires that it does")));
+                    return exception(createJSWebAssemblyLinkError(exec, vm, importFailMessage(import, "Table import", "does not have a 'maximum' but the module requires that it does")));
                 if (*actualMaximum > *expectedMaximum)
-                    return exception(createJSWebAssemblyLinkError(exec, vm, ASCIILiteral("Imported Table's 'maximum' is larger than the module's expected 'maximum'")));
+                    return exception(createJSWebAssemblyLinkError(exec, vm, importFailMessage(import, "Imported Table", "'maximum' is larger than the module's expected 'maximum'")));
             }
 
             // ii. Append v to tables.
@@ -244,20 +248,20 @@ JSWebAssemblyInstance* JSWebAssemblyInstance::create(VM& vm, ExecState* exec, JS
             JSWebAssemblyMemory* memory = jsDynamicCast<JSWebAssemblyMemory*>(vm, value);
             // i. If v is not a WebAssembly.Memory object, throw a WebAssembly.LinkError.
             if (!memory)
-                return exception(createJSWebAssemblyLinkError(exec, vm, ASCIILiteral("Memory import is not an instance of WebAssembly.Memory")));
+                return exception(createJSWebAssemblyLinkError(exec, vm, importFailMessage(import, "Memory import", "is not an instance of WebAssembly.Memory")));
 
             Wasm::PageCount declaredInitial = moduleInformation.memory.initial();
             Wasm::PageCount importedInitial = memory->memory().initial();
             if (importedInitial < declaredInitial)
-                return exception(createJSWebAssemblyLinkError(exec, vm, ASCIILiteral("Memory import provided an 'initial' that is smaller than the module's declared 'initial' import memory size")));
+                return exception(createJSWebAssemblyLinkError(exec, vm, importFailMessage(import, "Memory import", "provided an 'initial' that is smaller than the module's declared 'initial' import memory size")));
 
             if (Wasm::PageCount declaredMaximum = moduleInformation.memory.maximum()) {
                 Wasm::PageCount importedMaximum = memory->memory().maximum();
                 if (!importedMaximum)
-                    return exception(createJSWebAssemblyLinkError(exec, vm, ASCIILiteral("Memory import did not have a 'maximum' but the module requires that it does")));
+                    return exception(createJSWebAssemblyLinkError(exec, vm, importFailMessage(import, "Memory import", "did not have a 'maximum' but the module requires that it does")));
 
                 if (importedMaximum > declaredMaximum)
-                    return exception(createJSWebAssemblyLinkError(exec, vm, ASCIILiteral("Memory import provided a 'maximum' that is larger than the module's declared 'maximum' import memory size")));
+                    return exception(createJSWebAssemblyLinkError(exec, vm, importFailMessage(import, "Memory import", "provided a 'maximum' that is larger than the module's declared 'maximum' import memory size")));
             }
 
             // ii. Append v to memories.
@@ -273,9 +277,9 @@ JSWebAssemblyInstance* JSWebAssemblyInstance::create(VM& vm, ExecState* exec, JS
             ASSERT(moduleInformation.globals[import.kindIndex].mutability == Wasm::Global::Immutable);
             // ii. If the global_type of i is i64 or Type(v) is not Number, throw a WebAssembly.LinkError.
             if (moduleInformation.globals[import.kindIndex].type == Wasm::I64)
-                return exception(createJSWebAssemblyLinkError(exec, vm, ASCIILiteral("imported global cannot be an i64")));
+                return exception(createJSWebAssemblyLinkError(exec, vm, importFailMessage(import, "imported global", "cannot be an i64")));
             if (!value.isNumber())
-                return exception(createJSWebAssemblyLinkError(exec, vm, ASCIILiteral("imported global must be a number")));
+                return exception(createJSWebAssemblyLinkError(exec, vm, importFailMessage(import, "imported global", "must be a number")));
             // iii. Append ToWebAssemblyValue(v) to imports.
             ASSERT(numImportGlobals == import.kindIndex);
             switch (moduleInformation.globals[import.kindIndex].type) {
index 364b786..3107174 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2016-2017 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -73,7 +73,7 @@ void WebAssemblyModuleRecord::finishCreation(ExecState* exec, VM& vm, const Wasm
     Base::finishCreation(exec, vm);
     ASSERT(inherits(vm, info()));
     for (const auto& exp : moduleInformation.exports) {
-        Identifier field = Identifier::fromString(&vm, exp.field);
+        Identifier field = Identifier::fromString(&vm, String::fromUTF8(exp.field));
         addExportEntry(ExportEntry::createLocal(field, field));
     }
 }
@@ -99,8 +99,6 @@ void WebAssemblyModuleRecord::link(ExecState* exec, JSWebAssemblyModule* module,
     SymbolTable* exportSymbolTable = module->exportSymbolTable();
     unsigned functionImportCount = codeBlock->functionImportCount();
 
-    // FIXME wire up the imports. https://bugs.webkit.org/show_bug.cgi?id=165118
-
     // Let exports be a list of (string, JS value) pairs that is mapped from each external value e in instance.exports as follows:
     JSModuleEnvironment* moduleEnvironment = JSModuleEnvironment::create(vm, globalObject, nullptr, exportSymbolTable, JSValue(), this);
     for (const auto& exp : moduleInformation.exports) {
@@ -179,7 +177,7 @@ void WebAssemblyModuleRecord::link(ExecState* exec, JSWebAssemblyModule* module,
         bool shouldThrowReadOnlyError = false;
         bool ignoreReadOnlyErrors = true;
         bool putResult = false;
-        symbolTablePutTouchWatchpointSet(moduleEnvironment, exec, Identifier::fromString(&vm, exp.field), exportedValue, shouldThrowReadOnlyError, ignoreReadOnlyErrors, putResult);
+        symbolTablePutTouchWatchpointSet(moduleEnvironment, exec, Identifier::fromString(&vm, String::fromUTF8(exp.field)), exportedValue, shouldThrowReadOnlyError, ignoreReadOnlyErrors, putResult);
         RELEASE_ASSERT(putResult);
     }