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