| 
									
										
										
										
											2018-01-24 06:09:26 +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-01-24 06:09:26 +08:00
										 |  |  | "use strict"; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-30 23:08:51 +08:00
										 |  |  | const { RawSource } = require("webpack-sources"); | 
					
						
							| 
									
										
										
										
											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 t = require("@webassemblyjs/ast"); | 
					
						
							| 
									
										
										
										
											2018-06-06 17:06:40 +08:00
										 |  |  | const { | 
					
						
							|  |  |  | 	moduleContextFromModuleAST | 
					
						
							|  |  |  | } = require("@webassemblyjs/helper-module-context"); | 
					
						
							| 
									
										
										
										
											2018-07-30 23:08:51 +08:00
										 |  |  | const { editWithAST, addWithAST } = require("@webassemblyjs/wasm-edit"); | 
					
						
							|  |  |  | const { decode } = require("@webassemblyjs/wasm-parser"); | 
					
						
							| 
									
										
										
										
											2018-03-09 00:54:06 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-02 15:53:35 +08:00
										 |  |  | const WebAssemblyExportImportedDependency = require("../dependencies/WebAssemblyExportImportedDependency"); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-30 23:08:51 +08:00
										 |  |  | /** @typedef {import("webpack-sources").Source} Source */ | 
					
						
							|  |  |  | /** @typedef {import("../DependencyTemplates")} DependencyTemplates */ | 
					
						
							| 
									
										
										
										
											2018-07-18 00:57:03 +08:00
										 |  |  | /** @typedef {import("../Generator").GenerateContext} GenerateContext */ | 
					
						
							| 
									
										
										
										
											2018-05-11 20:24:40 +08:00
										 |  |  | /** @typedef {import("../Module")} Module */ | 
					
						
							| 
									
										
										
										
											2018-07-24 23:35:36 +08:00
										 |  |  | /** @typedef {import("../ModuleGraph")} ModuleGraph */ | 
					
						
							| 
									
										
										
										
											2018-07-21 00:17:51 +08:00
										 |  |  | /** @typedef {import("../NormalModule")} NormalModule */ | 
					
						
							|  |  |  | /** @typedef {import("../RuntimeTemplate")} RuntimeTemplate */ | 
					
						
							| 
									
										
										
										
											2018-07-30 23:08:51 +08:00
										 |  |  | /** @typedef {import("./WebAssemblyUtils").UsedWasmDependency} UsedWasmDependency */ | 
					
						
							| 
									
										
										
										
											2018-05-11 20:24:40 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-14 19:00:19 +08:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @typedef {(ArrayBuffer) => ArrayBuffer} ArrayBufferTransform | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-11 22:30:06 +08:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @template T | 
					
						
							|  |  |  |  * @param {Function[]} fns transforms | 
					
						
							|  |  |  |  * @returns {Function} composed transform | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2018-06-27 19:48:13 +08:00
										 |  |  | const compose = (...fns) => { | 
					
						
							| 
									
										
										
										
											2018-07-31 17:44:32 +08:00
										 |  |  | 	return fns.reduce( | 
					
						
							|  |  |  | 		(prevFn, nextFn) => { | 
					
						
							|  |  |  | 			return value => nextFn(prevFn(value)); | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		value => value | 
					
						
							|  |  |  | 	); | 
					
						
							| 
									
										
										
										
											2018-06-27 19:48:13 +08:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2018-03-09 00:54:06 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											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
										 |  |  | /** | 
					
						
							|  |  |  |  * Get imported globals | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * @param {Object} ast - Module's AST | 
					
						
							|  |  |  |  * @returns {Array<t.ModuleImport>} - nodes | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2018-06-27 19:48:13 +08:00
										 |  |  | const getImportedGlobals = ast => { | 
					
						
							| 
									
										
										
										
											2018-03-12 18:43:20 +08:00
										 |  |  | 	const importedGlobals = []; | 
					
						
							| 
									
										
										
										
											2018-03-09 00:54:06 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-12 18:43:20 +08:00
										 |  |  | 	t.traverse(ast, { | 
					
						
							|  |  |  | 		ModuleImport({ node }) { | 
					
						
							| 
									
										
										
										
											2018-06-06 16:39:06 +08:00
										 |  |  | 			if (t.isGlobalType(node.descr) === true) { | 
					
						
							| 
									
										
										
										
											2018-03-12 18:43:20 +08:00
										 |  |  | 				importedGlobals.push(node); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}); | 
					
						
							| 
									
										
										
										
											2018-03-09 00:54:06 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-12 18:43:20 +08:00
										 |  |  | 	return importedGlobals; | 
					
						
							| 
									
										
										
										
											2018-06-27 19:48:13 +08:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2018-03-09 00:54:06 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-27 19:48:13 +08:00
										 |  |  | const getCountImportedFunc = ast => { | 
					
						
							| 
									
										
										
										
											2018-05-07 15:49:14 +08:00
										 |  |  | 	let count = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	t.traverse(ast, { | 
					
						
							|  |  |  | 		ModuleImport({ node }) { | 
					
						
							| 
									
										
										
										
											2018-06-06 16:39:06 +08:00
										 |  |  | 			if (t.isFuncImportDescr(node.descr) === true) { | 
					
						
							| 
									
										
										
										
											2018-05-07 15:49:14 +08:00
										 |  |  | 				count++; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return count; | 
					
						
							| 
									
										
										
										
											2018-06-27 19:48:13 +08:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2018-05-07 15:49:14 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											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-05-30 18:45:05 +08:00
										 |  |  |  * @returns {t.Index} - index | 
					
						
							| 
									
										
										
										
											2018-03-15 01:11:13 +08:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2018-06-27 19:48:13 +08:00
										 |  |  | const 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-08-21 08:26:50 +08:00
										 |  |  | 	if (typeSectionMetadata === undefined) { | 
					
						
							| 
									
										
										
										
											2018-03-26 17:01:12 +08:00
										 |  |  | 		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); | 
					
						
							| 
									
										
										
										
											2018-06-27 19:48:13 +08:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2018-05-04 21:38:53 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * 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-30 18:45:05 +08:00
										 |  |  |  * @returns {t.Index} - index | 
					
						
							| 
									
										
										
										
											2018-05-04 21:38:53 +08:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2018-06-27 19:48:13 +08:00
										 |  |  | const getNextFuncIndex = (ast, countImportedFunc) => { | 
					
						
							| 
									
										
										
										
											2018-05-04 21:38:53 +08:00
										 |  |  | 	const funcSectionMetadata = t.getSectionMetadata(ast, "func"); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-21 08:26:50 +08:00
										 |  |  | 	if (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-06-27 19:48:13 +08:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2018-03-15 01:11:13 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-02 23:57:58 +08:00
										 |  |  | /** | 
					
						
							|  |  |  |  * Create a init instruction for a global | 
					
						
							|  |  |  |  * @param {t.GlobalType} globalType the global type | 
					
						
							|  |  |  |  * @returns {t.Instruction} init expression | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | const createDefaultInitForGlobal = globalType => { | 
					
						
							|  |  |  | 	if (globalType.valtype[0] === "i") { | 
					
						
							|  |  |  | 		// create NumberLiteral global initializer
 | 
					
						
							|  |  |  | 		return t.objectInstruction("const", globalType.valtype, [ | 
					
						
							|  |  |  | 			t.numberLiteralFromRaw(66) | 
					
						
							|  |  |  | 		]); | 
					
						
							|  |  |  | 	} else if (globalType.valtype[0] === "f") { | 
					
						
							|  |  |  | 		// create FloatLiteral global initializer
 | 
					
						
							|  |  |  | 		return t.objectInstruction("const", globalType.valtype, [ | 
					
						
							|  |  |  | 			t.floatLiteral(66, false, false, "66") | 
					
						
							|  |  |  | 		]); | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		throw new Error("unknown type: " + globalType.valtype); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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 => { | 
					
						
							| 
									
										
										
										
											2018-05-30 03:20:43 +08:00
										 |  |  | 	const additionalInitCode = state.additionalInitCode; | 
					
						
							| 
									
										
										
										
											2018-03-13 00:22:05 +08:00
										 |  |  | 	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) { | 
					
						
							| 
									
										
										
										
											2018-06-06 16:39:06 +08:00
										 |  |  | 			if (t.isGlobalType(path.node.descr) === true) { | 
					
						
							| 
									
										
										
										
											2018-03-13 00:22:05 +08:00
										 |  |  | 				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-06-02 23:57:58 +08:00
										 |  |  | 				const init = createDefaultInitForGlobal(globalType); | 
					
						
							| 
									
										
										
										
											2018-05-28 20:55:40 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				newGlobals.push(t.global(globalType, [init])); | 
					
						
							| 
									
										
										
										
											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-05-29 20:52:29 +08:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// in order to preserve non-imported global's order we need to re-inject
 | 
					
						
							|  |  |  | 		// those as well
 | 
					
						
							|  |  |  | 		Global(path) { | 
					
						
							| 
									
										
										
										
											2018-05-30 03:20:43 +08:00
										 |  |  | 			const { node } = path; | 
					
						
							| 
									
										
										
										
											2018-05-28 22:56:06 +08:00
										 |  |  | 			const [init] = node.init; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if (init.id === "get_global") { | 
					
						
							|  |  |  | 				node.globalType.mutability = "var"; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				const initialGlobalidx = init.args[0]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-02 23:57:58 +08:00
										 |  |  | 				node.init = [createDefaultInitForGlobal(node.globalType)]; | 
					
						
							| 
									
										
										
										
											2018-05-28 22:56:06 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				additionalInitCode.push( | 
					
						
							|  |  |  | 					/** | 
					
						
							|  |  |  | 					 * get_global in global initilizer only work for imported globals. | 
					
						
							|  |  |  | 					 * They have the same indices than the init params, so use the | 
					
						
							|  |  |  | 					 * same index. | 
					
						
							|  |  |  | 					 */ | 
					
						
							|  |  |  | 					t.instruction("get_local", [initialGlobalidx]), | 
					
						
							| 
									
										
										
										
											2018-05-30 03:20:43 +08:00
										 |  |  | 					t.instruction("set_global", [t.indexLiteral(newGlobals.length)]) | 
					
						
							| 
									
										
										
										
											2018-05-28 22:56:06 +08:00
										 |  |  | 				); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-30 03:20:43 +08:00
										 |  |  | 			newGlobals.push(node); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-29 20:52:29 +08:00
										 |  |  | 			path.remove(); | 
					
						
							| 
									
										
										
										
											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 | 
					
						
							| 
									
										
										
										
											2018-06-02 15:53:35 +08:00
										 |  |  |  * @param {Module} state.module Module | 
					
						
							| 
									
										
										
										
											2018-08-07 01:39:43 +08:00
										 |  |  |  * @param {ModuleGraph} state.moduleGraph module graph | 
					
						
							| 
									
										
										
										
											2018-06-03 00:00:22 +08:00
										 |  |  |  * @param {Set<string>} state.externalExports Module | 
					
						
							| 
									
										
										
										
											2018-05-09 22:19:31 +08:00
										 |  |  |  * @returns {ArrayBufferTransform} transform | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2018-08-07 01:39:43 +08:00
										 |  |  | const rewriteExportNames = ({ | 
					
						
							|  |  |  | 	ast, | 
					
						
							|  |  |  | 	moduleGraph, | 
					
						
							|  |  |  | 	module, | 
					
						
							|  |  |  | 	externalExports | 
					
						
							|  |  |  | }) => bin => { | 
					
						
							| 
									
										
										
										
											2018-05-09 22:19:31 +08:00
										 |  |  | 	return editWithAST(ast, bin, { | 
					
						
							|  |  |  | 		ModuleExport(path) { | 
					
						
							| 
									
										
										
										
											2018-06-03 00:00:22 +08:00
										 |  |  | 			const isExternal = externalExports.has(path.node.name); | 
					
						
							|  |  |  | 			if (isExternal) { | 
					
						
							| 
									
										
										
										
											2018-06-02 15:53:35 +08:00
										 |  |  | 				path.remove(); | 
					
						
							|  |  |  | 				return; | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2018-08-07 03:01:24 +08:00
										 |  |  | 			const usedName = module.getUsedName(moduleGraph, path.node.name); | 
					
						
							| 
									
										
										
										
											2018-06-02 15:53:35 +08:00
										 |  |  | 			if (!usedName) { | 
					
						
							| 
									
										
										
										
											2018-05-09 22:19:31 +08:00
										 |  |  | 				path.remove(); | 
					
						
							| 
									
										
										
										
											2018-06-02 15:53:35 +08:00
										 |  |  | 				return; | 
					
						
							| 
									
										
										
										
											2018-05-09 22:19:31 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2018-06-02 15:53:35 +08:00
										 |  |  | 			path.node.name = usedName; | 
					
						
							| 
									
										
										
										
											2018-05-09 22:19:31 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	}); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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 | 
					
						
							|  |  |  | 			); | 
					
						
							| 
									
										
										
										
											2018-06-02 21:51:26 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-21 08:26:50 +08:00
										 |  |  | 			if (result !== undefined) { | 
					
						
							| 
									
										
										
										
											2018-06-06 05:38:29 +08:00
										 |  |  | 				path.node.module = result.module; | 
					
						
							| 
									
										
										
										
											2018-05-11 20:24:40 +08:00
										 |  |  | 				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-06-06 17:06:40 +08:00
										 |  |  |  * @param {t.Index} state.startAtFuncOffset index of the start function | 
					
						
							| 
									
										
										
										
											2018-04-28 00:53:07 +08:00
										 |  |  |  * @param {t.ModuleImport[]} state.importedGlobals list of imported globals | 
					
						
							| 
									
										
										
										
											2018-05-30 03:20:43 +08:00
										 |  |  |  * @param {t.Instruction[]} state.additionalInitCode list of addition instructions for the init function | 
					
						
							| 
									
										
										
										
											2018-05-30 18:45:05 +08:00
										 |  |  |  * @param {t.Index} state.nextFuncIndex index of the next function | 
					
						
							|  |  |  |  * @param {t.Index} 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-06-06 17:06:40 +08:00
										 |  |  | 	startAtFuncOffset, | 
					
						
							| 
									
										
										
										
											2018-03-12 18:43:20 +08:00
										 |  |  | 	importedGlobals, | 
					
						
							| 
									
										
										
										
											2018-05-30 03:20:43 +08:00
										 |  |  | 	additionalInitCode, | 
					
						
							| 
									
										
										
										
											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]; | 
					
						
							|  |  |  | 	}, []); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-06 17:06:40 +08:00
										 |  |  | 	if (typeof startAtFuncOffset === "number") { | 
					
						
							|  |  |  | 		funcBody.push(t.callInstruction(t.numberLiteralFromRaw(startAtFuncOffset))); | 
					
						
							| 
									
										
										
										
											2018-03-12 18:43:20 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-30 03:20:43 +08:00
										 |  |  | 	for (const instr of additionalInitCode) { | 
					
						
							|  |  |  | 		funcBody.push(instr); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-12 18:43:20 +08:00
										 |  |  | 	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 | 
					
						
							| 
									
										
										
										
											2018-07-24 23:35:36 +08:00
										 |  |  |  * @param {ModuleGraph} moduleGraph module graph | 
					
						
							| 
									
										
										
										
											2018-05-11 20:24:40 +08:00
										 |  |  |  * @param {Module} module current module | 
					
						
							| 
									
										
										
										
											2018-06-06 05:38:29 +08:00
										 |  |  |  * @param {boolean} mangle mangle imports | 
					
						
							| 
									
										
										
										
											2018-05-11 20:24:40 +08:00
										 |  |  |  * @returns {Map<string, UsedWasmDependency>} mappings to mangled names | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2018-07-24 23:35:36 +08:00
										 |  |  | const getUsedDependencyMap = (moduleGraph, module, mangle) => { | 
					
						
							| 
									
										
										
										
											2018-05-11 20:24:40 +08:00
										 |  |  | 	/** @type {Map<string, UsedWasmDependency>} */ | 
					
						
							| 
									
										
										
										
											2018-05-10 17:34:09 +08:00
										 |  |  | 	const map = new Map(); | 
					
						
							| 
									
										
										
										
											2018-07-24 23:35:36 +08:00
										 |  |  | 	for (const usedDep of WebAssemblyUtils.getUsedDependencies( | 
					
						
							|  |  |  | 		moduleGraph, | 
					
						
							|  |  |  | 		module, | 
					
						
							|  |  |  | 		mangle | 
					
						
							|  |  |  | 	)) { | 
					
						
							| 
									
										
										
										
											2018-05-11 20:24:40 +08:00
										 |  |  | 		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-12-03 22:00:32 +08:00
										 |  |  | const TYPES = new Set(["webassembly"]); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-28 00:53:07 +08:00
										 |  |  | class WebAssemblyGenerator extends Generator { | 
					
						
							| 
									
										
										
										
											2018-06-06 05:38:29 +08:00
										 |  |  | 	constructor(options) { | 
					
						
							|  |  |  | 		super(); | 
					
						
							|  |  |  | 		this.options = options; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-03 22:00:32 +08:00
										 |  |  | 	/** | 
					
						
							|  |  |  | 	 * @returns {Set<string>} available types (do not mutate) | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	getTypes() { | 
					
						
							|  |  |  | 		return TYPES; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-04 18:23:40 +08:00
										 |  |  | 	/** | 
					
						
							|  |  |  | 	 * @param {NormalModule} module the module | 
					
						
							|  |  |  | 	 * @param {string=} type source type | 
					
						
							|  |  |  | 	 * @returns {number} estimate size of the module | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	getSize(module, type) { | 
					
						
							|  |  |  | 		const originalSource = module.originalSource(); | 
					
						
							|  |  |  | 		if (!originalSource) { | 
					
						
							|  |  |  | 			return 0; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return originalSource.size(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-21 00:17:51 +08:00
										 |  |  | 	/** | 
					
						
							|  |  |  | 	 * @param {NormalModule} module module for which the code should be generated | 
					
						
							| 
									
										
										
										
											2018-07-18 00:57:03 +08:00
										 |  |  | 	 * @param {GenerateContext} generateContext context for generate | 
					
						
							| 
									
										
										
										
											2018-07-21 00:17:51 +08:00
										 |  |  | 	 * @returns {Source} generated code | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2018-07-24 23:35:36 +08:00
										 |  |  | 	generate(module, { moduleGraph }) { | 
					
						
							| 
									
										
										
										
											2018-07-25 18:20:35 +08:00
										 |  |  | 		const source = module.originalSource().source(); | 
					
						
							|  |  |  | 		// TODO remove this casts when webpack-sources is fixed
 | 
					
						
							|  |  |  | 		// source() should have return type (string | Buffer)
 | 
					
						
							| 
									
										
										
										
											2018-08-16 19:12:41 +08:00
										 |  |  | 		const sourceAsAny = /** @type {TODO} */ (source); | 
					
						
							| 
									
										
										
										
											2018-10-23 14:42:03 +08:00
										 |  |  | 		const bin = /** @type {Buffer} */ (sourceAsAny); | 
					
						
							| 
									
										
										
										
											2018-03-09 00:54:06 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-16 19:55:41 +08:00
										 |  |  | 		const usedExports = moduleGraph.getUsedExports(module); | 
					
						
							| 
									
										
										
										
											2018-05-09 22:19:31 +08:00
										 |  |  | 		const initFuncId = t.identifier( | 
					
						
							| 
									
										
										
										
											2018-08-07 01:39:43 +08:00
										 |  |  | 			usedExports && usedExports !== true | 
					
						
							|  |  |  | 				? Template.numberToIdentifer(usedExports.size) | 
					
						
							| 
									
										
										
										
											2018-05-09 22:19:31 +08:00
										 |  |  | 				: "__webpack_init__" | 
					
						
							|  |  |  | 		); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-06 17:06:40 +08:00
										 |  |  | 		// parse it
 | 
					
						
							| 
									
										
										
										
											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-06-06 17:06:40 +08:00
										 |  |  | 		const moduleContext = moduleContextFromModuleAST(ast.body[0]); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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-06-06 17:06:40 +08:00
										 |  |  | 		const startAtFuncOffset = moduleContext.getStart(); | 
					
						
							| 
									
										
										
										
											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-06-06 05:38:29 +08:00
										 |  |  | 		const usedDependencyMap = getUsedDependencyMap( | 
					
						
							| 
									
										
										
										
											2018-07-24 23:35:36 +08:00
										 |  |  | 			moduleGraph, | 
					
						
							| 
									
										
										
										
											2018-06-06 05:38:29 +08:00
										 |  |  | 			module, | 
					
						
							|  |  |  | 			this.options.mangleImports | 
					
						
							|  |  |  | 		); | 
					
						
							| 
									
										
										
										
											2018-06-03 00:00:22 +08:00
										 |  |  | 		const externalExports = new Set( | 
					
						
							| 
									
										
										
										
											2018-06-02 15:53:35 +08:00
										 |  |  | 			module.dependencies | 
					
						
							|  |  |  | 				.filter(d => d instanceof WebAssemblyExportImportedDependency) | 
					
						
							| 
									
										
										
										
											2018-07-21 00:17:51 +08:00
										 |  |  | 				.map(d => { | 
					
						
							|  |  |  | 					const wasmDep = /** @type {WebAssemblyExportImportedDependency} */ (d); | 
					
						
							|  |  |  | 					return wasmDep.exportName; | 
					
						
							|  |  |  | 				}) | 
					
						
							| 
									
										
										
										
											2018-06-02 15:53:35 +08:00
										 |  |  | 		); | 
					
						
							| 
									
										
										
										
											2018-05-10 17:34:09 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-30 03:20:43 +08:00
										 |  |  | 		/** @type {t.Instruction[]} */ | 
					
						
							|  |  |  | 		const additionalInitCode = []; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-12 18:43:20 +08:00
										 |  |  | 		const transform = compose( | 
					
						
							| 
									
										
										
										
											2018-05-09 22:19:31 +08:00
										 |  |  | 			rewriteExportNames({ | 
					
						
							|  |  |  | 				ast, | 
					
						
							| 
									
										
										
										
											2018-08-07 01:39:43 +08:00
										 |  |  | 				moduleGraph, | 
					
						
							| 
									
										
										
										
											2018-06-02 15:53:35 +08:00
										 |  |  | 				module, | 
					
						
							| 
									
										
										
										
											2018-06-03 00:00:22 +08:00
										 |  |  | 				externalExports | 
					
						
							| 
									
										
										
										
											2018-05-09 22:19:31 +08:00
										 |  |  | 			}), | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-09 23:40:38 +08:00
										 |  |  | 			removeStartFunc({ ast }), | 
					
						
							| 
									
										
										
										
											2018-03-12 18:43:20 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-30 03:20:43 +08:00
										 |  |  | 			rewriteImportedGlobals({ ast, additionalInitCode }), | 
					
						
							| 
									
										
										
										
											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-05-30 03:20:43 +08:00
										 |  |  | 				additionalInitCode, | 
					
						
							| 
									
										
										
										
											2018-06-06 17:06:40 +08:00
										 |  |  | 				startAtFuncOffset, | 
					
						
							| 
									
										
										
										
											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); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-18 17:59:57 +08:00
										 |  |  | 		const newBuf = Buffer.from(newBin); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return new RawSource(/** @type {TODO} */ (newBuf)); | 
					
						
							| 
									
										
										
										
											2018-01-24 06:09:26 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | module.exports = WebAssemblyGenerator; |