call.js 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. const verbose = false;
  6. const defaultffi = {spectest: {print}};
  7. main().catch(e => print(e));
  8. async function main() {
  9. print("Compile call.0.wasm");
  10. const mod1 = await WebAssembly.compile(readbuffer("binaries/call.0.wasm"));
  11. print("Instanciate call.0.wasm");
  12. const inst1 = new WebAssembly.Instance(mod1, {});
  13. testInstance(inst1);
  14. print("Compile call.1.wasm");
  15. const mod2 = new WebAssembly.Module(readbuffer("binaries/call.1.wasm"));
  16. print("Instanciate call.1.wasm");
  17. const inst2 = new WebAssembly.Instance(mod2, Object.assign({}, defaultffi, {test: inst1.exports}));
  18. testInstance(inst2);
  19. const overwriteMethods = {
  20. "i_func-i32": print,
  21. "i_func-i64": () => print("Should have trapped"),
  22. "i_func-f32": print,
  23. "i_func-f64": print,
  24. "i_func->i32": () => 5,
  25. "i_func->i64": () => print("Will trap when converting return value"),
  26. "i_func->f32": () => 3.14,
  27. "i_func->f64": () => -5.47,
  28. "i_func-i32->i32": a => a - 1,
  29. "i_func-i64->i64": () => print("Should have trapped"),
  30. "i_func-f32->f32": a => a + 1.4,
  31. "i_func-f64->f64": a => a * 2,
  32. };
  33. const imports = Object.assign({}, inst1.exports, overwriteMethods);
  34. print("Instanciate call.1.wasm");
  35. const inst3 = new WebAssembly.Instance(mod2, Object.assign({}, defaultffi, {test: imports}));
  36. const tests = [
  37. {run: invoke, name: "func-i32", params: [48]},
  38. {run: assertTrap, name: "func-i64"},
  39. {run: invoke, name: "func-f32", params: [5.148]},
  40. {run: invoke, name: "func-f64", params: [8.476]},
  41. {run: assertReturn, name: "func->i32", check: a => a === 5},
  42. {run: assertTrap, name: "func->i64"},
  43. {run: assertReturn, name: "func->f32", check: a => Math.fround(a) === Math.fround(3.14)},
  44. {run: assertReturn, name: "func->f64", check: a => a === -5.47},
  45. {run: assertReturn, name: "func-i32->i32", params: [7], check: a => a === 6},
  46. {run: assertTrap, name: "func-i64->i64"},
  47. {run: assertReturn, name: "func-f32->f32", params: [2.6], check: a => Math.fround(a) === Math.fround(4.0)},
  48. {run: assertReturn, name: "func-f64->f64", params: [6], check: a => a === 12},
  49. {run: assertReturn, name: "i32", params: [4], check: a => a === (4 - 1 + 5)},
  50. {run: assertTrap, name: "i64"},
  51. {run: assertReturn, name: "f32", params: [25.1], check: a => Math.fround(a) === Math.fround(3.14 + 1.4 + 25.1)},
  52. {run: assertReturn, name: "f64", params: [45], check: a => a === (45 * 2 - 5.47)},
  53. ];
  54. let testsPassed = 0;
  55. for (const test of tests) {
  56. const {run, name, params = [], check} = test;
  57. const testName = `js-${name}`;
  58. try {
  59. testsPassed += +run(inst3.exports[name].bind(null, ...params), testName, check);
  60. } catch (e) {
  61. print(`${testName} failed. unexpectedly threw: ${e}`);
  62. }
  63. }
  64. print(`${testsPassed}/${tests.length} tests passed\n\n`);
  65. }
  66. function invoke(method) {
  67. method();
  68. return true;
  69. }
  70. function testInstance(instance) {
  71. const {exports} = instance;
  72. const tests = retrieveTestMethods(exports);
  73. let testsPassed = 0;
  74. for (const methodName of tests) {
  75. const method = exports[methodName];
  76. try {
  77. if (methodName.startsWith("$assert_return")) {
  78. testsPassed += +assertReturn(method, methodName, a => a === 1);
  79. } else if (methodName.startsWith("$assert_trap")) {
  80. testsPassed += +assertTrap(method, methodName);
  81. } else if (methodName.startsWith("$action")) {
  82. testsPassed += +invoke(method);
  83. }
  84. } catch (e) {
  85. print(`${methodName} failed. unexpectedly threw: ${e}`);
  86. }
  87. }
  88. print(`${testsPassed}/${tests.length} tests passed\n\n`);
  89. }
  90. function assertReturn(method, methodName, check) {
  91. const val = method();
  92. if (!check(val)) {
  93. print(`${methodName} failed.`);
  94. } else {
  95. if (verbose) {
  96. print(`${methodName} passed.`);
  97. }
  98. return true;
  99. }
  100. }
  101. function assertTrap(method, methodName) {
  102. try {
  103. method();
  104. print(`${methodName} failed. Expected an error to be thrown`);
  105. } catch (e) {
  106. if (e instanceof WebAssembly.RuntimeError || e instanceof TypeError) {
  107. if (verbose) {
  108. print(`${methodName} passed. Error thrown: ${e}`);
  109. }
  110. return true;
  111. }
  112. throw e;
  113. }
  114. }
  115. function retrieveTestMethods(exports) {
  116. return Object.keys(exports)
  117. .map(key => /_(\d+)$/.exec(key))
  118. .filter(m => !!m)
  119. .map(m => ({order: parseInt(m[1]), key: m.input}))
  120. .sort((a, b) => a.order - b.order)
  121. .map(({key}) => key);
  122. }