You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
			
				
					247 lines
				
				6.2 KiB
			
		
		
			
		
	
	
					247 lines
				
				6.2 KiB
			| 
								 
											4 years ago
										 
									 | 
							
								import * as decoder from "./decoder";
							 | 
						||
| 
								 | 
							
								import * as t from "@webassemblyjs/ast";
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * TODO(sven): I added initial props, but we should rather fix
							 | 
						||
| 
								 | 
							
								 * https://github.com/xtuc/webassemblyjs/issues/405
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								var defaultDecoderOpts = {
							 | 
						||
| 
								 | 
							
								  dump: false,
							 | 
						||
| 
								 | 
							
								  ignoreCodeSection: false,
							 | 
						||
| 
								 | 
							
								  ignoreDataSection: false,
							 | 
						||
| 
								 | 
							
								  ignoreCustomNameSection: false
							 | 
						||
| 
								 | 
							
								}; // traverses the AST, locating function name metadata, which is then
							 | 
						||
| 
								 | 
							
								// used to update index-based identifiers with function names
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function restoreFunctionNames(ast) {
							 | 
						||
| 
								 | 
							
								  var functionNames = [];
							 | 
						||
| 
								 | 
							
								  t.traverse(ast, {
							 | 
						||
| 
								 | 
							
								    FunctionNameMetadata: function FunctionNameMetadata(_ref) {
							 | 
						||
| 
								 | 
							
								      var node = _ref.node;
							 | 
						||
| 
								 | 
							
								      functionNames.push({
							 | 
						||
| 
								 | 
							
								        name: node.value,
							 | 
						||
| 
								 | 
							
								        index: node.index
							 | 
						||
| 
								 | 
							
								      });
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (functionNames.length === 0) {
							 | 
						||
| 
								 | 
							
								    return;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  t.traverse(ast, {
							 | 
						||
| 
								 | 
							
								    Func: function (_Func) {
							 | 
						||
| 
								 | 
							
								      function Func(_x) {
							 | 
						||
| 
								 | 
							
								        return _Func.apply(this, arguments);
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      Func.toString = function () {
							 | 
						||
| 
								 | 
							
								        return _Func.toString();
							 | 
						||
| 
								 | 
							
								      };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      return Func;
							 | 
						||
| 
								 | 
							
								    }(function (_ref2) {
							 | 
						||
| 
								 | 
							
								      var node = _ref2.node;
							 | 
						||
| 
								 | 
							
								      // $FlowIgnore
							 | 
						||
| 
								 | 
							
								      var nodeName = node.name;
							 | 
						||
| 
								 | 
							
								      var indexBasedFunctionName = nodeName.value;
							 | 
						||
| 
								 | 
							
								      var index = Number(indexBasedFunctionName.replace("func_", ""));
							 | 
						||
| 
								 | 
							
								      var functionName = functionNames.find(function (f) {
							 | 
						||
| 
								 | 
							
								        return f.index === index;
							 | 
						||
| 
								 | 
							
								      });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      if (functionName) {
							 | 
						||
| 
								 | 
							
								        var oldValue = nodeName.value;
							 | 
						||
| 
								 | 
							
								        nodeName.value = functionName.name;
							 | 
						||
| 
								 | 
							
								        nodeName.numeric = oldValue; // $FlowIgnore
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        delete nodeName.raw;
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    }),
							 | 
						||
| 
								 | 
							
								    // Also update the reference in the export
							 | 
						||
| 
								 | 
							
								    ModuleExport: function (_ModuleExport) {
							 | 
						||
| 
								 | 
							
								      function ModuleExport(_x2) {
							 | 
						||
| 
								 | 
							
								        return _ModuleExport.apply(this, arguments);
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      ModuleExport.toString = function () {
							 | 
						||
| 
								 | 
							
								        return _ModuleExport.toString();
							 | 
						||
| 
								 | 
							
								      };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      return ModuleExport;
							 | 
						||
| 
								 | 
							
								    }(function (_ref3) {
							 | 
						||
| 
								 | 
							
								      var node = _ref3.node;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      if (node.descr.exportType === "Func") {
							 | 
						||
| 
								 | 
							
								        // $FlowIgnore
							 | 
						||
| 
								 | 
							
								        var nodeName = node.descr.id;
							 | 
						||
| 
								 | 
							
								        var index = nodeName.value;
							 | 
						||
| 
								 | 
							
								        var functionName = functionNames.find(function (f) {
							 | 
						||
| 
								 | 
							
								          return f.index === index;
							 | 
						||
| 
								 | 
							
								        });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if (functionName) {
							 | 
						||
| 
								 | 
							
								          node.descr.id = t.identifier(functionName.name);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    }),
							 | 
						||
| 
								 | 
							
								    ModuleImport: function (_ModuleImport) {
							 | 
						||
| 
								 | 
							
								      function ModuleImport(_x3) {
							 | 
						||
| 
								 | 
							
								        return _ModuleImport.apply(this, arguments);
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      ModuleImport.toString = function () {
							 | 
						||
| 
								 | 
							
								        return _ModuleImport.toString();
							 | 
						||
| 
								 | 
							
								      };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      return ModuleImport;
							 | 
						||
| 
								 | 
							
								    }(function (_ref4) {
							 | 
						||
| 
								 | 
							
								      var node = _ref4.node;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      if (node.descr.type === "FuncImportDescr") {
							 | 
						||
| 
								 | 
							
								        // $FlowIgnore
							 | 
						||
| 
								 | 
							
								        var indexBasedFunctionName = node.descr.id;
							 | 
						||
| 
								 | 
							
								        var index = Number(indexBasedFunctionName.replace("func_", ""));
							 | 
						||
| 
								 | 
							
								        var functionName = functionNames.find(function (f) {
							 | 
						||
| 
								 | 
							
								          return f.index === index;
							 | 
						||
| 
								 | 
							
								        });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if (functionName) {
							 | 
						||
| 
								 | 
							
								          // $FlowIgnore
							 | 
						||
| 
								 | 
							
								          node.descr.id = t.identifier(functionName.name);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    }),
							 | 
						||
| 
								 | 
							
								    CallInstruction: function (_CallInstruction) {
							 | 
						||
| 
								 | 
							
								      function CallInstruction(_x4) {
							 | 
						||
| 
								 | 
							
								        return _CallInstruction.apply(this, arguments);
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      CallInstruction.toString = function () {
							 | 
						||
| 
								 | 
							
								        return _CallInstruction.toString();
							 | 
						||
| 
								 | 
							
								      };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      return CallInstruction;
							 | 
						||
| 
								 | 
							
								    }(function (nodePath) {
							 | 
						||
| 
								 | 
							
								      var node = nodePath.node;
							 | 
						||
| 
								 | 
							
								      var index = node.index.value;
							 | 
						||
| 
								 | 
							
								      var functionName = functionNames.find(function (f) {
							 | 
						||
| 
								 | 
							
								        return f.index === index;
							 | 
						||
| 
								 | 
							
								      });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      if (functionName) {
							 | 
						||
| 
								 | 
							
								        var oldValue = node.index;
							 | 
						||
| 
								 | 
							
								        node.index = t.identifier(functionName.name);
							 | 
						||
| 
								 | 
							
								        node.numeric = oldValue; // $FlowIgnore
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        delete node.raw;
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    })
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function restoreLocalNames(ast) {
							 | 
						||
| 
								 | 
							
								  var localNames = [];
							 | 
						||
| 
								 | 
							
								  t.traverse(ast, {
							 | 
						||
| 
								 | 
							
								    LocalNameMetadata: function LocalNameMetadata(_ref5) {
							 | 
						||
| 
								 | 
							
								      var node = _ref5.node;
							 | 
						||
| 
								 | 
							
								      localNames.push({
							 | 
						||
| 
								 | 
							
								        name: node.value,
							 | 
						||
| 
								 | 
							
								        localIndex: node.localIndex,
							 | 
						||
| 
								 | 
							
								        functionIndex: node.functionIndex
							 | 
						||
| 
								 | 
							
								      });
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (localNames.length === 0) {
							 | 
						||
| 
								 | 
							
								    return;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  t.traverse(ast, {
							 | 
						||
| 
								 | 
							
								    Func: function (_Func2) {
							 | 
						||
| 
								 | 
							
								      function Func(_x5) {
							 | 
						||
| 
								 | 
							
								        return _Func2.apply(this, arguments);
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      Func.toString = function () {
							 | 
						||
| 
								 | 
							
								        return _Func2.toString();
							 | 
						||
| 
								 | 
							
								      };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      return Func;
							 | 
						||
| 
								 | 
							
								    }(function (_ref6) {
							 | 
						||
| 
								 | 
							
								      var node = _ref6.node;
							 | 
						||
| 
								 | 
							
								      var signature = node.signature;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      if (signature.type !== "Signature") {
							 | 
						||
| 
								 | 
							
								        return;
							 | 
						||
| 
								 | 
							
								      } // $FlowIgnore
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      var nodeName = node.name;
							 | 
						||
| 
								 | 
							
								      var indexBasedFunctionName = nodeName.value;
							 | 
						||
| 
								 | 
							
								      var functionIndex = Number(indexBasedFunctionName.replace("func_", ""));
							 | 
						||
| 
								 | 
							
								      signature.params.forEach(function (param, paramIndex) {
							 | 
						||
| 
								 | 
							
								        var paramName = localNames.find(function (f) {
							 | 
						||
| 
								 | 
							
								          return f.localIndex === paramIndex && f.functionIndex === functionIndex;
							 | 
						||
| 
								 | 
							
								        });
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if (paramName && paramName.name !== "") {
							 | 
						||
| 
								 | 
							
								          param.id = paramName.name;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								      });
							 | 
						||
| 
								 | 
							
								    })
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function restoreModuleName(ast) {
							 | 
						||
| 
								 | 
							
								  t.traverse(ast, {
							 | 
						||
| 
								 | 
							
								    ModuleNameMetadata: function (_ModuleNameMetadata) {
							 | 
						||
| 
								 | 
							
								      function ModuleNameMetadata(_x6) {
							 | 
						||
| 
								 | 
							
								        return _ModuleNameMetadata.apply(this, arguments);
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      ModuleNameMetadata.toString = function () {
							 | 
						||
| 
								 | 
							
								        return _ModuleNameMetadata.toString();
							 | 
						||
| 
								 | 
							
								      };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      return ModuleNameMetadata;
							 | 
						||
| 
								 | 
							
								    }(function (moduleNameMetadataPath) {
							 | 
						||
| 
								 | 
							
								      // update module
							 | 
						||
| 
								 | 
							
								      t.traverse(ast, {
							 | 
						||
| 
								 | 
							
								        Module: function (_Module) {
							 | 
						||
| 
								 | 
							
								          function Module(_x7) {
							 | 
						||
| 
								 | 
							
								            return _Module.apply(this, arguments);
							 | 
						||
| 
								 | 
							
								          }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								          Module.toString = function () {
							 | 
						||
| 
								 | 
							
								            return _Module.toString();
							 | 
						||
| 
								 | 
							
								          };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								          return Module;
							 | 
						||
| 
								 | 
							
								        }(function (_ref7) {
							 | 
						||
| 
								 | 
							
								          var node = _ref7.node;
							 | 
						||
| 
								 | 
							
								          var name = moduleNameMetadataPath.node.value; // compatiblity with wast-parser
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								          if (name === "") {
							 | 
						||
| 
								 | 
							
								            name = null;
							 | 
						||
| 
								 | 
							
								          }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								          node.id = name;
							 | 
						||
| 
								 | 
							
								        })
							 | 
						||
| 
								 | 
							
								      });
							 | 
						||
| 
								 | 
							
								    })
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								export function decode(buf, customOpts) {
							 | 
						||
| 
								 | 
							
								  var opts = Object.assign({}, defaultDecoderOpts, customOpts);
							 | 
						||
| 
								 | 
							
								  var ast = decoder.decode(buf, opts);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (opts.ignoreCustomNameSection === false) {
							 | 
						||
| 
								 | 
							
								    restoreFunctionNames(ast);
							 | 
						||
| 
								 | 
							
								    restoreLocalNames(ast);
							 | 
						||
| 
								 | 
							
								    restoreModuleName(ast);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return ast;
							 | 
						||
| 
								 | 
							
								}
							 |