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-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
|
|
|
);
|
|
|
|
|
2018-01-24 06:09:26 +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);
|
2018-01-24 06:09:26 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
module.exports = WebAssemblyGenerator;
|