webpack/lib/WebAssemblyGenerator.js

149 lines
3.1 KiB
JavaScript
Raw Normal View History

/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
"use strict";
2018-03-09 00:54:06 +08:00
const { RawSource } = require("webpack-sources");
const { edit, add } = require("@webassemblyjs/wasm-edit");
const { decode } = require("@webassemblyjs/wasm-parser");
// const { print } = require("@webassemblyjs/wast-printer");
const t = require("@webassemblyjs/ast");
// FIXME(sven): remove this once we're ready to merge
function debug(...msg) {
if (false) console.log(...msg);
}
function compose(...fns) {
return fns.reverse().reduce((prevFn, nextFn) => {
return value => nextFn(prevFn(value));
}, value => value);
}
2018-03-09 19:04:27 +08:00
/**
* Utility functions
*/
const isGlobalImport = moduleImport => moduleImport.descr.type === "GlobalType";
2018-03-09 00:54:06 +08:00
/**
* Export the start function and removes the start instruction
*/
function rewriteStartFunc(bin) {
debug("rewriteStartFunc");
let startAtFuncIndex;
bin = edit(bin, {
Start(path) {
startAtFuncIndex = path.node.index;
path.remove();
}
});
// No start func, abort here
if (startAtFuncIndex === undefined) {
return bin;
}
debug("found start at func index", startAtFuncIndex.value);
bin = add(bin, [t.moduleExport("start", "Func", startAtFuncIndex)]);
return bin;
}
/**
2018-03-10 02:03:33 +08:00
* Remove the ModuleImport for globals but keep the global declaration
2018-03-09 19:04:27 +08:00
*
* @param {ArrayBuffer} bin
* @returns {ArrayBuffer} bin'
*/
function removeImportedGlobals(bin) {
2018-03-10 02:03:33 +08:00
const newGlobals = [];
bin = edit(bin, {
2018-03-09 19:04:27 +08:00
ModuleImport(path) {
if (isGlobalImport(path.node) === true) {
debug("remove import", path.node.module, path.node.name);
2018-03-10 02:03:33 +08:00
const globalType = path.node.descr;
globalType.mutability = "var";
newGlobals.push(
t.global(globalType, [
t.objectInstruction("const", "i32", [t.numberLiteral(0)])
])
);
2018-03-09 19:04:27 +08:00
path.remove();
}
}
});
2018-03-10 02:03:33 +08:00
return add(bin, newGlobals);
2018-03-09 19:04:27 +08:00
}
/**
2018-03-10 02:03:33 +08:00
* Add our init function.
2018-03-09 19:04:27 +08:00
*
* @param {ArrayBuffer} bin
* @returns {ArrayBuffer} bin'
*/
2018-03-10 02:03:33 +08:00
function addInitFunction(bin) {
// get next func index
2018-03-09 00:54:06 +08:00
const ast = decode(bin, {
ignoreDataSection: true
});
2018-03-10 02:03:33 +08:00
const section = t.getSectionMetadata(ast, "func");
const nextTypeIndex = section.vectorOfSize;
const func = t.func(
null,
[t.funcParam("i32")],
[],
[
t.instruction("get_local", [t.indexLiteral(0)]),
t.instruction("set_global", [t.indexLiteral(0)])
]
);
const functype = t.typeInstructionFunc(func.params, func.result);
const funcindex = t.indexInFuncSection(t.indexLiteral(nextTypeIndex));
const moduleExport = t.moduleExport(
"__init__",
"Func",
t.indexLiteral(nextTypeIndex + 1)
);
return add(bin, [func, moduleExport, funcindex, functype]);
2018-03-09 00:54:06 +08:00
}
const transform = compose(
2018-03-09 19:04:27 +08:00
removeImportedGlobals,
2018-03-10 02:03:33 +08:00
addInitFunction
2018-03-09 00:54:06 +08:00
2018-03-10 02:03:33 +08:00
// rewriteStartFunc
2018-03-09 00:54:06 +08:00
);
class WebAssemblyGenerator {
generate(module) {
2018-03-09 00:54:06 +08:00
const bin = module.originalSource().source();
debug("__________________________________________________________");
const newBin = transform(bin);
debug("__________________________________________________________");
2018-03-09 19:04:27 +08:00
// console.log(print(decode(newBin)));
2018-03-09 00:54:06 +08:00
return new RawSource(newBin);
}
}
module.exports = WebAssemblyGenerator;