module.exports = class WasmContainer {
/**
* The interface API is the api the exposed to interfaces. All queries about
* the enviroment and call to the kernel go through this API
*/
constructor (code) {
this._module = WebAssembly.Module(code)
}
static get name () {
return 'wasm'
}
/**
* Runs the core VM with a given environment and imports
*/
async run (message, kernel, imports = []) {
const responses = {}
/**
* Builds a import map with an array of given interfaces
*/
function buildImports (opts, imports) {
const importMap = {}
for (const Import of imports) {
const name = Import.name
opts.response = responses[name] = {}
const newInterface = new Import(opts)
const props = Object.getOwnPropertyNames(Import.prototype)
// bind the methods to the correct 'this'
importMap[name] = {}
for (const prop of props) {
importMap[name][prop] = newInterface[prop].bind(newInterface)
}
}
return importMap
}
let instance
const opts = {
vm: {
/**
* adds an aync operation to the operations queue
*/
pushOpsQueue: (promise, callbackIndex) => {
this._opsQueue = Promise.all([this._opsQueue, promise]).then(values => {
const result = values.pop()
instance.exports.callback.get(callbackIndex)(result)
})
},
memory: () => {
return instance.exports.memory.buffer
}
},
kernel: kernel,
message: message
}
const initializedImports = buildImports(opts, imports)
instance = WebAssembly.Instance(this._module, initializedImports)
if (instance.exports.main) {
instance.exports.main()
}
await this.onDone()
return responses
}
/**
* returns a promise that resolves when the wasm instance is done running
*/
async onDone () {
let prevOps
while (prevOps !== this._opsQueue) {
prevOps = this._opsQueue
await this._opsQueue
}
}
}
|