Skip to content

Commit

Permalink
allow to disable wasm import mangle
Browse files Browse the repository at this point in the history
disable it by default (temporary)
  • Loading branch information
sokra committed Jun 5, 2018
1 parent e2fe200 commit 8e3be48
Show file tree
Hide file tree
Showing 10 changed files with 239 additions and 139 deletions.
16 changes: 12 additions & 4 deletions lib/WebpackOptionsApply.js
Expand Up @@ -87,7 +87,9 @@ class WebpackOptionsApply extends OptionsApply {
FetchCompileWasmTemplatePlugin = require("./web/FetchCompileWasmTemplatePlugin");
NodeSourcePlugin = require("./node/NodeSourcePlugin");
new JsonpTemplatePlugin().apply(compiler);
new FetchCompileWasmTemplatePlugin().apply(compiler);
new FetchCompileWasmTemplatePlugin({
mangleImports: options.optimization.mangleWasmImports
}).apply(compiler);
new FunctionModulePlugin().apply(compiler);
new NodeSourcePlugin(options.node).apply(compiler);
new LoaderTargetPlugin(options.target).apply(compiler);
Expand All @@ -97,7 +99,9 @@ class WebpackOptionsApply extends OptionsApply {
FetchCompileWasmTemplatePlugin = require("./web/FetchCompileWasmTemplatePlugin");
NodeSourcePlugin = require("./node/NodeSourcePlugin");
new WebWorkerTemplatePlugin().apply(compiler);
new FetchCompileWasmTemplatePlugin().apply(compiler);
new FetchCompileWasmTemplatePlugin({
mangleImports: options.optimization.mangleWasmImports
}).apply(compiler);
new FunctionModulePlugin().apply(compiler);
new NodeSourcePlugin(options.node).apply(compiler);
new LoaderTargetPlugin(options.target).apply(compiler);
Expand All @@ -111,7 +115,9 @@ class WebpackOptionsApply extends OptionsApply {
new NodeTemplatePlugin({
asyncChunkLoading: options.target === "async-node"
}).apply(compiler);
new ReadFileCompileWasmTemplatePlugin().apply(compiler);
new ReadFileCompileWasmTemplatePlugin({
mangleImports: options.optimization.mangleWasmImports
}).apply(compiler);
new FunctionModulePlugin().apply(compiler);
new NodeTargetPlugin().apply(compiler);
new LoaderTargetPlugin("node").apply(compiler);
Expand Down Expand Up @@ -274,7 +280,9 @@ class WebpackOptionsApply extends OptionsApply {

new JavascriptModulesPlugin().apply(compiler);
new JsonModulesPlugin().apply(compiler);
new WebAssemblyModulesPlugin().apply(compiler);
new WebAssemblyModulesPlugin({
mangleImports: options.optimization.mangleWasmImports
}).apply(compiler);

new EntryOptionPlugin().apply(compiler);
compiler.hooks.entryOption.call(options.context, options.entry);
Expand Down
1 change: 1 addition & 0 deletions lib/WebpackOptionsDefaulter.js
Expand Up @@ -257,6 +257,7 @@ class WebpackOptionsDefaulter extends OptionsDefaulter {
this.set("optimization.checkWasmTypes", "make", options =>
isProductionLikeMode(options)
);
this.set("optimization.mangleWasmImports", false);
this.set(
"optimization.namedModules",
"make",
Expand Down
13 changes: 11 additions & 2 deletions lib/node/ReadFileCompileWasmTemplatePlugin.js
Expand Up @@ -8,6 +8,10 @@ const Template = require("../Template");
const WasmMainTemplatePlugin = require("../wasm/WasmMainTemplatePlugin");

class ReadFileCompileWasmTemplatePlugin {
constructor(options) {
this.options = options || {};
}

apply(compiler) {
compiler.hooks.thisCompilation.tap(
"ReadFileCompileWasmTemplatePlugin",
Expand Down Expand Up @@ -40,8 +44,13 @@ class ReadFileCompileWasmTemplatePlugin {
]);

const plugin = new WasmMainTemplatePlugin(
generateLoadBinaryCode,
false
Object.assign(
{
generateLoadBinaryCode,
supportsStreaming: false
},
this.options
)
);
plugin.apply(compilation.mainTemplate);
}
Expand Down
124 changes: 83 additions & 41 deletions lib/wasm/WasmMainTemplatePlugin.js
Expand Up @@ -27,12 +27,16 @@ function getAllWasmModules(chunk) {
/**
* generates the import object function for a module
* @param {Module} module the module
* @param {boolean} mangle mangle imports
* @returns {string} source code
*/
function generateImportObject(module) {
function generateImportObject(module, mangle) {
const waitForInstances = new Map();
const properties = [];
const usedWasmDependencies = WebAssemblyUtils.getUsedDependencies(module);
const usedWasmDependencies = WebAssemblyUtils.getUsedDependencies(
module,
mangle
);
for (const usedDep of usedWasmDependencies) {
const dep = usedDep.dependency;
const importedModule = dep.module;
Expand All @@ -41,15 +45,17 @@ function generateImportObject(module) {
const description = dep.description;
const direct = dep.onlyDirectImport;

const propertyName = usedDep.name;
const module = usedDep.module;
const name = usedDep.name;

if (direct) {
const instanceVar = `m${waitForInstances.size}`;
waitForInstances.set(instanceVar, importedModule.id);
properties.push(
`${JSON.stringify(propertyName)}: ${instanceVar}` +
`[${JSON.stringify(usedName)}]`
);
properties.push({
module,
name,
value: `${instanceVar}[${JSON.stringify(usedName)}]`
});
} else {
const params = description.signature.params.map(
(param, k) => "p" + k + param.valtype
Expand All @@ -58,20 +64,55 @@ function generateImportObject(module) {
const mod = `installedModules[${JSON.stringify(importedModule.id)}]`;
const func = `${mod}.exports[${JSON.stringify(usedName)}]`;

properties.push(
Template.asString([
`${JSON.stringify(propertyName)}: ` +
(importedModule.type.startsWith("webassembly")
? `${mod} ? ${func} : `
: "") +
`function(${params}) {`,
properties.push({
module,
name,
value: Template.asString([
(importedModule.type.startsWith("webassembly")
? `${mod} ? ${func} : `
: "") + `function(${params}) {`,
Template.indent([`return ${func}(${params});`]),
"}"
])
);
});
}
}

let importObject;
if (mangle) {
importObject = [
"return {",
Template.indent([
properties.map(p => `${JSON.stringify(p.name)}: ${p.value}`).join(",\n")
]),
"};"
];
} else {
const propertiesByModule = new Map();
for (const p of properties) {
let list = propertiesByModule.get(p.module);
if (list === undefined) {
propertiesByModule.set(p.module, (list = []));
}
list.push(p);
}
importObject = [
"return {",
Template.indent([
Array.from(propertiesByModule, ([module, list]) => {
return Template.asString([
`${JSON.stringify(module)}: {`,
Template.indent([
list.map(p => `${JSON.stringify(p.name)}: ${p.value}`).join(",\n")
]),
"}"
]);
}).join(",\n")
]),
"};"
];
}

if (waitForInstances.size === 1) {
const moduleId = Array.from(waitForInstances.values())[0];
const promise = `installedWasmModules[${JSON.stringify(moduleId)}]`;
Expand All @@ -80,11 +121,7 @@ function generateImportObject(module) {
`${JSON.stringify(module.id)}: function() {`,
Template.indent([
`return promiseResolve().then(function() { return ${promise}; }).then(function(${variable}) {`,
Template.indent([
"return {",
Template.indent([properties.join(",\n")]),
"};"
]),
Template.indent(importObject),
"});"
]),
"},"
Expand All @@ -102,41 +139,35 @@ function generateImportObject(module) {
`${JSON.stringify(module.id)}: function() {`,
Template.indent([
`return promiseResolve().then(function() { return Promise.all([${promises}]); }).then(function(array) {`,
Template.indent([
`var ${variables};`,
"return {",
Template.indent([properties.join(",\n")]),
"};"
]),
Template.indent([`var ${variables};`, ...importObject]),
"});"
]),
"},"
]);
} else {
return Template.asString([
`${JSON.stringify(module.id)}: function() {`,
Template.indent([
"return {",
Template.indent([properties.join(",\n")]),
"};"
]),
Template.indent(importObject),
"},"
]);
}
}

class WasmMainTemplatePlugin {
constructor(generateLoadBinaryCode, supportsStreaming) {
constructor({ generateLoadBinaryCode, supportsStreaming, mangleImports }) {
this.generateLoadBinaryCode = generateLoadBinaryCode;
this.supportsStreaming = supportsStreaming;
this.mangleImports = mangleImports;
}
apply(mainTemplate) {
mainTemplate.hooks.localVars.tap(
"WasmMainTemplatePlugin",
(source, chunk) => {
const wasmModules = getAllWasmModules(chunk);
if (wasmModules.length === 0) return source;
const importObjects = wasmModules.map(generateImportObject);
const importObjects = wasmModules.map(module => {
return generateImportObject(module, this.mangleImports);
});
return Template.asString([
source,
"",
Expand Down Expand Up @@ -192,6 +223,12 @@ class WasmMainTemplatePlugin {
}
}
);
const createImportObject = content =>
this.mangleImports
? `{ ${JSON.stringify(
WebAssemblyUtils.MANGLED_MODULE
)}: ${content} }`
: content;
return Template.asString([
source,
"",
Expand Down Expand Up @@ -219,15 +256,17 @@ class WasmMainTemplatePlugin {
Template.indent([
"promise = Promise.all([WebAssembly.compileStreaming(req), importObject]).then(function(items) {",
Template.indent([
"return WebAssembly.instantiate(items[0], " +
`{ ${WebAssemblyUtils.MANGLED_MODULE}: items[1] });`
`return WebAssembly.instantiate(items[0], ${createImportObject(
"items[1]"
)});`
]),
"});"
]),
"} else if(typeof WebAssembly.instantiateStreaming === 'function') {",
Template.indent([
"promise = WebAssembly.instantiateStreaming(req, " +
`{ ${WebAssemblyUtils.MANGLED_MODULE}: importObject });`
`promise = WebAssembly.instantiateStreaming(req, ${createImportObject(
"importObject"
)});`
])
])
: Template.asString([
Expand All @@ -241,8 +280,9 @@ class WasmMainTemplatePlugin {
]),
"]).then(function(items) {",
Template.indent([
"return WebAssembly.instantiate(items[0], " +
`{ ${WebAssemblyUtils.MANGLED_MODULE}: items[1] });`
`return WebAssembly.instantiate(items[0], ${createImportObject(
"items[1]"
)});`
]),
"});"
])
Expand All @@ -252,8 +292,9 @@ class WasmMainTemplatePlugin {
"var bytesPromise = req.then(function(x) { return x.arrayBuffer(); });",
"promise = bytesPromise.then(function(bytes) {",
Template.indent([
"return WebAssembly.instantiate(bytes, " +
`{ ${WebAssemblyUtils.MANGLED_MODULE}: importObject });`
`return WebAssembly.instantiate(bytes, ${createImportObject(
"importObject"
)});`
]),
"});"
]),
Expand Down Expand Up @@ -290,6 +331,7 @@ class WasmMainTemplatePlugin {
hash.update("WasmMainTemplatePlugin");
hash.update("1");
hash.update(`${mainTemplate.outputOptions.webassemblyModuleFilename}`);
hash.update(`${this.mangleImports}`);
});
mainTemplate.hooks.hashForChunk.tap(
"WasmMainTemplatePlugin",
Expand Down
17 changes: 13 additions & 4 deletions lib/wasm/WebAssemblyGenerator.js
Expand Up @@ -294,7 +294,7 @@ const rewriteImports = ({ ast, usedDependencyMap }) => bin => {
);

if (typeof result !== "undefined") {
path.node.module = WebAssemblyUtils.MANGLED_MODULE;
path.node.module = result.module;
path.node.name = result.name;
}
}
Expand Down Expand Up @@ -374,12 +374,13 @@ const addInitFunction = ({
/**
* Extract mangle mappings from module
* @param {Module} module current module
* @param {boolean} mangle mangle imports
* @returns {Map<string, UsedWasmDependency>} mappings to mangled names
*/
const getUsedDependencyMap = module => {
const getUsedDependencyMap = (module, mangle) => {
/** @type {Map<string, UsedWasmDependency>} */
const map = new Map();
for (const usedDep of WebAssemblyUtils.getUsedDependencies(module)) {
for (const usedDep of WebAssemblyUtils.getUsedDependencies(module, mangle)) {
const dep = usedDep.dependency;
const request = dep.request;
const exportName = dep.name;
Expand All @@ -389,6 +390,11 @@ const getUsedDependencyMap = module => {
};

class WebAssemblyGenerator extends Generator {
constructor(options) {
super();
this.options = options;
}

generate(module) {
let bin = module.originalSource().source();
bin = preprocess(bin);
Expand All @@ -411,7 +417,10 @@ class WebAssemblyGenerator extends Generator {
const nextFuncIndex = getNextFuncIndex(ast, countImportedFunc);
const nextTypeIndex = getNextTypeIndex(ast);

const usedDependencyMap = getUsedDependencyMap(module);
const usedDependencyMap = getUsedDependencyMap(
module,
this.options.mangleImports
);
const externalExports = new Set(
module.dependencies
.filter(d => d instanceof WebAssemblyExportImportedDependency)
Expand Down
6 changes: 5 additions & 1 deletion lib/wasm/WebAssemblyModulesPlugin.js
Expand Up @@ -12,6 +12,10 @@ const WebAssemblyImportDependency = require("../dependencies/WebAssemblyImportDe
const WebAssemblyExportImportedDependency = require("../dependencies/WebAssemblyExportImportedDependency");

class WebAssemblyModulesPlugin {
constructor(options) {
this.options = options;
}

apply(compiler) {
compiler.hooks.compilation.tap(
"WebAssemblyModulesPlugin",
Expand All @@ -37,7 +41,7 @@ class WebAssemblyModulesPlugin {
.tap("WebAssemblyModulesPlugin", () => {
return Generator.byType({
javascript: new WebAssemblyJavascriptGenerator(),
webassembly: new WebAssemblyGenerator()
webassembly: new WebAssemblyGenerator(this.options)
});
});

Expand Down

0 comments on commit 8e3be48

Please sign in to comment.