git ssb

0+

wanderer🌟 / wasm-persist



Commit ef2bd6aff34a889b871ba0df64660c209670a621

nit

Signed-off-by: wanderer <mjbecze@gmail.com>
wanderer committed on 4/25/2018, 4:52:59 AM

Files changed

.travis.ymladded
LICENSEadded
README.mdadded
docs/index.mdadded
index.jsadded
injectGettersSetters.jsadded
package-lock.jsonadded
package.jsonadded
tests/index.jsadded
tests/wasm/customSections.wasmadded
tests/wasm/doubleGlobals.wasmadded
tests/wasm/empty.wasmadded
tests/wasm/singleFunction.wasmadded
tests/wasm/singleGlobal.wasmadded
tests/wasm/singleI32Global.wasmadded
tests/wasm/singleI64Global.wasmadded
tests/wasm/singleImport.wasmadded
tests/wasm/singleMemory.wasmadded
tests/wasm/singleTable.wasmadded
tests/wasm/singleType.wasmadded
tests/wast/doubleGlobals.wastadded
tests/wast/empty.wastadded
tests/wast/singleFunction.wastadded
tests/wast/singleI32Global.wastadded
tests/wast/singleI64Global.wastadded
tests/wast/singleImport.wastadded
tests/wast/singleMemory.wastadded
tests/wast/singleTable.wastadded
tests/wast/singleType.wastadded
tests/wast2wasm.jsadded
.travis.ymlView
@@ -1,0 +1,24 @@
1 +language: node_js
2 +node_js:
3 + - "9"
4 +env:
5 + global:
6 + - CXX=g++-4.8
7 + matrix:
8 + - TEST_SUITE=test
9 +addons:
10 + apt:
11 + sources:
12 + - ubuntu-toolchain-r-test
13 + packages:
14 + - g++-4.8
15 +matrix:
16 + fast_finish: true
17 + include:
18 + - os: linux
19 + node_js: "9"
20 + env: TEST_SUITE=coveralls
21 + - os: linux
22 + node_js: "9"
23 + env: TEST_SUITE=lint
24 +script: npm run $TEST_SUITE
LICENSEView
@@ -1,0 +1,373 @@
1 +Mozilla Public License Version 2.0
2 +==================================
3 +
4 +1. Definitions
5 +--------------
6 +
7 +1.1. "Contributor"
8 + means each individual or legal entity that creates, contributes to
9 + the creation of, or owns Covered Software.
10 +
11 +1.2. "Contributor Version"
12 + means the combination of the Contributions of others (if any) used
13 + by a Contributor and that particular Contributor's Contribution.
14 +
15 +1.3. "Contribution"
16 + means Covered Software of a particular Contributor.
17 +
18 +1.4. "Covered Software"
19 + means Source Code Form to which the initial Contributor has attached
20 + the notice in Exhibit A, the Executable Form of such Source Code
21 + Form, and Modifications of such Source Code Form, in each case
22 + including portions thereof.
23 +
24 +1.5. "Incompatible With Secondary Licenses"
25 + means
26 +
27 + (a) that the initial Contributor has attached the notice described
28 + in Exhibit B to the Covered Software; or
29 +
30 + (b) that the Covered Software was made available under the terms of
31 + version 1.1 or earlier of the License, but not also under the
32 + terms of a Secondary License.
33 +
34 +1.6. "Executable Form"
35 + means any form of the work other than Source Code Form.
36 +
37 +1.7. "Larger Work"
38 + means a work that combines Covered Software with other material, in
39 + a separate file or files, that is not Covered Software.
40 +
41 +1.8. "License"
42 + means this document.
43 +
44 +1.9. "Licensable"
45 + means having the right to grant, to the maximum extent possible,
46 + whether at the time of the initial grant or subsequently, any and
47 + all of the rights conveyed by this License.
48 +
49 +1.10. "Modifications"
50 + means any of the following:
51 +
52 + (a) any file in Source Code Form that results from an addition to,
53 + deletion from, or modification of the contents of Covered
54 + Software; or
55 +
56 + (b) any new file in Source Code Form that contains any Covered
57 + Software.
58 +
59 +1.11. "Patent Claims" of a Contributor
60 + means any patent claim(s), including without limitation, method,
61 + process, and apparatus claims, in any patent Licensable by such
62 + Contributor that would be infringed, but for the grant of the
63 + License, by the making, using, selling, offering for sale, having
64 + made, import, or transfer of either its Contributions or its
65 + Contributor Version.
66 +
67 +1.12. "Secondary License"
68 + means either the GNU General Public License, Version 2.0, the GNU
69 + Lesser General Public License, Version 2.1, the GNU Affero General
70 + Public License, Version 3.0, or any later versions of those
71 + licenses.
72 +
73 +1.13. "Source Code Form"
74 + means the form of the work preferred for making modifications.
75 +
76 +1.14. "You" (or "Your")
77 + means an individual or a legal entity exercising rights under this
78 + License. For legal entities, "You" includes any entity that
79 + controls, is controlled by, or is under common control with You. For
80 + purposes of this definition, "control" means (a) the power, direct
81 + or indirect, to cause the direction or management of such entity,
82 + whether by contract or otherwise, or (b) ownership of more than
83 + fifty percent (50%) of the outstanding shares or beneficial
84 + ownership of such entity.
85 +
86 +2. License Grants and Conditions
87 +--------------------------------
88 +
89 +2.1. Grants
90 +
91 +Each Contributor hereby grants You a world-wide, royalty-free,
92 +non-exclusive license:
93 +
94 +(a) under intellectual property rights (other than patent or trademark)
95 + Licensable by such Contributor to use, reproduce, make available,
96 + modify, display, perform, distribute, and otherwise exploit its
97 + Contributions, either on an unmodified basis, with Modifications, or
98 + as part of a Larger Work; and
99 +
100 +(b) under Patent Claims of such Contributor to make, use, sell, offer
101 + for sale, have made, import, and otherwise transfer either its
102 + Contributions or its Contributor Version.
103 +
104 +2.2. Effective Date
105 +
106 +The licenses granted in Section 2.1 with respect to any Contribution
107 +become effective for each Contribution on the date the Contributor first
108 +distributes such Contribution.
109 +
110 +2.3. Limitations on Grant Scope
111 +
112 +The licenses granted in this Section 2 are the only rights granted under
113 +this License. No additional rights or licenses will be implied from the
114 +distribution or licensing of Covered Software under this License.
115 +Notwithstanding Section 2.1(b) above, no patent license is granted by a
116 +Contributor:
117 +
118 +(a) for any code that a Contributor has removed from Covered Software;
119 + or
120 +
121 +(b) for infringements caused by: (i) Your and any other third party's
122 + modifications of Covered Software, or (ii) the combination of its
123 + Contributions with other software (except as part of its Contributor
124 + Version); or
125 +
126 +(c) under Patent Claims infringed by Covered Software in the absence of
127 + its Contributions.
128 +
129 +This License does not grant any rights in the trademarks, service marks,
130 +or logos of any Contributor (except as may be necessary to comply with
131 +the notice requirements in Section 3.4).
132 +
133 +2.4. Subsequent Licenses
134 +
135 +No Contributor makes additional grants as a result of Your choice to
136 +distribute the Covered Software under a subsequent version of this
137 +License (see Section 10.2) or under the terms of a Secondary License (if
138 +permitted under the terms of Section 3.3).
139 +
140 +2.5. Representation
141 +
142 +Each Contributor represents that the Contributor believes its
143 +Contributions are its original creation(s) or it has sufficient rights
144 +to grant the rights to its Contributions conveyed by this License.
145 +
146 +2.6. Fair Use
147 +
148 +This License is not intended to limit any rights You have under
149 +applicable copyright doctrines of fair use, fair dealing, or other
150 +equivalents.
151 +
152 +2.7. Conditions
153 +
154 +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
155 +in Section 2.1.
156 +
157 +3. Responsibilities
158 +-------------------
159 +
160 +3.1. Distribution of Source Form
161 +
162 +All distribution of Covered Software in Source Code Form, including any
163 +Modifications that You create or to which You contribute, must be under
164 +the terms of this License. You must inform recipients that the Source
165 +Code Form of the Covered Software is governed by the terms of this
166 +License, and how they can obtain a copy of this License. You may not
167 +attempt to alter or restrict the recipients' rights in the Source Code
168 +Form.
169 +
170 +3.2. Distribution of Executable Form
171 +
172 +If You distribute Covered Software in Executable Form then:
173 +
174 +(a) such Covered Software must also be made available in Source Code
175 + Form, as described in Section 3.1, and You must inform recipients of
176 + the Executable Form how they can obtain a copy of such Source Code
177 + Form by reasonable means in a timely manner, at a charge no more
178 + than the cost of distribution to the recipient; and
179 +
180 +(b) You may distribute such Executable Form under the terms of this
181 + License, or sublicense it under different terms, provided that the
182 + license for the Executable Form does not attempt to limit or alter
183 + the recipients' rights in the Source Code Form under this License.
184 +
185 +3.3. Distribution of a Larger Work
186 +
187 +You may create and distribute a Larger Work under terms of Your choice,
188 +provided that You also comply with the requirements of this License for
189 +the Covered Software. If the Larger Work is a combination of Covered
190 +Software with a work governed by one or more Secondary Licenses, and the
191 +Covered Software is not Incompatible With Secondary Licenses, this
192 +License permits You to additionally distribute such Covered Software
193 +under the terms of such Secondary License(s), so that the recipient of
194 +the Larger Work may, at their option, further distribute the Covered
195 +Software under the terms of either this License or such Secondary
196 +License(s).
197 +
198 +3.4. Notices
199 +
200 +You may not remove or alter the substance of any license notices
201 +(including copyright notices, patent notices, disclaimers of warranty,
202 +or limitations of liability) contained within the Source Code Form of
203 +the Covered Software, except that You may alter any license notices to
204 +the extent required to remedy known factual inaccuracies.
205 +
206 +3.5. Application of Additional Terms
207 +
208 +You may choose to offer, and to charge a fee for, warranty, support,
209 +indemnity or liability obligations to one or more recipients of Covered
210 +Software. However, You may do so only on Your own behalf, and not on
211 +behalf of any Contributor. You must make it absolutely clear that any
212 +such warranty, support, indemnity, or liability obligation is offered by
213 +You alone, and You hereby agree to indemnify every Contributor for any
214 +liability incurred by such Contributor as a result of warranty, support,
215 +indemnity or liability terms You offer. You may include additional
216 +disclaimers of warranty and limitations of liability specific to any
217 +jurisdiction.
218 +
219 +4. Inability to Comply Due to Statute or Regulation
220 +---------------------------------------------------
221 +
222 +If it is impossible for You to comply with any of the terms of this
223 +License with respect to some or all of the Covered Software due to
224 +statute, judicial order, or regulation then You must: (a) comply with
225 +the terms of this License to the maximum extent possible; and (b)
226 +describe the limitations and the code they affect. Such description must
227 +be placed in a text file included with all distributions of the Covered
228 +Software under this License. Except to the extent prohibited by statute
229 +or regulation, such description must be sufficiently detailed for a
230 +recipient of ordinary skill to be able to understand it.
231 +
232 +5. Termination
233 +--------------
234 +
235 +5.1. The rights granted under this License will terminate automatically
236 +if You fail to comply with any of its terms. However, if You become
237 +compliant, then the rights granted under this License from a particular
238 +Contributor are reinstated (a) provisionally, unless and until such
239 +Contributor explicitly and finally terminates Your grants, and (b) on an
240 +ongoing basis, if such Contributor fails to notify You of the
241 +non-compliance by some reasonable means prior to 60 days after You have
242 +come back into compliance. Moreover, Your grants from a particular
243 +Contributor are reinstated on an ongoing basis if such Contributor
244 +notifies You of the non-compliance by some reasonable means, this is the
245 +first time You have received notice of non-compliance with this License
246 +from such Contributor, and You become compliant prior to 30 days after
247 +Your receipt of the notice.
248 +
249 +5.2. If You initiate litigation against any entity by asserting a patent
250 +infringement claim (excluding declaratory judgment actions,
251 +counter-claims, and cross-claims) alleging that a Contributor Version
252 +directly or indirectly infringes any patent, then the rights granted to
253 +You by any and all Contributors for the Covered Software under Section
254 +2.1 of this License shall terminate.
255 +
256 +5.3. In the event of termination under Sections 5.1 or 5.2 above, all
257 +end user license agreements (excluding distributors and resellers) which
258 +have been validly granted by You or Your distributors under this License
259 +prior to termination shall survive termination.
260 +
261 +************************************************************************
262 +* *
263 +* 6. Disclaimer of Warranty *
264 +* ------------------------- *
265 +* *
266 +* Covered Software is provided under this License on an "as is" *
267 +* basis, without warranty of any kind, either expressed, implied, or *
268 +* statutory, including, without limitation, warranties that the *
269 +* Covered Software is free of defects, merchantable, fit for a *
270 +* particular purpose or non-infringing. The entire risk as to the *
271 +* quality and performance of the Covered Software is with You. *
272 +* Should any Covered Software prove defective in any respect, You *
273 +* (not any Contributor) assume the cost of any necessary servicing, *
274 +* repair, or correction. This disclaimer of warranty constitutes an *
275 +* essential part of this License. No use of any Covered Software is *
276 +* authorized under this License except under this disclaimer. *
277 +* *
278 +************************************************************************
279 +
280 +************************************************************************
281 +* *
282 +* 7. Limitation of Liability *
283 +* -------------------------- *
284 +* *
285 +* Under no circumstances and under no legal theory, whether tort *
286 +* (including negligence), contract, or otherwise, shall any *
287 +* Contributor, or anyone who distributes Covered Software as *
288 +* permitted above, be liable to You for any direct, indirect, *
289 +* special, incidental, or consequential damages of any character *
290 +* including, without limitation, damages for lost profits, loss of *
291 +* goodwill, work stoppage, computer failure or malfunction, or any *
292 +* and all other commercial damages or losses, even if such party *
293 +* shall have been informed of the possibility of such damages. This *
294 +* limitation of liability shall not apply to liability for death or *
295 +* personal injury resulting from such party's negligence to the *
296 +* extent applicable law prohibits such limitation. Some *
297 +* jurisdictions do not allow the exclusion or limitation of *
298 +* incidental or consequential damages, so this exclusion and *
299 +* limitation may not apply to You. *
300 +* *
301 +************************************************************************
302 +
303 +8. Litigation
304 +-------------
305 +
306 +Any litigation relating to this License may be brought only in the
307 +courts of a jurisdiction where the defendant maintains its principal
308 +place of business and such litigation shall be governed by laws of that
309 +jurisdiction, without reference to its conflict-of-law provisions.
310 +Nothing in this Section shall prevent a party's ability to bring
311 +cross-claims or counter-claims.
312 +
313 +9. Miscellaneous
314 +----------------
315 +
316 +This License represents the complete agreement concerning the subject
317 +matter hereof. If any provision of this License is held to be
318 +unenforceable, such provision shall be reformed only to the extent
319 +necessary to make it enforceable. Any law or regulation which provides
320 +that the language of a contract shall be construed against the drafter
321 +shall not be used to construe this License against a Contributor.
322 +
323 +10. Versions of the License
324 +---------------------------
325 +
326 +10.1. New Versions
327 +
328 +Mozilla Foundation is the license steward. Except as provided in Section
329 +10.3, no one other than the license steward has the right to modify or
330 +publish new versions of this License. Each version will be given a
331 +distinguishing version number.
332 +
333 +10.2. Effect of New Versions
334 +
335 +You may distribute the Covered Software under the terms of the version
336 +of the License under which You originally received the Covered Software,
337 +or under the terms of any subsequent version published by the license
338 +steward.
339 +
340 +10.3. Modified Versions
341 +
342 +If you create software not governed by this License, and you want to
343 +create a new license for such software, you may create and use a
344 +modified version of this License if you rename the license and remove
345 +any references to the name of the license steward (except to note that
346 +such modified license differs from this License).
347 +
348 +10.4. Distributing Source Code Form that is Incompatible With Secondary
349 +Licenses
350 +
351 +If You choose to distribute Source Code Form that is Incompatible With
352 +Secondary Licenses under the terms of this version of the License, the
353 +notice described in Exhibit B of this License must be attached.
354 +
355 +Exhibit A - Source Code Form License Notice
356 +-------------------------------------------
357 +
358 + This Source Code Form is subject to the terms of the Mozilla Public
359 + License, v. 2.0. If a copy of the MPL was not distributed with this
360 + file, You can obtain one at http://mozilla.org/MPL/2.0/.
361 +
362 +If it is not possible or desirable to put the notice in a particular
363 +file, then You may include the notice in a location (such as a LICENSE
364 +file in a relevant directory) where a recipient would be likely to look
365 +for such a notice.
366 +
367 +You may add additional accurate notices of copyright ownership.
368 +
369 +Exhibit B - "Incompatible With Secondary Licenses" Notice
370 +---------------------------------------------------------
371 +
372 + This Source Code Form is "Incompatible With Secondary Licenses", as
373 + defined by the Mozilla Public License, v. 2.0.
README.mdView
@@ -1,0 +1,46 @@
1 +# SYNOPSIS
2 +[![NPM Package](https://img.shields.io/npm/v/wasm-persist.svg?style=flat-square)](https://www.npmjs.org/package/wasm-persist)
3 +[![Build Status](https://img.shields.io/travis/dfinity/wasm-persist.svg?branch=master&style=flat-square)](https://travis-ci.org/dfinity/wasm-persist)
4 +[![Coverage Status](https://img.shields.io/coveralls/dfinity/wasm-persist.svg?style=flat-square)](https://coveralls.io/r/dfinity/wasm-persist)
5 +
6 +[![js-standard-style](https://cdn.rawgit.com/feross/standard/master/badge.svg)](https://github.com/feross/standard)
7 +
8 +This allows you to hibernate a WebAssembly instance and later start it up again
9 +at the exact place you left off
10 +
11 +# INSTALL
12 +`npm install wasm-persist`
13 +
14 +# USAGE
15 +
16 +```javascript
17 +const persist = require('wasm-persist')
18 +...
19 +wasm = persit.prepare(wasm)
20 +const {instance} = await WebAssembly.instantiate(wasm)
21 +// call some exported functions on your instance
22 +// then when you are done
23 +const state = persit.hibernate(instance)
24 +
25 +...
26 +
27 +// later you can revive the wasm instance
28 +const {instance} = await WebAssembly.instantiate(wasm)
29 +// just call persist.resume with the old state
30 +persit.resume(instance, state)
31 +```
32 +# DESCIPTION
33 +The Idea for wasm-perist came from [orthongal persistance](https://en.wikipedia.org/wiki/Persistence_(computer_science)#Orthogonal_or_transparent_persistence)
34 +wasm-persist injects getter and setter function for each global and exports the
35 +memory and table if they exist. Hibernate calls the getters and creates an Object
36 +that contains the memory (as a typedArray) the globals and the function table.
37 +Resume does the opposite and calls the setters for the globals and updates the
38 +memory and the table. Forgein function on the table are not handled currently.
39 +
40 +# API
41 +[./docs/](./docs/index.md)
42 +
43 +# LICENSE
44 +[MPL-2.0][LICENSE]
45 +
46 +[LICENSE]: https://tldrlegal.com/license/mozilla-public-license-2.0-(mpl-2)
docs/index.mdView
@@ -1,0 +1,62 @@
1 +<!-- Generated by documentation.js. Update this documentation by updating the source code. -->
2 +
3 +### Table of Contents
4 +
5 +- [prepare][1]
6 +- [hibernate][2]
7 +- [resume][3]
8 +
9 +## prepare
10 +
11 +Prepares a binary by injecting getter and setter function for memory, globals and tables.
12 +
13 +**Parameters**
14 +
15 +- `binary` **[ArrayBuffer][4]** a wasm binary
16 +- `include` **[Object][5]** (optional, default `{memory:true,table:true}`)
17 + - `include.memory` **[Boolean][6]** whether or not to included memory (optional, default `true`)
18 + - `include.table` **[Boolean][6]** whether or not to included the function table (optional, default `true`)
19 + - `include.globals` **[Array][7]&lt;[Boolean][6]>** whether or not to
20 + included a given global. Each index in the array stands for a global index.
21 + Indexes that are set to false or left undefined will not be persisted. By
22 + default all globals are persisted. (optional, default `Array.<true>`)
23 +- `symbol` **[String][8]** a sting used to prefix the injected setter and getter functions (optional, default `'_'`)
24 +
25 +Returns **[ArrayBuffer][4]** the resulting wasm binary
26 +
27 +## hibernate
28 +
29 +Given a wasm Instance this will produce an Object containing the current state of
30 +the instance
31 +
32 +**Parameters**
33 +
34 +- `instance` **Webassembly.Instance**
35 +- `symbol` **[String][8]** the symbol that will be used to find the injected functions (optional, default `'_'`)
36 +
37 +Returns **[Object][5]** the state of the wasm instance
38 +
39 +## resume
40 +
41 +resumes a prevously hibranted webassembly instance
42 +
43 +**Parameters**
44 +
45 +- `instance` **WebAssemby.Instance**
46 +- `state` **[Object][5]** the pervous state of the wasm instance
47 +
48 +[1]: #prepare
49 +
50 +[2]: #hibernate
51 +
52 +[3]: #resume
53 +
54 +[4]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer
55 +
56 +[5]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object
57 +
58 +[6]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean
59 +
60 +[7]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array
61 +
62 +[8]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String
index.jsView
@@ -1,0 +1,108 @@
1 +const inject = require('./injectGettersSetters.js')
2 +
3 +/**
4 + * Prepares a binary by injecting getter and setter function for memory, globals and tables.
5 + * @param {ArrayBuffer} binary - a wasm binary
6 + * @param {Object} include
7 + * @param {Boolean} [include.memory=true] - whether or not to included memory
8 + * @param {Boolean} [include.table=true] - whether or not to included the function table
9 + * @param {Array.<Boolean>} [include.globals=Array.<true>] - whether or not to
10 + * included a given global. Each index in the array stands for a global index.
11 + * Indexes that are set to false or left undefined will not be persisted. By
12 + * default all globals are persisted.
13 + * @param {String} [symbol = '_'] - a sting used to prefix the injected setter and getter functions
14 + * @return {ArrayBuffer} the resulting wasm binary
15 + */
16 +function prepare (binary, include = {memory: true, table: true}, symbol = '_') {
17 + return inject(binary, include, symbol)
18 +}
19 +
20 +/**
21 + * Given a wasm Instance this will produce an Object containing the current state of
22 + * the instance
23 + * @param {Webassembly.Instance} instance
24 + * @param {String} symbol - the symbol that will be used to find the injected functions
25 + * @returns {Object} the state of the wasm instance
26 + */
27 +function hibernate (instance, symbol = '_') {
28 + const json = {
29 + globals: [],
30 + table: [],
31 + symbol
32 + }
33 + for (const key in instance.exports) {
34 + const val = instance.exports[key]
35 + if (key.startsWith(symbol)) {
36 + const keyElems = key.slice(symbol.length).split('_')
37 + // save the memory
38 + if (val instanceof WebAssembly.Memory) {
39 + json.memory = new Uint32Array(val.buffer)
40 + } else if (val instanceof WebAssembly.Table) {
41 + // mark the tables, (do something for external function?)
42 + // the external functions should have a callback
43 + for (let i = 0; i < val.length; i++) {
44 + const func = val.get(i)
45 + if (func === instance.exports[`${symbol}func_${func.name}`]) {
46 + json.table.push(func.name)
47 + }
48 + }
49 + } else if (keyElems[0] === 'global' && keyElems[1] === 'getter') {
50 + // save the globals
51 + const last = keyElems.pop()
52 + if (last === 'high') {
53 + json.globals.push([instance.exports[key]()])
54 + } else if (last === 'low') {
55 + json.globals[json.globals.length - 1].push(instance.exports[key]())
56 + } else {
57 + json.globals.push(instance.exports[key]())
58 + }
59 + }
60 + }
61 + }
62 + instance.__hibrenated = true
63 + return json
64 +}
65 +
66 +/**
67 + * resumes a prevously hibranted webassembly instance
68 + * @param {WebAssemby.Instance} instance
69 + * @param {Object} state - the pervous state of the wasm instance
70 + * @retrun {WebAssembly.Instance}
71 + */
72 +function resume (instance, state) {
73 + if (instance.__hibrenated) {
74 + instance.__hibrenated = false
75 + } else {
76 + // initailize memory
77 + const mem = instance.exports[`${state.symbol}memory`]
78 + if (mem) {
79 + // console.log(mem.length)
80 + (new Uint32Array(mem.buffer)).set(state.memory, 0)
81 + }
82 +
83 + // initailize table
84 + if (instance.exports._table) {
85 + for (const index in state.table) {
86 + const funcIndex = state.table[index]
87 + instance.exports._table.set(index, instance.exports[`${state.symbol}func_${funcIndex}`])
88 + }
89 + }
90 +
91 + // intialize globals
92 + for (const index in state.globals) {
93 + const val = state.globals[index]
94 + if (Array.isArray(val)) {
95 + instance.exports[`${state.symbol}global_setter_i64_${index}`](val[1], val[0])
96 + } else {
97 + instance.exports[`${state.symbol}global_setter_i32_${index}`](val)
98 + }
99 + }
100 + }
101 + return instance
102 +}
103 +
104 +module.exports = {
105 + prepare,
106 + hibernate,
107 + resume
108 +}
injectGettersSetters.jsView
@@ -1,0 +1,180 @@
1 +const leb128 = require('leb128').unsigned
2 +const Pipe = require('buffer-pipe')
3 +const Iterator = require('wasm-json-toolkit').Iterator
4 +
5 +const EXTERNAL_KIND = {
6 + 'function': 0,
7 + 'table': 1,
8 + 'memory': 2,
9 + 'global': 3
10 +}
11 +
12 +module.exports = function prepare (wasm, include, symbol) {
13 + let globalI64SetterIndex, globalI32SetterIndex, globalGetterIndex, funcSection
14 + let numOfFuncs = 0
15 + let numOfImports = 0
16 + const addedCodeEntries = []
17 + const globalsGetterSetters = []
18 +
19 + const needExporting = {
20 + 'function': [],
21 + 'global': []
22 + }
23 +
24 + const it = new Iterator(wasm)
25 +
26 + for (const section of it) {
27 + if (section.type === 'type') {
28 + const numOfTypes = section.count
29 + // form: func, 1 param, i32, no return
30 + const globalI32SetterType = Buffer.from([0x60, 0x01, 0x7f, 0x0])
31 + // form: func, 2 param, i32, i32, no return
32 + const globalI64SetterType = Buffer.from([0x60, 0x02, 0x7f, 0x7f, 0x0])
33 + // form: func, 0 param, i32, 1 return
34 + const globalGetterType = Buffer.from([0x60, 0x00, 0x1, 0x7f])
35 + section.appendEntries([globalI32SetterType, globalI64SetterType, globalGetterType])
36 +
37 + globalI32SetterIndex = leb128.encode(numOfTypes)
38 + globalI64SetterIndex = leb128.encode(numOfTypes + 1)
39 + globalGetterIndex = leb128.encode(numOfTypes + 2)
40 + } else if (section.type === 'import') {
41 + // parse the import section to build the function indexes
42 + const json = section.toJSON()
43 + numOfImports = json.entries.filter(entry => entry.kind === 'function').length
44 + } else if (section.type === 'function') {
45 + // mark functions to be exported
46 + numOfFuncs = section.count
47 + funcSection = section
48 + needExporting['function'] = Array(section.count).fill(true)
49 + } else if (section.type === 'table') {
50 + needExporting['table'] = true && include.table
51 + } else if (section.type === 'memory') {
52 + needExporting['memory'] = true && include.memory
53 + } else if (section.type === 'global') {
54 + const json = section.toJSON()
55 + const addedFuncs = []
56 + if (!include.globals) {
57 + include.globals = new Array(json.entries.length).fill(true)
58 + }
59 + for (const i in json.entries) {
60 + const type = json.entries[i].type
61 + const lebIndex = leb128.encode(i)
62 + if (type.mutability && include.globals[i]) {
63 + if (type.contentType === 'i32') {
64 + globalsGetterSetters.push(type.contentType)
65 + addedFuncs.push(globalGetterIndex)
66 + addedFuncs.push(globalI32SetterIndex)
67 + // getter
68 + // size, local count, get_global, index, end
69 + addedCodeEntries.push(Buffer.concat([
70 + Buffer.from([0x03 + lebIndex.length, 0x00, 0x23]),
71 + lebIndex,
72 + Buffer.from([0x0b])
73 + ]))
74 + // setter
75 + // size, local count, get_local, index , set_global, index, end
76 + addedCodeEntries.push(Buffer.concat([
77 + Buffer.from([0x05 + lebIndex.length, 0x00, 0x20, 0x0, 0x24]),
78 + lebIndex,
79 + Buffer.from([0x0b])
80 + ]))
81 + } else {
82 + globalsGetterSetters.push(type.contentType)
83 + addedFuncs.push(globalGetterIndex)
84 + addedFuncs.push(globalGetterIndex)
85 + addedFuncs.push(globalI64SetterIndex)
86 + // 64 bit
87 + // getter high
88 + addedCodeEntries.push(Buffer.concat([
89 + Buffer.from([0x07 + lebIndex.length, 0x00, 0x23]),
90 + lebIndex,
91 + Buffer.from([0x42, 0x20, 0x88, 0xa7, 0x0b])
92 + ]))
93 +
94 + // get low
95 + addedCodeEntries.push(Buffer.concat([
96 + Buffer.from([0x04 + lebIndex.length, 0x00, 0x23]),
97 + lebIndex,
98 + Buffer.from([0xa7, 0x0b])
99 + ]))
100 + // (set_global $b
101 + // (i64.add
102 + // (i64.shl (i64.extend_u/i32 (get_local 0)) (i64.const 32))
103 + // (i64.extend_u/i32 (get_local 1))))
104 + // setter
105 + addedCodeEntries.push(Buffer.concat([
106 + Buffer.from([0x0d + lebIndex.length, 0x00, 0x20, 0x01, 0xad, 0x42, 0x20, 0x86, 0x20, 0x00, 0xad, 0x7c, 0x24]),
107 + lebIndex,
108 + Buffer.from([0x0b])
109 + ]))
110 + }
111 + }
112 + }
113 + funcSection.appendEntries(addedFuncs)
114 + } else if (section.type === 'export') {
115 + // export the memory
116 + const addedExports = []
117 + if (needExporting['memory']) {
118 + const funcExp = generateFuncExport(`${symbol}memory`, 0, 'memory')
119 + addedExports.push(funcExp)
120 + }
121 +
122 + // export the table
123 + if (needExporting['table']) {
124 + const funcExp = generateFuncExport(`${symbol}table`, 0, 'table')
125 + addedExports.push(funcExp)
126 + }
127 +
128 + // export functions
129 + const funcs = needExporting['function']
130 + for (let index in funcs) {
131 + index = Number(index)
132 + const funcExp = generateFuncExport(`${symbol}func_${index + numOfImports}`, numOfImports + index, 'function')
133 + addedExports.push(funcExp)
134 + }
135 +
136 + // export globals
137 + let globalFuncIndex = 0
138 + for (let index in globalsGetterSetters) {
139 + const type = globalsGetterSetters[index]
140 + const funcIndex = numOfImports + numOfFuncs + globalFuncIndex
141 + if (type === 'i32') {
142 + // getter
143 + const getter = generateFuncExport(`${symbol}global_getter_${type}_${index}`, funcIndex, 'function')
144 + addedExports.push(getter)
145 +
146 + // setter
147 + const setter = generateFuncExport(`${symbol}global_setter_${type}_${index}`, funcIndex + 1, 'function')
148 + addedExports.push(setter)
149 + globalFuncIndex += 2
150 + } else {
151 + // i64s
152 + // setter high
153 + const setterHigh = generateFuncExport(`${symbol}global_getter_${type}_${index}_high`, funcIndex, 'function')
154 + addedExports.push(setterHigh)
155 + // setter Low
156 + const setterLow = generateFuncExport(`${symbol}global_getter_${type}_${index}_low`, funcIndex + 1, 'function')
157 + addedExports.push(setterLow)
158 + // getter
159 + const getter = generateFuncExport(`${symbol}global_setter_${type}_${index}`, funcIndex + 2, 'function')
160 + addedExports.push(getter)
161 + globalFuncIndex += 3
162 + }
163 + }
164 + section.appendEntries(addedExports)
165 + } else if (section.type === 'code') {
166 + section.appendEntries(addedCodeEntries)
167 + }
168 + }
169 + return it.wasm
170 +}
171 +
172 +function generateFuncExport (name, index, type) {
173 + const setterHigh = new Pipe()
174 + const fieldString = Buffer.from(name)
175 + leb128.write(fieldString.length, setterHigh)
176 + setterHigh.write(fieldString)
177 + setterHigh.write(Buffer.from([EXTERNAL_KIND[type]]))
178 + leb128.write(index, setterHigh)
179 + return setterHigh.buffer
180 +}
package-lock.jsonView
The diff is too large to show. Use a local git client to view these changes.
Old file size: 0 bytes
New file size: 331017 bytes
package.jsonView
@@ -1,0 +1,40 @@
1 +{
2 + "name": "wasm-persist",
3 + "version": "0.0.0",
4 + "description": "a JS module for creating orthogonal persistent WebAssembly instances",
5 + "main": "index.js",
6 + "scripts": {
7 + "coveralls": "npm run coverage && nyc report --reporter=text-lcov | coveralls",
8 + "coverage": "nyc npm test",
9 + "lint": "standard",
10 + "test": "node ./tests/index.js",
11 + "build:docs": "documentation build --github -f md ./index.js > ./docs/index.md"
12 + },
13 + "keywords": [
14 + "WebAssembly",
15 + "wasm"
16 + ],
17 + "author": "mjbecze <mjbecze@gmail.com>",
18 + "license": "MPL-2.0",
19 + "dependencies": {
20 + "buffer-pipe": "0.0.2",
21 + "leb128": "0.0.4",
22 + "wasm-json-toolkit": "^0.3.0"
23 + },
24 + "devDependencies": {
25 + "coveralls": "^3.0.0",
26 + "documentation": "^6.2.0",
27 + "nyc": "^11.6.0",
28 + "standard": "^11.0.1",
29 + "tape": "^4.9.0",
30 + "wabt": "^1.0.0"
31 + },
32 + "repository": {
33 + "type": "git",
34 + "url": "git@github.com:dfinity/wasm-persist.git"
35 + },
36 + "bugs": {
37 + "url": "https://github.com/dfinity/wasm-persist/issues"
38 + },
39 + "homepage": "https://github.com/dfinity/wasm-persist"
40 +}
tests/index.jsView
@@ -1,0 +1,214 @@
1 +const fs = require('fs')
2 +const tape = require('tape')
3 +const persit = require('../')
4 +
5 +tape('empty', async t => {
6 + let wasm = fs.readFileSync(`${__dirname}/wasm/empty.wasm`)
7 + wasm = persit.prepare(wasm)
8 + const wasmInstance = await WebAssembly.instantiate(wasm)
9 + const json = persit.hibernate(wasmInstance.instance)
10 + persit.resume(wasmInstance.instance, json)
11 + t.deepEquals(json, {globals: [], table: [], symbol: '_'})
12 + t.equals(Object.keys(wasmInstance.instance.exports).length, 0)
13 +
14 + t.end()
15 +})
16 +
17 +tape('custom', async t => {
18 + let wasm = fs.readFileSync(`${__dirname}/wasm/customSections.wasm`)
19 + wasm = persit.prepare(wasm)
20 + const wasmInstance = await WebAssembly.instantiate(wasm)
21 + const json = persit.hibernate(wasmInstance.instance)
22 + persit.resume(wasmInstance.instance, json)
23 + t.deepEquals(json, {globals: [], table: [], symbol: '_'})
24 + t.equals(Object.keys(wasmInstance.instance.exports).length, 0)
25 +
26 + t.end()
27 +})
28 +
29 +tape('single type section', async t => {
30 + let wasm = fs.readFileSync(`${__dirname}/wasm/singleType.wasm`)
31 + wasm = persit.prepare(wasm)
32 + const wasmInstance = await WebAssembly.instantiate(wasm)
33 + const json = persit.hibernate(wasmInstance.instance)
34 + t.deepEquals(json, {globals: [], table: [], symbol: '_'})
35 + t.equals(Object.keys(wasmInstance.instance.exports).length, 0)
36 +
37 + t.end()
38 +})
39 +
40 +tape('single import section', async t => {
41 + let wasm = fs.readFileSync(`${__dirname}/wasm/singleImport.wasm`)
42 + wasm = persit.prepare(wasm)
43 + const wasmInstance = await WebAssembly.instantiate(wasm, {foo: {bar () {}}})
44 + const json = persit.hibernate(wasmInstance.instance)
45 + t.deepEquals(json, {globals: [], table: [], symbol: '_'})
46 + t.equals(Object.keys(wasmInstance.instance.exports).length, 0)
47 +
48 + t.end()
49 +})
50 +
51 +tape('single function', async t => {
52 + let wasm = fs.readFileSync(`${__dirname}/wasm/singleFunction.wasm`)
53 + wasm = persit.prepare(wasm)
54 + const wasmInstance = await WebAssembly.instantiate(wasm)
55 + const json = persit.hibernate(wasmInstance.instance)
56 + t.deepEquals(json, {globals: [], table: [], symbol: '_'})
57 + t.equals(Object.keys(wasmInstance.instance.exports).length, 2)
58 +
59 + t.end()
60 +})
61 +
62 +tape('single table', async t => {
63 + let wasm = fs.readFileSync(`${__dirname}/wasm/singleTable.wasm`)
64 + wasm = persit.prepare(wasm)
65 + const wasmInstance = await WebAssembly.instantiate(wasm)
66 + const json = persit.hibernate(wasmInstance.instance)
67 + t.deepEquals(json, {globals: [], table: ['0'], symbol: '_'})
68 + t.equals(Object.keys(wasmInstance.instance.exports).length, 3)
69 +
70 + t.end()
71 +})
72 +
73 +tape('single table with foregn fuction', async t => {
74 + let wasm = fs.readFileSync(`${__dirname}/wasm/singleTable.wasm`)
75 + wasm = persit.prepare(wasm)
76 + const wasmInstance = await WebAssembly.instantiate(wasm)
77 + const wasmInstance2 = await WebAssembly.instantiate(wasm)
78 + wasmInstance.instance.exports._table.set(0, wasmInstance2.instance.exports.e)
79 + const json = persit.hibernate(wasmInstance.instance)
80 + t.deepEquals(json, {globals: [], table: [], symbol: '_'})
81 + t.equals(Object.keys(wasmInstance.instance.exports).length, 3)
82 +
83 + t.end()
84 +})
85 +
86 +tape('single table resume', async t => {
87 + let wasm = fs.readFileSync(`${__dirname}/wasm/singleTable.wasm`)
88 + wasm = persit.prepare(wasm)
89 + const wasmInstance = await WebAssembly.instantiate(wasm)
90 + const json = persit.hibernate(wasmInstance.instance)
91 +
92 + const wasmInstance2 = await WebAssembly.instantiate(wasm)
93 + persit.resume(wasmInstance2.instance, json)
94 + const json2 = persit.hibernate(wasmInstance2.instance)
95 + t.deepEquals(json, json2)
96 + t.equals(Object.keys(wasmInstance.instance.exports).length, 3)
97 +
98 + t.end()
99 +})
100 +
101 +tape('single memory', async t => {
102 + let wasm = fs.readFileSync(`${__dirname}/wasm/singleMemory.wasm`)
103 + wasm = persit.prepare(wasm)
104 + const wasmInstance = await WebAssembly.instantiate(wasm)
105 + const json = persit.hibernate(wasmInstance.instance)
106 + t.equals(json.memory.length, 16384)
107 + t.equals(Object.keys(wasmInstance.instance.exports).length, 3)
108 +
109 + t.end()
110 +})
111 +
112 +tape('skipping memory', async t => {
113 + let wasm = fs.readFileSync(`${__dirname}/wasm/singleMemory.wasm`)
114 + wasm = persit.prepare(wasm, '_', {memory: false})
115 + const wasmInstance = await WebAssembly.instantiate(wasm)
116 + const json = persit.hibernate(wasmInstance.instance)
117 + t.equals(json.memory, undefined)
118 + t.equals(Object.keys(wasmInstance.instance.exports).length, 2)
119 +
120 + t.end()
121 +})
122 +
123 +tape('resuming memory', async t => {
124 + let wasm = fs.readFileSync(`${__dirname}/wasm/singleMemory.wasm`)
125 + wasm = persit.prepare(wasm)
126 + const wasmInstance = await WebAssembly.instantiate(wasm)
127 + const json = persit.hibernate(wasmInstance.instance)
128 +
129 + const wasmInstance2 = await WebAssembly.instantiate(wasm)
130 + persit.resume(wasmInstance2.instance, json)
131 + const json2 = persit.hibernate(wasmInstance2.instance)
132 + t.deepEquals(json, json2)
133 + t.equals(Object.keys(wasmInstance.instance.exports).length, 3)
134 +
135 + t.end()
136 +})
137 +
138 +tape('single i32 global', async t => {
139 + let wasm = fs.readFileSync(`${__dirname}/wasm/singleI32Global.wasm`)
140 + wasm = persit.prepare(wasm)
141 + const wasmInstance = await WebAssembly.instantiate(wasm)
142 + const json = persit.hibernate(wasmInstance.instance)
143 + t.deepEquals(json, {globals: [-2], table: [], symbol: '_'})
144 + t.equals(Object.keys(wasmInstance.instance.exports).length, 4)
145 +
146 + t.end()
147 +})
148 +
149 +tape('single i32 global', async t => {
150 + let wasm = fs.readFileSync(`${__dirname}/wasm/singleI32Global.wasm`)
151 + wasm = persit.prepare(wasm)
152 + const wasmInstance = await WebAssembly.instantiate(wasm)
153 + const json = persit.hibernate(wasmInstance.instance)
154 + t.deepEquals(json, {globals: [-2], table: [], symbol: '_'})
155 + t.equals(Object.keys(wasmInstance.instance.exports).length, 4)
156 +
157 + json.globals[0] = 8
158 + const wasmInstance2 = await WebAssembly.instantiate(wasm)
159 + persit.resume(wasmInstance2.instance, json)
160 + const json2 = persit.hibernate(wasmInstance2.instance)
161 + t.deepEquals(json2, {globals: [8], table: [], symbol: '_'})
162 +
163 + t.end()
164 +})
165 +
166 +tape('single i64 global', async t => {
167 + let wasm = fs.readFileSync(`${__dirname}/wasm/singleI64Global.wasm`)
168 + wasm = persit.prepare(wasm)
169 + const wasmInstance = await WebAssembly.instantiate(wasm)
170 + const json = persit.hibernate(wasmInstance.instance)
171 + t.deepEquals(json, {globals: [[-1, -2]], table: [], symbol: '_'})
172 + t.equals(Object.keys(wasmInstance.instance.exports).length, 5)
173 +
174 + t.end()
175 +})
176 +
177 +tape('resuming i64 global', async t => {
178 + let wasm = fs.readFileSync(`${__dirname}/wasm/singleI64Global.wasm`)
179 + wasm = persit.prepare(wasm)
180 + const wasmInstance = await WebAssembly.instantiate(wasm)
181 + const json = {globals: [[99, 97]], table: [], symbol: '_'}
182 + persit.resume(wasmInstance.instance, json)
183 + const json2 = persit.hibernate(wasmInstance.instance)
184 + t.deepEquals(json, json2)
185 + t.equals(Object.keys(wasmInstance.instance.exports).length, 5)
186 +
187 + t.end()
188 +})
189 +
190 +tape('skipping some globals', async t => {
191 + let wasm = fs.readFileSync(`${__dirname}/wasm/doubleGlobals.wasm`)
192 + wasm = persit.prepare(wasm, {
193 + globals: [true]
194 + }, '_@')
195 + const wasmInstance = await WebAssembly.instantiate(wasm)
196 + const json = persit.hibernate(wasmInstance.instance, '_@')
197 + t.deepEquals(json, {globals: [-2], table: [], symbol: '_@'})
198 + t.equals(Object.keys(wasmInstance.instance.exports).length, 4)
199 +
200 + t.end()
201 +})
202 +
203 +tape('skipping some globals', async t => {
204 + let wasm = fs.readFileSync(`${__dirname}/wasm/doubleGlobals.wasm`)
205 + wasm = persit.prepare(wasm, {
206 + globals: [false, true]
207 + }, '_@')
208 + const wasmInstance = await WebAssembly.instantiate(wasm)
209 + const json = persit.hibernate(wasmInstance.instance, '_@')
210 + t.deepEquals(json, {globals: [[-1, -2]], table: [], symbol: '_@'})
211 + t.equals(Object.keys(wasmInstance.instance.exports).length, 5)
212 +
213 + t.end()
214 +})
tests/wasm/customSections.wasmView
@@ -1,0 +1,1 @@
1 +asmname
tests/wasm/doubleGlobals.wasmView
@@ -1,0 +1,2 @@
1 +asm` A~ ~B~ e
2 +
tests/wasm/empty.wasmView
@@ -1,0 +1,1 @@
1 +asm
tests/wasm/singleFunction.wasmView
@@ -1,0 +1,2 @@
1 +asm`e
2 +
tests/wasm/singleGlobal.wasmView
@@ -1,0 +1,2 @@
1 +asm`A~ e
2 +
tests/wasm/singleI32Global.wasmView
@@ -1,0 +1,2 @@
1 +asm`A~ e
2 +
tests/wasm/singleI64Global.wasmView
@@ -1,0 +1,2 @@
1 +asm`~B~ e
2 +
tests/wasm/singleImport.wasmView
@@ -1,0 +1,1 @@
1 +asm`} foobar
tests/wasm/singleMemory.wasmView
@@ -1,0 +1,2 @@
1 +asm`e
2 + A hi
tests/wasm/singleTable.wasmView
@@ -1,0 +1,2 @@
1 +asm`pe A 
2 +
tests/wasm/singleType.wasmView
@@ -1,0 +1,1 @@
1 +asm`
tests/wast/doubleGlobals.wastView
@@ -1,0 +1,6 @@
1 +(module
2 + (global (mut i32) (i32.const -2))
3 + (global (mut i64) (i64.const -2))
4 + (func)
5 + (export "e" (func 0))
6 +)
tests/wast/empty.wastView
@@ -1,0 +1,1 @@
1 +(module)
tests/wast/singleFunction.wastView
@@ -1,0 +1,4 @@
1 +(module
2 + (func)
3 + (export "e" (func 0))
4 +)
tests/wast/singleI32Global.wastView
@@ -1,0 +1,5 @@
1 +(module
2 + (global $a (mut i32) (i32.const -2))
3 + (func)
4 + (export "e" (func 0))
5 +)
tests/wast/singleI64Global.wastView
@@ -1,0 +1,5 @@
1 +(module
2 + (global $a (mut i64) (i64.const -2))
3 + (func)
4 + (export "e" (func 0))
5 +)
tests/wast/singleImport.wastView
@@ -1,0 +1,3 @@
1 +(module
2 + (import "foo" "bar" (func (param f32)))
3 + )
tests/wast/singleMemory.wastView
@@ -1,0 +1,5 @@
1 +(module
2 + (memory (data "hi"))
3 + (func)
4 + (export "e" (func 0))
5 +)
tests/wast/singleTable.wastView
@@ -1,0 +1,6 @@
1 +(module
2 + (table 1 1 anyfunc)
3 + (elem (i32.const 0) 0)
4 + (func)
5 + (export "e" (func 0))
6 +)
tests/wast/singleType.wastView
@@ -1,0 +1,3 @@
1 +(module
2 + (type (func (param i32) (result i32)))
3 + )
tests/wast2wasm.jsView
@@ -1,0 +1,26 @@
1 +const wabt = require('wabt')
2 +const fs = require('fs')
3 +
4 +function filesWast2wasm () {
5 + const srcFiles = fs.readdirSync(`${__dirname}/wast`)
6 + const wastFiles = srcFiles.filter(name => name.split('.').pop() === 'wast')
7 + for (let file of wastFiles) {
8 + const wat = fs.readFileSync(`${__dirname}/wast/${file}`).toString()
9 + file = file.split('.')[0]
10 +
11 + try {
12 + const mod = wabt.parseWat('module.wast', wat)
13 + const r = mod.toBinary({log: true})
14 + let binary = Buffer.from(r.buffer)
15 + if (!WebAssembly.validate(binary)) {
16 + throw new Error('invalid wasm binary')
17 + }
18 + fs.writeFileSync(`${__dirname}/wasm/${file}.wasm`, binary)
19 + } catch (e) {
20 + console.log(`failed at ${file}`)
21 + console.log(e)
22 + }
23 + }
24 +}
25 +
26 +filesWast2wasm()

Built with git-ssb-web