WebAssemblyJavascriptGenerator.js 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. const { RawSource } = require("webpack-sources");
  7. const { UsageState } = require("../ExportsInfo");
  8. const Generator = require("../Generator");
  9. const InitFragment = require("../InitFragment");
  10. const { WEBASSEMBLY_TYPES } = require("../ModuleSourceTypesConstants");
  11. const RuntimeGlobals = require("../RuntimeGlobals");
  12. const Template = require("../Template");
  13. const ModuleDependency = require("../dependencies/ModuleDependency");
  14. const WebAssemblyExportImportedDependency = require("../dependencies/WebAssemblyExportImportedDependency");
  15. const WebAssemblyImportDependency = require("../dependencies/WebAssemblyImportDependency");
  16. /** @typedef {import("webpack-sources").Source} Source */
  17. /** @typedef {import("../Dependency")} Dependency */
  18. /** @typedef {import("../DependencyTemplates")} DependencyTemplates */
  19. /** @typedef {import("../Generator").GenerateContext} GenerateContext */
  20. /** @typedef {import("../Module")} Module */
  21. /** @typedef {import("../Module").SourceTypes} SourceTypes */
  22. /** @typedef {import("../NormalModule")} NormalModule */
  23. /** @typedef {import("../RuntimeTemplate")} RuntimeTemplate */
  24. class WebAssemblyJavascriptGenerator extends Generator {
  25. /**
  26. * @param {NormalModule} module fresh module
  27. * @returns {SourceTypes} available types (do not mutate)
  28. */
  29. getTypes(module) {
  30. return WEBASSEMBLY_TYPES;
  31. }
  32. /**
  33. * @param {NormalModule} module the module
  34. * @param {string=} type source type
  35. * @returns {number} estimate size of the module
  36. */
  37. getSize(module, type) {
  38. return 95 + module.dependencies.length * 5;
  39. }
  40. /**
  41. * @param {NormalModule} module module for which the code should be generated
  42. * @param {GenerateContext} generateContext context for generate
  43. * @returns {Source | null} generated code
  44. */
  45. generate(module, generateContext) {
  46. const {
  47. runtimeTemplate,
  48. moduleGraph,
  49. chunkGraph,
  50. runtimeRequirements,
  51. runtime
  52. } = generateContext;
  53. /** @type {InitFragment<InitFragment<string>>[]} */
  54. const initFragments = [];
  55. const exportsInfo = moduleGraph.getExportsInfo(module);
  56. let needExportsCopy = false;
  57. const importedModules = new Map();
  58. const initParams = [];
  59. let index = 0;
  60. for (const dep of module.dependencies) {
  61. const moduleDep =
  62. dep && dep instanceof ModuleDependency ? dep : undefined;
  63. if (moduleGraph.getModule(dep)) {
  64. let importData = importedModules.get(moduleGraph.getModule(dep));
  65. if (importData === undefined) {
  66. importedModules.set(
  67. moduleGraph.getModule(dep),
  68. (importData = {
  69. importVar: `m${index}`,
  70. index,
  71. request: (moduleDep && moduleDep.userRequest) || undefined,
  72. names: new Set(),
  73. reexports: []
  74. })
  75. );
  76. index++;
  77. }
  78. if (dep instanceof WebAssemblyImportDependency) {
  79. importData.names.add(dep.name);
  80. if (dep.description.type === "GlobalType") {
  81. const exportName = dep.name;
  82. const importedModule = moduleGraph.getModule(dep);
  83. if (importedModule) {
  84. const usedName = moduleGraph
  85. .getExportsInfo(importedModule)
  86. .getUsedName(exportName, runtime);
  87. if (usedName) {
  88. initParams.push(
  89. runtimeTemplate.exportFromImport({
  90. moduleGraph,
  91. module: importedModule,
  92. request: dep.request,
  93. importVar: importData.importVar,
  94. originModule: module,
  95. exportName: dep.name,
  96. asiSafe: true,
  97. isCall: false,
  98. callContext: null,
  99. defaultInterop: true,
  100. initFragments,
  101. runtime,
  102. runtimeRequirements
  103. })
  104. );
  105. }
  106. }
  107. }
  108. }
  109. if (dep instanceof WebAssemblyExportImportedDependency) {
  110. importData.names.add(dep.name);
  111. const usedName = moduleGraph
  112. .getExportsInfo(module)
  113. .getUsedName(dep.exportName, runtime);
  114. if (usedName) {
  115. runtimeRequirements.add(RuntimeGlobals.exports);
  116. const exportProp = `${module.exportsArgument}[${JSON.stringify(
  117. usedName
  118. )}]`;
  119. const defineStatement = Template.asString([
  120. `${exportProp} = ${runtimeTemplate.exportFromImport({
  121. moduleGraph,
  122. module: /** @type {Module} */ (moduleGraph.getModule(dep)),
  123. request: dep.request,
  124. importVar: importData.importVar,
  125. originModule: module,
  126. exportName: dep.name,
  127. asiSafe: true,
  128. isCall: false,
  129. callContext: null,
  130. defaultInterop: true,
  131. initFragments,
  132. runtime,
  133. runtimeRequirements
  134. })};`,
  135. `if(WebAssembly.Global) ${exportProp} = ` +
  136. `new WebAssembly.Global({ value: ${JSON.stringify(
  137. dep.valueType
  138. )} }, ${exportProp});`
  139. ]);
  140. importData.reexports.push(defineStatement);
  141. needExportsCopy = true;
  142. }
  143. }
  144. }
  145. }
  146. const importsCode = Template.asString(
  147. Array.from(
  148. importedModules,
  149. ([module, { importVar, request, reexports }]) => {
  150. const importStatement = runtimeTemplate.importStatement({
  151. module,
  152. chunkGraph,
  153. request,
  154. importVar,
  155. originModule: module,
  156. runtimeRequirements
  157. });
  158. return importStatement[0] + importStatement[1] + reexports.join("\n");
  159. }
  160. )
  161. );
  162. const copyAllExports =
  163. exportsInfo.otherExportsInfo.getUsed(runtime) === UsageState.Unused &&
  164. !needExportsCopy;
  165. // need these globals
  166. runtimeRequirements.add(RuntimeGlobals.module);
  167. runtimeRequirements.add(RuntimeGlobals.moduleId);
  168. runtimeRequirements.add(RuntimeGlobals.wasmInstances);
  169. if (exportsInfo.otherExportsInfo.getUsed(runtime) !== UsageState.Unused) {
  170. runtimeRequirements.add(RuntimeGlobals.makeNamespaceObject);
  171. runtimeRequirements.add(RuntimeGlobals.exports);
  172. }
  173. if (!copyAllExports) {
  174. runtimeRequirements.add(RuntimeGlobals.exports);
  175. }
  176. // create source
  177. const source = new RawSource(
  178. [
  179. '"use strict";',
  180. "// Instantiate WebAssembly module",
  181. `var wasmExports = ${RuntimeGlobals.wasmInstances}[${module.moduleArgument}.id];`,
  182. exportsInfo.otherExportsInfo.getUsed(runtime) !== UsageState.Unused
  183. ? `${RuntimeGlobals.makeNamespaceObject}(${module.exportsArgument});`
  184. : "",
  185. // this must be before import for circular dependencies
  186. "// export exports from WebAssembly module",
  187. copyAllExports
  188. ? `${module.moduleArgument}.exports = wasmExports;`
  189. : "for(var name in wasmExports) " +
  190. "if(name) " +
  191. `${module.exportsArgument}[name] = wasmExports[name];`,
  192. "// exec imports from WebAssembly module (for esm order)",
  193. importsCode,
  194. "",
  195. "// exec wasm module",
  196. `wasmExports[""](${initParams.join(", ")})`
  197. ].join("\n")
  198. );
  199. return InitFragment.addToSource(source, initFragments, generateContext);
  200. }
  201. }
  202. module.exports = WebAssemblyJavascriptGenerator;