webpack/lib/wasm-sync/WebAssemblyJavascriptGenera...

228 lines
7.1 KiB
JavaScript
Raw Normal View History

2018-04-28 00:53:07 +08:00
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
2018-07-30 23:08:51 +08:00
2018-04-28 00:53:07 +08:00
"use strict";
2018-07-30 23:08:51 +08:00
const { RawSource } = require("webpack-sources");
const { UsageState } = require("../ExportsInfo");
2018-04-28 00:53:07 +08:00
const Generator = require("../Generator");
const InitFragment = require("../InitFragment");
2024-11-01 04:19:07 +08:00
const { WEBASSEMBLY_TYPES } = require("../ModuleSourceTypesConstants");
const RuntimeGlobals = require("../RuntimeGlobals");
2018-04-28 00:53:07 +08:00
const Template = require("../Template");
2020-08-07 23:05:48 +08:00
const ModuleDependency = require("../dependencies/ModuleDependency");
const WebAssemblyExportImportedDependency = require("../dependencies/WebAssemblyExportImportedDependency");
2018-07-30 23:08:51 +08:00
const WebAssemblyImportDependency = require("../dependencies/WebAssemblyImportDependency");
2018-04-28 00:53:07 +08:00
/** @typedef {import("webpack-sources").Source} Source */
2020-08-03 02:09:36 +08:00
/** @typedef {import("../Dependency")} Dependency */
2018-07-23 18:19:16 +08:00
/** @typedef {import("../DependencyTemplates")} DependencyTemplates */
/** @typedef {import("../Generator").GenerateContext} GenerateContext */
2024-02-17 01:39:12 +08:00
/** @typedef {import("../Module")} Module */
2024-11-01 04:19:07 +08:00
/** @typedef {import("../Module").SourceTypes} SourceTypes */
2018-07-30 23:08:51 +08:00
/** @typedef {import("../NormalModule")} NormalModule */
/** @typedef {import("../RuntimeTemplate")} RuntimeTemplate */
2018-04-28 00:53:07 +08:00
class WebAssemblyJavascriptGenerator extends Generator {
/**
* @param {NormalModule} module fresh module
2024-11-01 04:19:07 +08:00
* @returns {SourceTypes} available types (do not mutate)
*/
getTypes(module) {
2024-11-01 04:19:07 +08:00
return WEBASSEMBLY_TYPES;
}
/**
* @param {NormalModule} module the module
* @param {string=} type source type
* @returns {number} estimate size of the module
*/
getSize(module, type) {
return 95 + module.dependencies.length * 5;
}
/**
* @param {NormalModule} module module for which the code should be generated
* @param {GenerateContext} generateContext context for generate
2024-10-24 04:30:31 +08:00
* @returns {Source | null} generated code
*/
generate(module, generateContext) {
const {
runtimeTemplate,
moduleGraph,
chunkGraph,
runtimeRequirements,
runtime
} = generateContext;
2023-05-26 02:31:28 +08:00
/** @type {InitFragment<InitFragment<string>>[]} */
const initFragments = [];
const exportsInfo = moduleGraph.getExportsInfo(module);
2018-04-28 00:53:07 +08:00
let needExportsCopy = false;
const importedModules = new Map();
const initParams = [];
let index = 0;
for (const dep of module.dependencies) {
2020-08-07 23:05:48 +08:00
const moduleDep =
dep && dep instanceof ModuleDependency ? dep : undefined;
if (moduleGraph.getModule(dep)) {
let importData = importedModules.get(moduleGraph.getModule(dep));
if (importData === undefined) {
importedModules.set(
moduleGraph.getModule(dep),
(importData = {
importVar: `m${index}`,
index,
2020-08-07 23:05:48 +08:00
request: (moduleDep && moduleDep.userRequest) || undefined,
names: new Set(),
reexports: []
})
);
index++;
}
if (dep instanceof WebAssemblyImportDependency) {
importData.names.add(dep.name);
if (dep.description.type === "GlobalType") {
const exportName = dep.name;
const importedModule = moduleGraph.getModule(dep);
2018-04-28 00:53:07 +08:00
if (importedModule) {
const usedName = moduleGraph
.getExportsInfo(importedModule)
.getUsedName(exportName, runtime);
if (usedName) {
initParams.push(
runtimeTemplate.exportFromImport({
moduleGraph,
module: importedModule,
request: dep.request,
importVar: importData.importVar,
originModule: module,
exportName: dep.name,
asiSafe: true,
isCall: false,
2018-11-17 01:18:44 +08:00
callContext: null,
defaultInterop: true,
initFragments,
runtime,
2018-11-17 01:18:44 +08:00
runtimeRequirements
})
);
}
}
}
}
if (dep instanceof WebAssemblyExportImportedDependency) {
importData.names.add(dep.name);
const usedName = moduleGraph
.getExportsInfo(module)
.getUsedName(dep.exportName, runtime);
if (usedName) {
2018-11-17 01:18:44 +08:00
runtimeRequirements.add(RuntimeGlobals.exports);
const exportProp = `${module.exportsArgument}[${JSON.stringify(
usedName
)}]`;
const defineStatement = Template.asString([
`${exportProp} = ${runtimeTemplate.exportFromImport({
moduleGraph,
2024-02-17 01:39:12 +08:00
module: /** @type {Module} */ (moduleGraph.getModule(dep)),
request: dep.request,
importVar: importData.importVar,
originModule: module,
exportName: dep.name,
asiSafe: true,
isCall: false,
2018-11-17 01:18:44 +08:00
callContext: null,
defaultInterop: true,
initFragments,
runtime,
2018-11-17 01:18:44 +08:00
runtimeRequirements
})};`,
`if(WebAssembly.Global) ${exportProp} = ` +
`new WebAssembly.Global({ value: ${JSON.stringify(
dep.valueType
)} }, ${exportProp});`
]);
importData.reexports.push(defineStatement);
needExportsCopy = true;
}
}
}
}
const importsCode = Template.asString(
Array.from(
importedModules,
([module, { importVar, request, reexports }]) => {
const importStatement = runtimeTemplate.importStatement({
module,
chunkGraph,
request,
importVar,
2018-11-17 01:18:44 +08:00
originModule: module,
runtimeRequirements
});
return importStatement[0] + importStatement[1] + reexports.join("\n");
}
)
);
2018-04-28 15:57:21 +08:00
2018-11-17 01:18:44 +08:00
const copyAllExports =
exportsInfo.otherExportsInfo.getUsed(runtime) === UsageState.Unused &&
!needExportsCopy;
2018-11-17 01:18:44 +08:00
// need these globals
runtimeRequirements.add(RuntimeGlobals.module);
runtimeRequirements.add(RuntimeGlobals.moduleId);
2018-11-17 01:18:44 +08:00
runtimeRequirements.add(RuntimeGlobals.wasmInstances);
if (exportsInfo.otherExportsInfo.getUsed(runtime) !== UsageState.Unused) {
2018-11-17 01:18:44 +08:00
runtimeRequirements.add(RuntimeGlobals.makeNamespaceObject);
runtimeRequirements.add(RuntimeGlobals.exports);
}
if (!copyAllExports) {
runtimeRequirements.add(RuntimeGlobals.exports);
}
2018-04-28 15:57:21 +08:00
// create source
2018-04-28 00:53:07 +08:00
const source = new RawSource(
[
'"use strict";',
"// Instantiate WebAssembly module",
`var wasmExports = ${RuntimeGlobals.wasmInstances}[${module.moduleArgument}.id];`,
2018-04-28 00:53:07 +08:00
exportsInfo.otherExportsInfo.getUsed(runtime) !== UsageState.Unused
? `${RuntimeGlobals.makeNamespaceObject}(${module.exportsArgument});`
: "",
2018-04-28 15:57:21 +08:00
// this must be before import for circular dependencies
2018-04-28 00:53:07 +08:00
"// export exports from WebAssembly module",
2018-11-17 01:18:44 +08:00
copyAllExports
? `${module.moduleArgument}.exports = wasmExports;`
: "for(var name in wasmExports) " +
2024-07-31 12:23:44 +08:00
"if(name) " +
2024-01-14 09:41:34 +08:00
`${module.exportsArgument}[name] = wasmExports[name];`,
2018-04-28 15:57:21 +08:00
"// exec imports from WebAssembly module (for esm order)",
importsCode,
"",
2018-04-28 15:57:21 +08:00
"// exec wasm module",
`wasmExports[""](${initParams.join(", ")})`
2018-04-28 00:53:07 +08:00
].join("\n")
);
return InitFragment.addToSource(source, initFragments, generateContext);
2018-04-28 00:53:07 +08:00
}
/**
* @param {Error} error the error
* @param {NormalModule} module module for which the code should be generated
* @param {GenerateContext} generateContext context for generate
* @returns {Source | null} generated code
*/
generateError(error, module, generateContext) {
return new RawSource(`throw new Error(${JSON.stringify(error.message)});`);
}
2018-04-28 00:53:07 +08:00
}
module.exports = WebAssemblyJavascriptGenerator;