table_signatures.js 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft Corporation and contributors. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. WScript.Flag("-wasmI64");
  6. WScript.LoadScriptFile("../UnitTestFramework/UnitTestFramework.js");
  7. const types = {
  8. i32: {param: "i32", result: "(result i32)", body: "i32.const 1"},
  9. i64: {param: "i64", result: "(result i64)", body: "i64.const 1"},
  10. f32: {param: "f32", result: "(result f32)", body: "f32.const 1"},
  11. f64: {param: "f64", result: "(result f64)", body: "f64.const 1"},
  12. void: {param: "", result: "", body: ""},
  13. };
  14. function* paramTypes() {
  15. while (true) {
  16. yield types.i32;
  17. yield types.i64;
  18. yield types.i32;
  19. yield types.f32;
  20. yield types.i32;
  21. yield types.f64;
  22. }
  23. }
  24. class Signature {
  25. constructor(id, resType) {
  26. this.id = id;
  27. this.params = [];
  28. this.result = types[resType];
  29. }
  30. addParam(type) {
  31. this.params.push(type);
  32. }
  33. toWat() {
  34. // Types for the custom functions
  35. return `(type $t${this.id} (func (param ${this.params.map(t => t.param).join(" ")}) ${this.result.result}))`;
  36. }
  37. makeCallwat() {
  38. // Type of the call to the custom functions (first param is the index in the table)
  39. return `(type $callt${this.id} (func (param i32 ${this.params.map(t => t.param).join(" ")}) ${this.result.result}))`;
  40. }
  41. }
  42. const signatures = [];
  43. const nArgumentsToTest = [0, 1, 2, 3, 10, 25, 50, 200];
  44. for (const resType in types) {
  45. for (const nArgs of nArgumentsToTest) {
  46. const gen = paramTypes();
  47. const sigId = signatures.length;
  48. const signature = new Signature(sigId, resType);
  49. for (let j = 0; j < nArgs; ++j) {
  50. signature.addParam(gen.next().value);
  51. }
  52. signatures.push(signature);
  53. }
  54. }
  55. const moduleText = `
  56. (module
  57. ${signatures.map(sig => sig.toWat()).join("\n ")}
  58. ${signatures.map(sig => sig.makeCallwat()).join("\n ")}
  59. (table ${signatures.length} anyfunc)
  60. ;; Add custom functions to the table
  61. (elem (i32.const 0)
  62. ${signatures.map(sig => `$f${sig.id}`).join(" ")}
  63. )
  64. ;; Functions to put in the table
  65. ${signatures.map(sig => `
  66. (func $f${sig.id} (type $t${sig.id}) ${sig.result.body})`
  67. ).join("")}
  68. ;; Functions to call from the table
  69. ${signatures.map(sig => `
  70. (func (export "call${sig.id}") (type $callt${sig.id})
  71. ${sig.params.map((_, iParam) => `(get_local ${iParam + 1})`).join(" ")}
  72. (call_indirect (type $t${sig.id}) (get_local 0))
  73. )`
  74. ).join("")}
  75. )`;
  76. const mod = new WebAssembly.Module(WebAssembly.wabt.convertWast2Wasm(moduleText));
  77. const ex = new WebAssembly.Instance(mod).exports;
  78. const tests = signatures.map(sig => ({
  79. name: `Signature $t${sig.id}`,
  80. body() {
  81. if (argv.verbose) {
  82. console.log(`signature wat: ${sig.toWat()}`);
  83. }
  84. assert.doesNotThrow(() => ex[`call${sig.id}`](sig.id), `Calling signature ${sig.id} should not throw`);
  85. for (let j = 0; j < signatures.length; ++j) {
  86. if (j !== sig.id) {
  87. assert.throws(() => ex[`call${j}`](sig.id), WebAssembly.RuntimeError, `Expected signature mismatch between\n${sig.toWat()}\n${signatures[j].toWat()}`, "Function called with invalid signature");
  88. }
  89. }
  90. }
  91. }));
  92. WScript.LoadScriptFile("../UnitTestFramework/yargs.js");
  93. const argv = yargsParse(WScript.Arguments, {
  94. boolean: ["verbose"],
  95. number: ["start", "end"],
  96. default: {
  97. verbose: true,
  98. start: 0,
  99. end: tests.length
  100. }
  101. }).argv;
  102. const todoTests = tests
  103. .slice(argv.start, argv.end);
  104. testRunner.run(todoTests, {verbose: argv.verbose});