git ssb

0+

wanderer🌟 / js-primea-wasm-container



Tree: f5b59c97800ffbfc5bc0a2e98c9ed035dea81ba7

Files: f5b59c97800ffbfc5bc0a2e98c9ed035dea81ba7 / index.js

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

Built with git-ssb-web