You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
	
	
		
			217 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			JavaScript
		
	
		
		
			
		
	
	
			217 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			JavaScript
		
	
| 
											9 months ago
										 | /* | ||
|  | 	MIT License http://www.opensource.org/licenses/mit-license.php
 | ||
|  | 	Author Tobias Koppers @sokra | ||
|  | */ | ||
|  | 
 | ||
|  | "use strict"; | ||
|  | 
 | ||
|  | const { RawSource } = require("webpack-sources"); | ||
|  | const { UsageState } = require("../ExportsInfo"); | ||
|  | const Generator = require("../Generator"); | ||
|  | const InitFragment = require("../InitFragment"); | ||
|  | const RuntimeGlobals = require("../RuntimeGlobals"); | ||
|  | const Template = require("../Template"); | ||
|  | const ModuleDependency = require("../dependencies/ModuleDependency"); | ||
|  | const WebAssemblyExportImportedDependency = require("../dependencies/WebAssemblyExportImportedDependency"); | ||
|  | const WebAssemblyImportDependency = require("../dependencies/WebAssemblyImportDependency"); | ||
|  | 
 | ||
|  | /** @typedef {import("webpack-sources").Source} Source */ | ||
|  | /** @typedef {import("../Dependency")} Dependency */ | ||
|  | /** @typedef {import("../DependencyTemplates")} DependencyTemplates */ | ||
|  | /** @typedef {import("../Generator").GenerateContext} GenerateContext */ | ||
|  | /** @typedef {import("../NormalModule")} NormalModule */ | ||
|  | /** @typedef {import("../RuntimeTemplate")} RuntimeTemplate */ | ||
|  | 
 | ||
|  | const TYPES = new Set(["webassembly"]); | ||
|  | 
 | ||
|  | class WebAssemblyJavascriptGenerator extends Generator { | ||
|  | 	/** | ||
|  | 	 * @param {NormalModule} module fresh module | ||
|  | 	 * @returns {Set<string>} available types (do not mutate) | ||
|  | 	 */ | ||
|  | 	getTypes(module) { | ||
|  | 		return 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 | ||
|  | 	 * @returns {Source} generated code | ||
|  | 	 */ | ||
|  | 	generate(module, generateContext) { | ||
|  | 		const { | ||
|  | 			runtimeTemplate, | ||
|  | 			moduleGraph, | ||
|  | 			chunkGraph, | ||
|  | 			runtimeRequirements, | ||
|  | 			runtime | ||
|  | 		} = generateContext; | ||
|  | 		/** @type {InitFragment<InitFragment<string>>[]} */ | ||
|  | 		const initFragments = []; | ||
|  | 
 | ||
|  | 		const exportsInfo = moduleGraph.getExportsInfo(module); | ||
|  | 
 | ||
|  | 		let needExportsCopy = false; | ||
|  | 		const importedModules = new Map(); | ||
|  | 		const initParams = []; | ||
|  | 		let index = 0; | ||
|  | 		for (const dep of module.dependencies) { | ||
|  | 			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, | ||
|  | 							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); | ||
|  | 
 | ||
|  | 						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, | ||
|  | 										callContext: null, | ||
|  | 										defaultInterop: true, | ||
|  | 										initFragments, | ||
|  | 										runtime, | ||
|  | 										runtimeRequirements | ||
|  | 									}) | ||
|  | 								); | ||
|  | 							} | ||
|  | 						} | ||
|  | 					} | ||
|  | 				} | ||
|  | 				if (dep instanceof WebAssemblyExportImportedDependency) { | ||
|  | 					importData.names.add(dep.name); | ||
|  | 					const usedName = moduleGraph | ||
|  | 						.getExportsInfo(module) | ||
|  | 						.getUsedName(dep.exportName, runtime); | ||
|  | 					if (usedName) { | ||
|  | 						runtimeRequirements.add(RuntimeGlobals.exports); | ||
|  | 						const exportProp = `${module.exportsArgument}[${JSON.stringify( | ||
|  | 							usedName | ||
|  | 						)}]`;
 | ||
|  | 						const defineStatement = Template.asString([ | ||
|  | 							`${exportProp} = ${runtimeTemplate.exportFromImport({ | ||
|  | 								moduleGraph, | ||
|  | 								module: moduleGraph.getModule(dep), | ||
|  | 								request: dep.request, | ||
|  | 								importVar: importData.importVar, | ||
|  | 								originModule: module, | ||
|  | 								exportName: dep.name, | ||
|  | 								asiSafe: true, | ||
|  | 								isCall: false, | ||
|  | 								callContext: null, | ||
|  | 								defaultInterop: true, | ||
|  | 								initFragments, | ||
|  | 								runtime, | ||
|  | 								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, | ||
|  | 						originModule: module, | ||
|  | 						runtimeRequirements | ||
|  | 					}); | ||
|  | 					return importStatement[0] + importStatement[1] + reexports.join("\n"); | ||
|  | 				} | ||
|  | 			) | ||
|  | 		); | ||
|  | 
 | ||
|  | 		const copyAllExports = | ||
|  | 			exportsInfo.otherExportsInfo.getUsed(runtime) === UsageState.Unused && | ||
|  | 			!needExportsCopy; | ||
|  | 
 | ||
|  | 		// need these globals
 | ||
|  | 		runtimeRequirements.add(RuntimeGlobals.module); | ||
|  | 		runtimeRequirements.add(RuntimeGlobals.moduleId); | ||
|  | 		runtimeRequirements.add(RuntimeGlobals.wasmInstances); | ||
|  | 		if (exportsInfo.otherExportsInfo.getUsed(runtime) !== UsageState.Unused) { | ||
|  | 			runtimeRequirements.add(RuntimeGlobals.makeNamespaceObject); | ||
|  | 			runtimeRequirements.add(RuntimeGlobals.exports); | ||
|  | 		} | ||
|  | 		if (!copyAllExports) { | ||
|  | 			runtimeRequirements.add(RuntimeGlobals.exports); | ||
|  | 		} | ||
|  | 
 | ||
|  | 		// create source
 | ||
|  | 		const source = new RawSource( | ||
|  | 			[ | ||
|  | 				'"use strict";', | ||
|  | 				"// Instantiate WebAssembly module", | ||
|  | 				`var wasmExports = ${RuntimeGlobals.wasmInstances}[${module.moduleArgument}.id];`, | ||
|  | 
 | ||
|  | 				exportsInfo.otherExportsInfo.getUsed(runtime) !== UsageState.Unused | ||
|  | 					? `${RuntimeGlobals.makeNamespaceObject}(${module.exportsArgument});` | ||
|  | 					: "", | ||
|  | 
 | ||
|  | 				// this must be before import for circular dependencies
 | ||
|  | 				"// export exports from WebAssembly module", | ||
|  | 				copyAllExports | ||
|  | 					? `${module.moduleArgument}.exports = wasmExports;` | ||
|  | 					: "for(var name in wasmExports) " + | ||
|  | 					  `if(name) ` + | ||
|  | 					  `${module.exportsArgument}[name] = wasmExports[name];`, | ||
|  | 				"// exec imports from WebAssembly module (for esm order)", | ||
|  | 				importsCode, | ||
|  | 				"", | ||
|  | 				"// exec wasm module", | ||
|  | 				`wasmExports[""](${initParams.join(", ")})` | ||
|  | 			].join("\n") | ||
|  | 		); | ||
|  | 		return InitFragment.addToSource(source, initFragments, generateContext); | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | module.exports = WebAssemblyJavascriptGenerator; |