| 
									
										
										
										
											2018-01-24 06:09:26 +08:00
										 |  |  | /* | 
					
						
							|  |  |  | 	MIT License http://www.opensource.org/licenses/mit-license.php
 | 
					
						
							|  |  |  | 	Author Tobias Koppers @sokra | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | "use strict"; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-28 00:53:07 +08:00
										 |  |  | const Generator = require("../Generator"); | 
					
						
							| 
									
										
										
										
											2018-05-09 22:19:31 +08:00
										 |  |  | const Template = require("../Template"); | 
					
						
							| 
									
										
										
										
											2018-05-11 20:24:40 +08:00
										 |  |  | const WebAssemblyUtils = require("./WebAssemblyUtils"); | 
					
						
							| 
									
										
										
										
											2018-03-09 00:54:06 +08:00
										 |  |  | const { RawSource } = require("webpack-sources"); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-14 19:00:19 +08:00
										 |  |  | const { shrinkPaddedLEB128 } = require("@webassemblyjs/wasm-opt"); | 
					
						
							| 
									
										
										
										
											2018-05-09 23:40:38 +08:00
										 |  |  | const { editWithAST, addWithAST } = require("@webassemblyjs/wasm-edit"); | 
					
						
							| 
									
										
										
										
											2018-05-11 22:46:33 +08:00
										 |  |  | const { decode } = require("@webassemblyjs/wasm-parser"); | 
					
						
							| 
									
										
										
										
											2018-03-09 00:54:06 +08:00
										 |  |  | const t = require("@webassemblyjs/ast"); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-11 20:24:40 +08:00
										 |  |  | /** @typedef {import("../Module")} Module */ | 
					
						
							|  |  |  | /** @typedef {import("./WebAssemblyUtils").UsedWasmDependency} UsedWasmDependency */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-14 19:00:19 +08:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @typedef {(ArrayBuffer) => ArrayBuffer} ArrayBufferTransform | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * Run some preprocessing on the binary before wasm-edit | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * @param {ArrayBuffer} ab - original binary | 
					
						
							|  |  |  |  * @returns {ArrayBufferTransform} transform | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | function preprocess(ab) { | 
					
						
							|  |  |  | 	const optBin = shrinkPaddedLEB128(new Uint8Array(ab)); | 
					
						
							|  |  |  | 	return optBin.buffer; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-11 22:30:06 +08:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @template T | 
					
						
							|  |  |  |  * @param {Function[]} fns transforms | 
					
						
							|  |  |  |  * @returns {Function} composed transform | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2018-03-09 00:54:06 +08:00
										 |  |  | function compose(...fns) { | 
					
						
							| 
									
										
										
										
											2018-05-09 22:19:31 +08:00
										 |  |  | 	return fns.reduce((prevFn, nextFn) => { | 
					
						
							| 
									
										
										
										
											2018-03-09 00:54:06 +08:00
										 |  |  | 		return value => nextFn(prevFn(value)); | 
					
						
							|  |  |  | 	}, value => value); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-12 18:43:20 +08:00
										 |  |  | // Utility functions
 | 
					
						
							| 
									
										
										
										
											2018-05-09 23:40:38 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * @param {t.ModuleImport} n the import | 
					
						
							|  |  |  |  * @returns {boolean} true, if a global was imported | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | const isGlobalImport = n => n.descr.type === "GlobalType"; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * @param {t.ModuleImport} n the import | 
					
						
							|  |  |  |  * @returns {boolean} true, if a func was imported | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | const isFuncImport = n => n.descr.type === "FuncImportDescr"; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-28 00:53:07 +08:00
										 |  |  | // TODO replace with @callback
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-09 00:54:06 +08:00
										 |  |  | /** | 
					
						
							| 
									
										
										
										
											2018-03-12 18:43:20 +08:00
										 |  |  |  * Removes the start instruction | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2018-03-14 21:49:33 +08:00
										 |  |  |  * @param {Object} state - unused state | 
					
						
							| 
									
										
										
										
											2018-04-28 00:53:07 +08:00
										 |  |  |  * @returns {ArrayBufferTransform} transform | 
					
						
							| 
									
										
										
										
											2018-03-09 00:54:06 +08:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2018-03-12 18:43:20 +08:00
										 |  |  | const removeStartFunc = state => bin => { | 
					
						
							| 
									
										
										
										
											2018-05-09 23:40:38 +08:00
										 |  |  | 	return editWithAST(state.ast, bin, { | 
					
						
							| 
									
										
										
										
											2018-03-12 18:43:20 +08:00
										 |  |  | 		Start(path) { | 
					
						
							|  |  |  | 			path.remove(); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}); | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2018-03-09 00:54:06 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-15 01:11:13 +08:00
										 |  |  | /** | 
					
						
							|  |  |  |  * Retrieve the start function | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * @param {Object} ast - Module's AST | 
					
						
							|  |  |  |  * @returns {t.Identifier | undefined} - node if any | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2018-03-12 18:43:20 +08:00
										 |  |  | function getStartFuncIndex(ast) { | 
					
						
							| 
									
										
										
										
											2018-03-09 00:54:06 +08:00
										 |  |  | 	let startAtFuncIndex; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-12 18:43:20 +08:00
										 |  |  | 	t.traverse(ast, { | 
					
						
							| 
									
										
										
										
											2018-05-07 15:49:14 +08:00
										 |  |  | 		Start({ node }) { | 
					
						
							|  |  |  | 			startAtFuncIndex = node.index; | 
					
						
							| 
									
										
										
										
											2018-03-09 00:54:06 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	}); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-12 18:43:20 +08:00
										 |  |  | 	return startAtFuncIndex; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2018-03-09 00:54:06 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-15 01:11:13 +08:00
										 |  |  | /** | 
					
						
							|  |  |  |  * Get imported globals | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * @param {Object} ast - Module's AST | 
					
						
							|  |  |  |  * @returns {Array<t.ModuleImport>} - nodes | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2018-03-12 18:43:20 +08:00
										 |  |  | function getImportedGlobals(ast) { | 
					
						
							|  |  |  | 	const importedGlobals = []; | 
					
						
							| 
									
										
										
										
											2018-03-09 00:54:06 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-12 18:43:20 +08:00
										 |  |  | 	t.traverse(ast, { | 
					
						
							|  |  |  | 		ModuleImport({ node }) { | 
					
						
							|  |  |  | 			if (isGlobalImport(node) === true) { | 
					
						
							|  |  |  | 				importedGlobals.push(node); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}); | 
					
						
							| 
									
										
										
										
											2018-03-09 00:54:06 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-12 18:43:20 +08:00
										 |  |  | 	return importedGlobals; | 
					
						
							| 
									
										
										
										
											2018-03-09 00:54:06 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-07 15:49:14 +08:00
										 |  |  | function getCountImportedFunc(ast) { | 
					
						
							|  |  |  | 	let count = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	t.traverse(ast, { | 
					
						
							|  |  |  | 		ModuleImport({ node }) { | 
					
						
							|  |  |  | 			if (isFuncImport(node) === true) { | 
					
						
							|  |  |  | 				count++; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return count; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-15 01:11:13 +08:00
										 |  |  | /** | 
					
						
							| 
									
										
										
										
											2018-05-04 21:38:53 +08:00
										 |  |  |  * Get next type index | 
					
						
							| 
									
										
										
										
											2018-03-15 01:11:13 +08:00
										 |  |  |  * | 
					
						
							|  |  |  |  * @param {Object} ast - Module's AST | 
					
						
							| 
									
										
										
										
											2018-04-28 00:53:07 +08:00
										 |  |  |  * @returns {t.IndexLiteral} - index | 
					
						
							| 
									
										
										
										
											2018-03-15 01:11:13 +08:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2018-05-04 21:38:53 +08:00
										 |  |  | function getNextTypeIndex(ast) { | 
					
						
							| 
									
										
										
										
											2018-03-26 17:01:12 +08:00
										 |  |  | 	const typeSectionMetadata = t.getSectionMetadata(ast, "type"); | 
					
						
							| 
									
										
										
										
											2018-03-15 01:11:13 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-26 17:01:12 +08:00
										 |  |  | 	if (typeof typeSectionMetadata === "undefined") { | 
					
						
							|  |  |  | 		return t.indexLiteral(0); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-03-15 01:11:13 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-04 21:38:53 +08:00
										 |  |  | 	return t.indexLiteral(typeSectionMetadata.vectorOfSize.value); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * Get next func index | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2018-05-07 15:49:14 +08:00
										 |  |  |  * The Func section metadata provide informations for implemented funcs | 
					
						
							|  |  |  |  * in order to have the correct index we shift the index by number of external | 
					
						
							|  |  |  |  * functions. | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2018-05-04 21:38:53 +08:00
										 |  |  |  * @param {Object} ast - Module's AST | 
					
						
							| 
									
										
										
										
											2018-05-07 15:49:14 +08:00
										 |  |  |  * @param {Number} countImportedFunc - number of imported funcs | 
					
						
							| 
									
										
										
										
											2018-05-04 21:38:53 +08:00
										 |  |  |  * @returns {t.IndexLiteral} - index | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2018-05-07 15:49:14 +08:00
										 |  |  | function getNextFuncIndex(ast, countImportedFunc) { | 
					
						
							| 
									
										
										
										
											2018-05-04 21:38:53 +08:00
										 |  |  | 	const funcSectionMetadata = t.getSectionMetadata(ast, "func"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (typeof funcSectionMetadata === "undefined") { | 
					
						
							| 
									
										
										
										
											2018-05-07 15:49:14 +08:00
										 |  |  | 		return t.indexLiteral(0 + countImportedFunc); | 
					
						
							| 
									
										
										
										
											2018-05-04 21:38:53 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-07 15:49:14 +08:00
										 |  |  | 	const vectorOfSize = funcSectionMetadata.vectorOfSize.value; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return t.indexLiteral(vectorOfSize + countImportedFunc); | 
					
						
							| 
									
										
										
										
											2018-03-15 01:11:13 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-09 00:54:06 +08:00
										 |  |  | /** | 
					
						
							| 
									
										
										
										
											2018-03-12 18:43:20 +08:00
										 |  |  |  * Rewrite the import globals: | 
					
						
							|  |  |  |  * - removes the ModuleImport instruction | 
					
						
							|  |  |  |  * - injects at the same offset a mutable global of the same time | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Since the imported globals are before the other global declarations, our | 
					
						
							|  |  |  |  * indices will be preserved. | 
					
						
							| 
									
										
										
										
											2018-03-09 19:04:27 +08:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2018-03-12 18:43:20 +08:00
										 |  |  |  * Note that globals will become mutable. | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2018-03-14 21:49:33 +08:00
										 |  |  |  * @param {Object} state - unused state | 
					
						
							| 
									
										
										
										
											2018-04-28 00:53:07 +08:00
										 |  |  |  * @returns {ArrayBufferTransform} transform | 
					
						
							| 
									
										
										
										
											2018-03-09 19:04:27 +08:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2018-03-13 00:22:05 +08:00
										 |  |  | const rewriteImportedGlobals = state => bin => { | 
					
						
							|  |  |  | 	const newGlobals = []; | 
					
						
							| 
									
										
										
										
											2018-03-10 02:03:33 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-09 23:40:38 +08:00
										 |  |  | 	bin = editWithAST(state.ast, bin, { | 
					
						
							| 
									
										
										
										
											2018-03-13 00:22:05 +08:00
										 |  |  | 		ModuleImport(path) { | 
					
						
							|  |  |  | 			if (isGlobalImport(path.node) === true) { | 
					
						
							|  |  |  | 				const globalType = path.node.descr; | 
					
						
							| 
									
										
										
										
											2018-03-10 02:03:33 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-13 00:22:05 +08:00
										 |  |  | 				globalType.mutability = "var"; | 
					
						
							| 
									
										
										
										
											2018-03-10 02:03:33 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-13 00:22:05 +08:00
										 |  |  | 				newGlobals.push( | 
					
						
							|  |  |  | 					t.global(globalType, [ | 
					
						
							| 
									
										
										
										
											2018-05-14 19:00:19 +08:00
										 |  |  | 						t.objectInstruction("const", "i32", [t.numberLiteralFromRaw(0)]) | 
					
						
							| 
									
										
										
										
											2018-03-13 00:22:05 +08:00
										 |  |  | 					]) | 
					
						
							|  |  |  | 				); | 
					
						
							| 
									
										
										
										
											2018-03-12 18:43:20 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-13 00:22:05 +08:00
										 |  |  | 				path.remove(); | 
					
						
							| 
									
										
										
										
											2018-03-09 19:04:27 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2018-03-13 00:22:05 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	}); | 
					
						
							| 
									
										
										
										
											2018-03-12 18:43:20 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-13 00:22:05 +08:00
										 |  |  | 	// Add global declaration instructions
 | 
					
						
							| 
									
										
										
										
											2018-05-09 23:40:38 +08:00
										 |  |  | 	return addWithAST(state.ast, bin, newGlobals); | 
					
						
							| 
									
										
										
										
											2018-03-12 18:43:20 +08:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2018-03-09 19:04:27 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-09 22:19:31 +08:00
										 |  |  | /** | 
					
						
							|  |  |  |  * Rewrite the export names | 
					
						
							|  |  |  |  * @param {Object} state state | 
					
						
							|  |  |  |  * @param {Object} state.ast Module's ast | 
					
						
							|  |  |  |  * @param {Object} state.module Module | 
					
						
							|  |  |  |  * @returns {ArrayBufferTransform} transform | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | const rewriteExportNames = ({ ast, module }) => bin => { | 
					
						
							|  |  |  | 	return editWithAST(ast, bin, { | 
					
						
							|  |  |  | 		ModuleExport(path) { | 
					
						
							|  |  |  | 			const usedName = module.isUsed(path.node.name); | 
					
						
							|  |  |  | 			if (usedName) { | 
					
						
							|  |  |  | 				path.node.name = usedName; | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				path.remove(); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-11 20:24:40 +08:00
										 |  |  | /** | 
					
						
							|  |  |  |  * Mangle import names and modules | 
					
						
							|  |  |  |  * @param {Object} state state | 
					
						
							|  |  |  |  * @param {Object} state.ast Module's ast | 
					
						
							|  |  |  |  * @param {Map<string, UsedWasmDependency>} state.usedDependencyMap mappings to mangle names | 
					
						
							|  |  |  |  * @returns {ArrayBufferTransform} transform | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | const rewriteImports = ({ ast, usedDependencyMap }) => bin => { | 
					
						
							|  |  |  | 	return editWithAST(ast, bin, { | 
					
						
							| 
									
										
										
										
											2018-05-10 17:34:09 +08:00
										 |  |  | 		ModuleImport(path) { | 
					
						
							| 
									
										
										
										
											2018-05-11 20:24:40 +08:00
										 |  |  | 			const result = usedDependencyMap.get( | 
					
						
							| 
									
										
										
										
											2018-05-10 17:34:09 +08:00
										 |  |  | 				path.node.module + ":" + path.node.name | 
					
						
							|  |  |  | 			); | 
					
						
							|  |  |  | 			if (result === undefined) { | 
					
						
							|  |  |  | 				path.remove(); | 
					
						
							|  |  |  | 			} else { | 
					
						
							| 
									
										
										
										
											2018-05-11 20:24:40 +08:00
										 |  |  | 				path.node.module = WebAssemblyUtils.MANGLED_MODULE; | 
					
						
							|  |  |  | 				path.node.name = result.name; | 
					
						
							| 
									
										
										
										
											2018-05-10 17:34:09 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-09 19:04:27 +08:00
										 |  |  | /** | 
					
						
							| 
									
										
										
										
											2018-03-12 18:43:20 +08:00
										 |  |  |  * Add an init function. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * The init function fills the globals given input arguments. | 
					
						
							| 
									
										
										
										
											2018-03-09 19:04:27 +08:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2018-04-28 00:53:07 +08:00
										 |  |  |  * @param {Object} state transformation state | 
					
						
							| 
									
										
										
										
											2018-05-09 23:40:38 +08:00
										 |  |  |  * @param {Object} state.ast - Module's ast | 
					
						
							| 
									
										
										
										
											2018-05-09 22:19:31 +08:00
										 |  |  |  * @param {t.Identifier} state.initFuncId identifier of the init function | 
					
						
							| 
									
										
										
										
											2018-04-28 00:53:07 +08:00
										 |  |  |  * @param {t.IndexLiteral} state.startAtFuncIndex index of the start function | 
					
						
							|  |  |  |  * @param {t.ModuleImport[]} state.importedGlobals list of imported globals | 
					
						
							|  |  |  |  * @param {t.IndexLiteral} state.nextFuncIndex index of the next function | 
					
						
							| 
									
										
										
										
											2018-05-04 21:38:53 +08:00
										 |  |  |  * @param {t.IndexLiteral} state.nextTypeIndex index of the next type | 
					
						
							| 
									
										
										
										
											2018-04-28 00:53:07 +08:00
										 |  |  |  * @returns {ArrayBufferTransform} transform | 
					
						
							| 
									
										
										
										
											2018-03-09 19:04:27 +08:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2018-03-12 18:43:20 +08:00
										 |  |  | const addInitFunction = ({ | 
					
						
							| 
									
										
										
										
											2018-05-09 23:40:38 +08:00
										 |  |  | 	ast, | 
					
						
							| 
									
										
										
										
											2018-05-09 22:19:31 +08:00
										 |  |  | 	initFuncId, | 
					
						
							| 
									
										
										
										
											2018-03-12 18:43:20 +08:00
										 |  |  | 	startAtFuncIndex, | 
					
						
							|  |  |  | 	importedGlobals, | 
					
						
							| 
									
										
										
										
											2018-05-04 21:38:53 +08:00
										 |  |  | 	nextFuncIndex, | 
					
						
							|  |  |  | 	nextTypeIndex | 
					
						
							| 
									
										
										
										
											2018-03-12 18:43:20 +08:00
										 |  |  | }) => bin => { | 
					
						
							|  |  |  | 	const funcParams = importedGlobals.map(importedGlobal => { | 
					
						
							|  |  |  | 		// used for debugging
 | 
					
						
							|  |  |  | 		const id = t.identifier(`${importedGlobal.module}.${importedGlobal.name}`); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return t.funcParam(importedGlobal.descr.valtype, id); | 
					
						
							| 
									
										
										
										
											2018-03-09 00:54:06 +08:00
										 |  |  | 	}); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-12 18:43:20 +08:00
										 |  |  | 	const funcBody = importedGlobals.reduce((acc, importedGlobal, index) => { | 
					
						
							|  |  |  | 		const args = [t.indexLiteral(index)]; | 
					
						
							|  |  |  | 		const body = [ | 
					
						
							|  |  |  | 			t.instruction("get_local", args), | 
					
						
							|  |  |  | 			t.instruction("set_global", args) | 
					
						
							|  |  |  | 		]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return [...acc, ...body]; | 
					
						
							|  |  |  | 	}, []); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (typeof startAtFuncIndex !== "undefined") { | 
					
						
							|  |  |  | 		funcBody.push(t.callInstruction(startAtFuncIndex)); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	const funcResults = []; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-07 15:49:14 +08:00
										 |  |  | 	// Code section
 | 
					
						
							| 
									
										
										
										
											2018-05-16 19:22:46 +08:00
										 |  |  | 	const funcSignature = t.signature(funcParams, funcResults); | 
					
						
							|  |  |  | 	const func = t.func(initFuncId, funcSignature, funcBody); | 
					
						
							| 
									
										
										
										
											2018-03-10 02:03:33 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-07 15:49:14 +08:00
										 |  |  | 	// Type section
 | 
					
						
							| 
									
										
										
										
											2018-05-16 19:22:46 +08:00
										 |  |  | 	const functype = t.typeInstruction(undefined, funcSignature); | 
					
						
							| 
									
										
										
										
											2018-05-07 15:49:14 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Func section
 | 
					
						
							| 
									
										
										
										
											2018-05-04 21:38:53 +08:00
										 |  |  | 	const funcindex = t.indexInFuncSection(nextTypeIndex); | 
					
						
							| 
									
										
										
										
											2018-03-10 02:03:33 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-07 15:49:14 +08:00
										 |  |  | 	// Export section
 | 
					
						
							| 
									
										
										
										
											2018-05-16 19:22:46 +08:00
										 |  |  | 	const moduleExport = t.moduleExport( | 
					
						
							|  |  |  | 		initFuncId.value, | 
					
						
							|  |  |  | 		t.moduleExportDescr("Func", nextFuncIndex) | 
					
						
							|  |  |  | 	); | 
					
						
							| 
									
										
										
										
											2018-03-10 02:03:33 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-09 23:40:38 +08:00
										 |  |  | 	return addWithAST(ast, bin, [func, moduleExport, funcindex, functype]); | 
					
						
							| 
									
										
										
										
											2018-03-12 18:43:20 +08:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2018-03-09 00:54:06 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-11 20:24:40 +08:00
										 |  |  | /** | 
					
						
							|  |  |  |  * Extract mangle mappings from module | 
					
						
							|  |  |  |  * @param {Module} module current module | 
					
						
							|  |  |  |  * @returns {Map<string, UsedWasmDependency>} mappings to mangled names | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | const getUsedDependencyMap = module => { | 
					
						
							|  |  |  | 	/** @type {Map<string, UsedWasmDependency>} */ | 
					
						
							| 
									
										
										
										
											2018-05-10 17:34:09 +08:00
										 |  |  | 	const map = new Map(); | 
					
						
							| 
									
										
										
										
											2018-05-11 20:24:40 +08:00
										 |  |  | 	for (const usedDep of WebAssemblyUtils.getUsedDependencies(module)) { | 
					
						
							|  |  |  | 		const dep = usedDep.dependency; | 
					
						
							|  |  |  | 		const request = dep.request; | 
					
						
							|  |  |  | 		const exportName = dep.name; | 
					
						
							|  |  |  | 		map.set(request + ":" + exportName, usedDep); | 
					
						
							| 
									
										
										
										
											2018-05-10 17:34:09 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return map; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-28 00:53:07 +08:00
										 |  |  | class WebAssemblyGenerator extends Generator { | 
					
						
							| 
									
										
										
										
											2018-01-24 06:09:26 +08:00
										 |  |  | 	generate(module) { | 
					
						
							| 
									
										
										
										
											2018-05-14 19:00:19 +08:00
										 |  |  | 		let bin = module.originalSource().source(); | 
					
						
							|  |  |  | 		bin = preprocess(bin); | 
					
						
							| 
									
										
										
										
											2018-03-09 00:54:06 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-09 22:19:31 +08:00
										 |  |  | 		const initFuncId = t.identifier( | 
					
						
							|  |  |  | 			Array.isArray(module.usedExports) | 
					
						
							|  |  |  | 				? Template.numberToIdentifer(module.usedExports.length) | 
					
						
							|  |  |  | 				: "__webpack_init__" | 
					
						
							|  |  |  | 		); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-11 22:46:33 +08:00
										 |  |  | 		const ast = decode(bin, { | 
					
						
							|  |  |  | 			ignoreDataSection: true, | 
					
						
							| 
									
										
										
										
											2018-05-16 19:22:46 +08:00
										 |  |  | 			ignoreCodeSection: true, | 
					
						
							|  |  |  | 			ignoreCustomNameSection: true | 
					
						
							| 
									
										
										
										
											2018-05-11 22:46:33 +08:00
										 |  |  | 		}); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-12 18:43:20 +08:00
										 |  |  | 		const importedGlobals = getImportedGlobals(ast); | 
					
						
							| 
									
										
										
										
											2018-05-07 15:49:14 +08:00
										 |  |  | 		const countImportedFunc = getCountImportedFunc(ast); | 
					
						
							| 
									
										
										
										
											2018-03-12 18:43:20 +08:00
										 |  |  | 		const startAtFuncIndex = getStartFuncIndex(ast); | 
					
						
							| 
									
										
										
										
											2018-05-07 15:49:14 +08:00
										 |  |  | 		const nextFuncIndex = getNextFuncIndex(ast, countImportedFunc); | 
					
						
							| 
									
										
										
										
											2018-05-04 21:38:53 +08:00
										 |  |  | 		const nextTypeIndex = getNextTypeIndex(ast); | 
					
						
							| 
									
										
										
										
											2018-03-12 18:43:20 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-11 20:24:40 +08:00
										 |  |  | 		const usedDependencyMap = getUsedDependencyMap(module); | 
					
						
							| 
									
										
										
										
											2018-05-10 17:34:09 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-12 18:43:20 +08:00
										 |  |  | 		const transform = compose( | 
					
						
							| 
									
										
										
										
											2018-05-09 22:19:31 +08:00
										 |  |  | 			rewriteExportNames({ | 
					
						
							|  |  |  | 				ast, | 
					
						
							|  |  |  | 				module | 
					
						
							|  |  |  | 			}), | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-09 23:40:38 +08:00
										 |  |  | 			removeStartFunc({ ast }), | 
					
						
							| 
									
										
										
										
											2018-03-12 18:43:20 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-09 23:40:38 +08:00
										 |  |  | 			rewriteImportedGlobals({ ast }), | 
					
						
							| 
									
										
										
										
											2018-03-12 18:43:20 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-10 17:34:09 +08:00
										 |  |  | 			rewriteImports({ | 
					
						
							| 
									
										
										
										
											2018-05-11 20:24:40 +08:00
										 |  |  | 				ast, | 
					
						
							|  |  |  | 				usedDependencyMap | 
					
						
							| 
									
										
										
										
											2018-05-10 17:34:09 +08:00
										 |  |  | 			}), | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-12 18:43:20 +08:00
										 |  |  | 			addInitFunction({ | 
					
						
							| 
									
										
										
										
											2018-05-09 23:40:38 +08:00
										 |  |  | 				ast, | 
					
						
							| 
									
										
										
										
											2018-05-09 22:19:31 +08:00
										 |  |  | 				initFuncId, | 
					
						
							| 
									
										
										
										
											2018-03-12 18:43:20 +08:00
										 |  |  | 				importedGlobals, | 
					
						
							| 
									
										
										
										
											2018-03-15 01:11:13 +08:00
										 |  |  | 				startAtFuncIndex, | 
					
						
							| 
									
										
										
										
											2018-05-04 21:38:53 +08:00
										 |  |  | 				nextFuncIndex, | 
					
						
							|  |  |  | 				nextTypeIndex | 
					
						
							| 
									
										
										
										
											2018-03-12 18:43:20 +08:00
										 |  |  | 			}) | 
					
						
							|  |  |  | 		); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-09 00:54:06 +08:00
										 |  |  | 		const newBin = transform(bin); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return new RawSource(newBin); | 
					
						
							| 
									
										
										
										
											2018-01-24 06:09:26 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | module.exports = WebAssemblyGenerator; |