Files: 1acaf62122a024e6a953fb715cf4bbda94b804ad / index.js
3531 bytesRaw
1 | const ReferanceMap = require('reference-map') |
2 | const AbstractContainer = require('primea-abstract-container') |
3 | const ContainerTable = require('primea-container-table') |
4 | |
5 | module.exports = class WasmContainer extends AbstractContainer { |
6 | /** |
7 | * The wasm container runs wasm code and provides a basic API for wasm |
8 | * interfaces for interacting with the kernel |
9 | * @param {object} kernel - the kernel instance |
10 | * @param {object} interfaces - a map of interfaces to expose to the wasm binary |
11 | */ |
12 | constructor (kernel, interfaces) { |
13 | super() |
14 | this.kernel = kernel |
15 | this.imports = interfaces |
16 | this.referanceMap = new ReferanceMap() |
17 | } |
18 | |
19 | async onCreation (message) { |
20 | let code = message.data |
21 | if (!WebAssembly.validate(code)) { |
22 | throw new Error('invalid wasm binary') |
23 | } else { |
24 | for (const name in this.imports) { |
25 | const interf = this.imports[name] |
26 | if (interf.initialize) { |
27 | code = await interf.initialize(code) |
28 | } |
29 | } |
30 | this.kernel.state.code = code |
31 | } |
32 | return this._run(message, 'onCreation') |
33 | } |
34 | |
35 | /** |
36 | * Runs the wasm VM given a message |
37 | * @param {object} message |
38 | * @returns {Promise} a promise that resolves once the compuation is finished |
39 | */ |
40 | onMessage (message) { |
41 | return this._run(message, 'onMessage') |
42 | } |
43 | |
44 | async _run (message, method) { |
45 | // Builds a import map with an array of given interfaces |
46 | const importMap = {} |
47 | for (const name in this.imports) { |
48 | importMap[name] = {} |
49 | const Import = this.imports[name] |
50 | const newInterface = new Import(this) |
51 | const props = Object.getOwnPropertyNames(Import.prototype) |
52 | |
53 | // bind the methods to the correct 'this' |
54 | for (const prop of props) { |
55 | if (prop !== 'constructor') { |
56 | importMap[name][prop] = newInterface[prop].bind(newInterface) |
57 | } |
58 | } |
59 | } |
60 | |
61 | const result = await WebAssembly.instantiate(this.kernel.state.code, importMap) |
62 | this.instance = result.instance |
63 | |
64 | // add the message and ports to the refereance map |
65 | const messageRef = this.referanceMap.add(message) |
66 | message.ports.forEach(port => this.referanceMap.add()) |
67 | |
68 | // runs the wasm code |
69 | this.instance.exports[method](messageRef) |
70 | return this.onDone() |
71 | } |
72 | |
73 | /** |
74 | * returns a promise that resolves when the wasm instance is done running |
75 | * @returns {Promise} |
76 | */ |
77 | async onDone () { |
78 | let prevOps |
79 | while (prevOps !== this._opsQueue) { |
80 | prevOps = this._opsQueue |
81 | await prevOps |
82 | } |
83 | this.referanceMap.clear() |
84 | } |
85 | |
86 | /** |
87 | * Pushed an async operation to the a promise queue that |
88 | * @returns {Promise} the returned promise resolves in the order the intail |
89 | * operation was pushed to the queue |
90 | */ |
91 | pushOpsQueue (promise) { |
92 | this._opsQueue = Promise.all([this._opsQueue, promise]) |
93 | return this._opsQueue |
94 | } |
95 | |
96 | /** |
97 | * executes a callback given an index in the exported callback container |
98 | * @param {integer} cb |
99 | * @param {*} val - a value to return to the callback function |
100 | */ |
101 | execute (cb, val) { |
102 | this.instance.exports.callbacks.get(cb)(val) |
103 | } |
104 | |
105 | /** |
106 | * returns a section of memory from the wasm instance |
107 | * @param {integer} offset |
108 | * @param {integer} length |
109 | * @returns {Uint8Array} |
110 | */ |
111 | getMemory (offset, length) { |
112 | return new Uint8Array(this.instance.exports.memory.buffer, offset, length) |
113 | } |
114 | |
115 | setMemory (offset, val) { |
116 | const mem = this.getMemory(offset, val.length) |
117 | mem.set(val) |
118 | } |
119 | |
120 | static get typeId () { |
121 | return ContainerTable.WebAssembly |
122 | } |
123 | } |
124 |
Built with git-ssb-web