run.js 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. #!/usr/bin/env node
  2. "use strict";
  3. const fs = require("fs");
  4. const path = require("path");
  5. const { spawnSync } = require("child_process");
  6. const libwabt = require("../../build/libwabt.js");
  7. try {
  8. var V86 = require("../../build/libv86-debug.js").V86;
  9. }
  10. catch(e) {
  11. console.error(e);
  12. console.error("Failed to import build/libv86-debug.js. Run " +
  13. "`make build/libv86-debug.js` first.");
  14. process.exit(1);
  15. }
  16. const LOG_LEVEL = 0;
  17. const GIT_DIFF_FLAGS = [ "--no-index", "--patience", "--color=always"];
  18. const TEST_DIR = path.join(__dirname, "tests");
  19. const BUILD_DIR = path.join(TEST_DIR, "build");
  20. function run_all()
  21. {
  22. const asm_files = fs.readdirSync(TEST_DIR).filter(filename => filename.endsWith(".asm"));
  23. const files = asm_files.map(asm_file => {
  24. const name = asm_file.slice(0, -4);
  25. return {
  26. name,
  27. expect_file: path.relative(".", path.join(TEST_DIR, name + ".wast")),
  28. actual_file: path.relative(".", path.join(BUILD_DIR, name + ".actual.wast")),
  29. actual_wasm: path.relative(".", path.join(BUILD_DIR, name + ".wasm")),
  30. asm_file: path.join(TEST_DIR, name + ".asm"),
  31. executable_file: path.join(BUILD_DIR, name + ".bin"),
  32. };
  33. });
  34. files.forEach(run_test);
  35. }
  36. function run_test({ name, executable_file, expect_file, actual_file, actual_wasm, asm_file })
  37. {
  38. const emulator = new V86({
  39. autostart: false,
  40. memory_size: 2 * 1024 * 1024,
  41. log_level: LOG_LEVEL,
  42. });
  43. const executable = fs.readFileSync(executable_file);
  44. const asm = fs.readFileSync(asm_file);
  45. const is_32 = asm.includes("BITS 32\n");
  46. emulator.add_listener("emulator-loaded", function()
  47. {
  48. const cpu = emulator.v86.cpu;
  49. const hook_not_called_timeout = setTimeout(() => {
  50. throw new Error("Hook for code generation not called");
  51. }, 1000);
  52. cpu.test_hook_did_generate_wasm = function(wasm)
  53. {
  54. const wast = disassemble_wasm(wasm);
  55. clearTimeout(hook_not_called_timeout);
  56. fs.writeFileSync(actual_file, wast);
  57. fs.writeFileSync(actual_wasm, wasm);
  58. cpu.test_hook_did_generate_wasm = function()
  59. {
  60. cpu.test_hook_did_generate_wasm = function() {};
  61. throw new Error("Hook for wasm generation called multiple times");
  62. };
  63. if(!fs.existsSync(expect_file))
  64. {
  65. // enhanced workflow: If file doesn't exist yet print full diff
  66. var expect_file_for_diff = "/dev/null";
  67. }
  68. else
  69. {
  70. expect_file_for_diff = expect_file;
  71. }
  72. const result = spawnSync("git",
  73. [].concat(
  74. "diff",
  75. GIT_DIFF_FLAGS,
  76. expect_file_for_diff,
  77. actual_file
  78. ),
  79. { encoding: "utf8" });
  80. if(result.status)
  81. {
  82. console.log(result.stdout);
  83. console.log(result.stderr);
  84. const failure_message = `${name}.asm failed:
  85. The code generator produced different code. If you believe this change is intentional,
  86. verify the diff above and run the following command to accept the change:
  87. cp ${actual_file} ${expect_file}
  88. When done, re-run this test to confirm that all expect-tests pass.
  89. `;
  90. console.log(failure_message);
  91. process.exit(1);
  92. }
  93. else
  94. {
  95. console.log("%s ok", name);
  96. console.assert(!result.stdout);
  97. console.assert(!result.stderr);
  98. }
  99. };
  100. if(is_32)
  101. {
  102. cpu.is_32[0] = true;
  103. cpu.stack_size_32[0] = true;
  104. }
  105. const START_ADDRESS = 0x1000;
  106. cpu.mem8.set(executable, START_ADDRESS);
  107. cpu.jit_force_generate_unsafe(START_ADDRESS);
  108. });
  109. }
  110. function disassemble_wasm(wasm)
  111. {
  112. // Need to make a small copy otherwise libwabt goes nuts trying to copy
  113. // the whole underlying buffer
  114. wasm = wasm.slice();
  115. try
  116. {
  117. var module = libwabt.readWasm(wasm, { readDebugNames: false });
  118. module.generateNames();
  119. module.applyNames();
  120. return module.toText({ foldExprs: true, inlineExport: true });
  121. }
  122. finally
  123. {
  124. module && module.destroy();
  125. }
  126. }
  127. run_all();