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