AsyncWebAssemblyParser.js 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. const t = require("@webassemblyjs/ast");
  7. const { decode } = require("@webassemblyjs/wasm-parser");
  8. const EnvironmentNotSupportAsyncWarning = require("../EnvironmentNotSupportAsyncWarning");
  9. const Parser = require("../Parser");
  10. const StaticExportsDependency = require("../dependencies/StaticExportsDependency");
  11. const WebAssemblyImportDependency = require("../dependencies/WebAssemblyImportDependency");
  12. /** @typedef {import("./AsyncWebAssemblyModulesPlugin").AsyncWasmModuleClass} AsyncWasmModule */
  13. /** @typedef {import("../Module").BuildInfo} BuildInfo */
  14. /** @typedef {import("../Module").BuildMeta} BuildMeta */
  15. /** @typedef {import("../NormalModule")} NormalModule */
  16. /** @typedef {import("../Parser").ParserState} ParserState */
  17. /** @typedef {import("../Parser").PreparsedAst} PreparsedAst */
  18. const WASM_HEADER = Buffer.from([0x00, 0x61, 0x73, 0x6d]);
  19. const decoderOpts = {
  20. ignoreCodeSection: true,
  21. ignoreDataSection: true,
  22. // this will avoid having to lookup with identifiers in the ModuleContext
  23. ignoreCustomNameSection: true
  24. };
  25. class WebAssemblyParser extends Parser {
  26. /**
  27. * Parses the provided source and updates the parser state.
  28. * @param {string | Buffer | PreparsedAst} source the source to parse
  29. * @param {ParserState} state the parser state
  30. * @returns {ParserState} the parser state
  31. */
  32. parse(source, state) {
  33. if (!Buffer.isBuffer(source)) {
  34. throw new Error("WebAssemblyParser input must be a Buffer");
  35. }
  36. const buildMeta = /** @type {BuildMeta} */ (state.module.buildMeta);
  37. buildMeta.exportsType = "namespace";
  38. buildMeta.async = true;
  39. EnvironmentNotSupportAsyncWarning.check(
  40. state.module,
  41. state.compilation.runtimeTemplate,
  42. "asyncWebAssembly"
  43. );
  44. // flag it as async module
  45. const buildInfo = /** @type {BuildInfo} */ (state.module.buildInfo);
  46. buildInfo.strict = true;
  47. if (/** @type {AsyncWasmModule} */ (state.module).phase === "source") {
  48. // For source phase, only validate magic header
  49. if (source.length < 4 || !source.subarray(0, 4).equals(WASM_HEADER)) {
  50. throw new Error(
  51. "Source phase imports require valid WebAssembly modules. Invalid magic header (expected \\0asm)."
  52. );
  53. }
  54. // Source phase exports the WebAssembly.Module as default
  55. state.module.addDependency(
  56. new StaticExportsDependency(["default"], false)
  57. );
  58. // Skip full parsing - no exports/imports needed for source phase
  59. return state;
  60. }
  61. // parse it
  62. const program = decode(source, decoderOpts);
  63. const module = program.body[0];
  64. /** @type {string[]} */
  65. const exports = [];
  66. t.traverse(module, {
  67. ModuleExport({ node }) {
  68. exports.push(node.name);
  69. },
  70. ModuleImport({ node }) {
  71. const dep = new WebAssemblyImportDependency(
  72. node.module,
  73. node.name,
  74. node.descr,
  75. false
  76. );
  77. state.module.addDependency(dep);
  78. }
  79. });
  80. state.module.addDependency(new StaticExportsDependency(exports, false));
  81. return state;
  82. }
  83. }
  84. module.exports = WebAssemblyParser;