git ssb

0+

wanderer🌟 / js-primea-wasm-container



Tree: 78d8551867f662dbcd26577f31cc14529b535ff0

Files: 78d8551867f662dbcd26577f31cc14529b535ff0 / index.js

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

Built with git-ssb-web