git ssb

0+

wanderer🌟 / js-primea-hypervisor



Commit 0de9abab60ad6c7b9852a3219889dc1a080484d5

Merge branch 'master' into greenkeeper/documentation-6.0.0

wanderer authored on 3/21/2018, 6:26:19 PM
GitHub committed on 3/21/2018, 6:26:19 PM
Parent: cffaab0554c3a8228f13ad2e78df2cc6aab77296
Parent: 8aa474dcde21c44a2049cae1deeb33baa977dad8

Files changed

.gitignorechanged
actor.jschanged
customTypes.jschanged
docs/actor.mdchanged
docs/hypervisor.mdchanged
docs/index.mdchanged
docs/scheduler.mdchanged
index.jschanged
message.jschanged
package-lock.jsonchanged
package.jsonchanged
scheduler.jschanged
tests/index.jschanged
tests/wasm/caller.wasmchanged
tests/wasm/funcRef_caller.wasmchanged
tests/wasm/funcRef_reciever.wasmchanged
tests/wasm/empty.wasmadded
tests/wasm/globals.wasmadded
tests/wasm/memory.wasmadded
tests/wasm/private_caller.wasmadded
tests/wasm/table.wasmadded
tests/wasmContainer.jschanged
tests/wast/caller.jsonchanged
tests/wast/funcRef_caller.jsonchanged
tests/wast/funcRef_caller.wastchanged
tests/wast/funcRef_reciever.jsonchanged
tests/wast/funcRef_reciever.wastchanged
tests/wast/globals.jsonadded
tests/wast/globals.wastadded
tests/wast/memory.wastadded
tests/wast/private_caller.jsonadded
tests/wast/private_caller.wasmadded
tests/wast/private_caller.wastadded
tests/wast/table.wastadded
tests/wast2wasm.jschanged
typeCheckWrapper.jschanged
wasmContainer.jschanged
injectGlobals.jsadded
systemObjects.jsadded
.gitignoreView
@@ -1,2 +1,3 @@
11 node_modules/
2-testdb/
2+testdb/
3+*.sublime-*
actor.jsView
@@ -1,7 +1,4 @@
1-const Pipe = require('buffer-pipe')
2-const leb128 = require('leb128').unsigned
3-
41 module.exports = class Actor {
52 /**
63 * the Actor manages the varous message passing functions and provides
74 * an interface for the containers to use
@@ -19,25 +16,15 @@
1916 this.running = false
2017 this.container = new this.Container(this)
2118 }
2219
23- serializeMetaData () {
24- return Actor.serializeMetaData(this.type, this.nonce)
25- }
26-
27- getFuncRef (name) {
28- return {
29- name,
30- destId: this.id
31- }
32- }
33-
3420 /**
3521 * Runs the shutdown routine for the actor
3622 */
3723 async shutdown () {
38- await this.state.done()
39- this.state.root['/'][3] = this.serializeMetaData()
24+ await this.tree.set(this.id.id, [this.type, this.nonce])
25+ const state = await this.tree.get(this.id.id)
26+ return this.tree.graph.set(state.root, '2', this.storage)
4027 }
4128
4229 /**
4330 * Runs the startup routine for the actor
@@ -61,9 +48,9 @@
6148 await this.container.onMessage(message)
6249 } catch (e) {
6350 message.emit('execution:error', e)
6451 }
65- message.emit('done')
52+ message.emit('done', this)
6653 }
6754
6855 /**
6956 * updates the number of ticks that the actor has run
@@ -103,22 +90,5 @@
10390 message._fromId = this.id
10491
10592 this.hypervisor.scheduler.queue([message])
10693 }
107-
108- static serializeMetaData (type, nonce = 0) {
109- const p = new Pipe()
110- leb128.write(type, p)
111- leb128.write(nonce, p)
112- return p.buffer
113- }
114-
115- static deserializeMetaData (buffer) {
116- const pipe = new Pipe(buffer)
117- const type = leb128.read(pipe)
118- const nonce = leb128.read(pipe)
119- return {
120- nonce,
121- type
122- }
123- }
12494 }
customTypes.jsView
@@ -4,8 +4,11 @@
44
55 const LANGUAGE_TYPES = {
66 'actor': 0x0,
77 'buf': 0x1,
8+ 'elem': 0x2,
9+ 'link': 0x3,
10+ 'id': 0x4,
811 'i32': 0x7f,
912 'i64': 0x7e,
1013 'f32': 0x7d,
1114 'f64': 0x7c,
@@ -14,8 +17,11 @@
1417 'block_type': 0x40,
1518
1619 0x0: 'actor',
1720 0x1: 'buf',
21+ 0x02: 'elem',
22+ 0x03: 'link',
23+ 0x04: 'id',
1824 0x7f: 'i32',
1925 0x7e: 'i64',
2026 0x7d: 'f32',
2127 0x7c: 'f64',
@@ -25,28 +31,54 @@
2531 }
2632
2733 function encodeJSON (json) {
2834 const stream = new Stream()
29- encodeCustomSection('type', json, stream, encodeType)
35+ encodeCustomSection('types', json, stream, encodeType)
3036 encodeCustomSection('typeMap', json, stream, encodeTypeMap)
37+ encodeCustomSection('globals', json, stream, encodeGlobals)
3138
3239 return stream.buffer
3340 }
3441
3542 function encodeCustomSection (name, json, stream, encodingFunc) {
36- stream.write([0])
3743 let payload = new Stream()
44+ json = json[name]
3845
39- // encode type
40- leb.unsigned.write(name.length, payload)
41- payload.write(name)
42- encodingFunc(json[name], payload)
43- // write the size of the payload
44- leb.unsigned.write(payload.bytesWrote, stream)
45- stream.write(payload.buffer)
46+ if (json) {
47+ stream.write([0])
48+ // encode type
49+ leb.unsigned.write(name.length, payload)
50+ payload.write(name)
51+ encodingFunc(json, payload)
52+ // write the size of the payload
53+ leb.unsigned.write(payload.bytesWrote, stream)
54+ stream.write(payload.buffer)
55+ }
4656 return stream
4757 }
4858
59+function encodeGlobals (json, stream) {
60+ leb.unsigned.write(json.length, stream)
61+ for (const entry of json) {
62+ leb.unsigned.write(entry.index, stream)
63+ leb.unsigned.write(LANGUAGE_TYPES[entry.type], stream)
64+ }
65+ return stream
66+}
67+
68+function decodeGlobals (buf) {
69+ const stream = new Stream(Buffer.from(buf))
70+ let numOfEntries = leb.unsigned.read(stream)
71+ const json = []
72+ while (numOfEntries--) {
73+ json.push({
74+ index: leb.unsigned.readBn(stream).toNumber(),
75+ type: LANGUAGE_TYPES[leb.unsigned.readBn(stream).toNumber()]
76+ })
77+ }
78+ return json
79+}
80+
4981 function encodeTypeMap (json, stream) {
5082 leb.unsigned.write(json.length, stream)
5183 for (let entry of json) {
5284 leb.unsigned.write(entry.func, stream)
@@ -82,9 +114,8 @@
82114 binEntries.write(entry.params.map(type => LANGUAGE_TYPES[type])) // the paramter types
83115 }
84116
85117 binEntries.write([entry.return_type ? 1 : 0]) // number of return types
86-
87118 if (entry.return_type) {
88119 binEntries.write([LANGUAGE_TYPES[entry.return_type]])
89120 }
90121 }
@@ -136,28 +167,34 @@
136167 function mergeTypeSections (json) {
137168 const result = {
138169 types: [],
139170 indexes: {},
140- exports: {}
171+ exports: {},
172+ globals: []
141173 }
142174
143- const wantedSections = ['custom', 'custom', 'type', 'import', 'function', 'export']
175+ const wantedSections = ['types', 'typeMap', 'globals', 'type', 'import', 'function', 'export']
144176 const iterator = findSections(json, wantedSections)
145177 const mappedFuncs = new Map()
146178 const mappedTypes = new Map()
147- const {value: customType} = iterator.next('custom')
179+ const {value: customType} = iterator.next()
148180 if (customType) {
149181 const type = decodeType(customType.payload)
150182 result.types = type
151183 }
152- let {value: typeMap} = iterator.next('custom')
184+ let {value: typeMap} = iterator.next()
153185 if (typeMap) {
154186 decodeTypeMap(typeMap.payload).forEach(map => mappedFuncs.set(map.func, map.type))
155187 }
156188
157- const {value: type} = iterator.next('type')
158- const {value: imports = {entries: []}} = iterator.next('import')
159- const {value: functions} = iterator.next('function')
189+ let {value: globals} = iterator.next()
190+ if (globals) {
191+ result.globals = decodeGlobals(globals.payload)
192+ }
193+
194+ const {value: type} = iterator.next()
195+ const {value: imports = {entries: []}} = iterator.next()
196+ const {value: functions = {entries: []}} = iterator.next()
160197 functions.entries.forEach((typeIndex, funcIndex) => {
161198 let customIndex = mappedFuncs.get(funcIndex)
162199 if (customIndex === undefined) {
163200 customIndex = mappedTypes.get(typeIndex)
@@ -168,9 +205,9 @@
168205 }
169206 result.indexes[funcIndex + imports.entries.length] = customIndex
170207 })
171208
172- const {value: exports = {entries: []}} = iterator.next('export')
209+ const {value: exports = {entries: []}} = iterator.next()
173210 exports.entries.forEach(entry => {
174211 if (entry.kind === 'function') {
175212 result.exports[entry.field_str] = entry.index
176213 }
@@ -182,8 +219,9 @@
182219 injectCustomSection,
183220 inject,
184221 decodeType,
185222 decodeTypeMap,
223+ decodeGlobals,
186224 encodeType,
187225 encodeTypeMap,
188226 encodeJSON,
189227 mergeTypeSections
docs/actor.mdView
@@ -2,9 +2,8 @@
22
33 ### Table of Contents
44
55 - [constructor](#constructor)
6-- [queue](#queue)
76 - [shutdown](#shutdown)
87 - [startup](#startup)
98 - [runMessage](#runmessage)
109 - [incrementTicks](#incrementticks)
@@ -12,9 +11,9 @@
1211 - [send](#send)
1312
1413 ## constructor
1514
16-[actor.js:15-25](https://github.com/dfinity/js-primea/blob/3d3fc0d82dd65f14b8533dcd2fb881c9fbbb1bd3/actor.js#L15-L25 "Source code on GitHub")
15+[actor.js:11-18](https://github.com/dfinity/js-primea/blob/21960d62467278cd5659e2eb5f80cc6ddd87e663/actor.js#L11-L18 "Source code on GitHub")
1716
1817 the Actor manages the varous message passing functions and provides
1918 an interface for the containers to use
2019
@@ -25,34 +24,23 @@
2524 - `opts.state` **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)** the state of the container
2625 - `opts.hypervisor` **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)** the instance of the hypervisor
2726 - `opts.container` **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)** the container constuctor and argments
2827
29-## queue
30-
31-[actor.js:32-39](https://github.com/dfinity/js-primea/blob/3d3fc0d82dd65f14b8533dcd2fb881c9fbbb1bd3/actor.js#L32-L39 "Source code on GitHub")
32-
33-adds a message to this actor's message queue
34-
35-**Parameters**
36-
37-- `message` **[object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)**
38-- `portName` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)**
39-
4028 ## shutdown
4129
42-[actor.js:89-92](https://github.com/dfinity/js-primea/blob/3d3fc0d82dd65f14b8533dcd2fb881c9fbbb1bd3/actor.js#L89-L92 "Source code on GitHub")
30+[actor.js:23-29](https://github.com/dfinity/js-primea/blob/21960d62467278cd5659e2eb5f80cc6ddd87e663/actor.js#L23-L29 "Source code on GitHub")
4331
4432 Runs the shutdown routine for the actor
4533
4634 ## startup
4735
48-[actor.js:97-99](https://github.com/dfinity/js-primea/blob/3d3fc0d82dd65f14b8533dcd2fb881c9fbbb1bd3/actor.js#L97-L99 "Source code on GitHub")
36+[actor.js:34-36](https://github.com/dfinity/js-primea/blob/21960d62467278cd5659e2eb5f80cc6ddd87e663/actor.js#L34-L36 "Source code on GitHub")
4937
5038 Runs the startup routine for the actor
5139
5240 ## runMessage
5341
54-[actor.js:107-114](https://github.com/dfinity/js-primea/blob/3d3fc0d82dd65f14b8533dcd2fb881c9fbbb1bd3/actor.js#L107-L114 "Source code on GitHub")
42+[actor.js:44-56](https://github.com/dfinity/js-primea/blob/21960d62467278cd5659e2eb5f80cc6ddd87e663/actor.js#L44-L56 "Source code on GitHub")
5543
5644 run the Actor with a given message
5745
5846 **Parameters**
@@ -63,9 +51,9 @@
6351 Returns **[Promise](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)**
6452
6553 ## incrementTicks
6654
67-[actor.js:120-123](https://github.com/dfinity/js-primea/blob/3d3fc0d82dd65f14b8533dcd2fb881c9fbbb1bd3/actor.js#L120-L123 "Source code on GitHub")
55+[actor.js:62-64](https://github.com/dfinity/js-primea/blob/21960d62467278cd5659e2eb5f80cc6ddd87e663/actor.js#L62-L64 "Source code on GitHub")
6856
6957 updates the number of ticks that the actor has run
7058
7159 **Parameters**
@@ -73,9 +61,9 @@
7361 - `count` **[Number](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number)** the number of ticks to add
7462
7563 ## createActor
7664
77-[actor.js:130-133](https://github.com/dfinity/js-primea/blob/3d3fc0d82dd65f14b8533dcd2fb881c9fbbb1bd3/actor.js#L130-L133 "Source code on GitHub")
65+[actor.js:71-74](https://github.com/dfinity/js-primea/blob/21960d62467278cd5659e2eb5f80cc6ddd87e663/actor.js#L71-L74 "Source code on GitHub")
7866
7967 creates an actor
8068
8169 **Parameters**
@@ -85,9 +73,9 @@
8573 - `message` **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)** an intial [message](https://github.com/primea/js-primea-message) to send newly created actor
8674
8775 ## send
8876
89-[actor.js:150-155](https://github.com/dfinity/js-primea/blob/3d3fc0d82dd65f14b8533dcd2fb881c9fbbb1bd3/actor.js#L150-L155 "Source code on GitHub")
77+[actor.js:91-96](https://github.com/dfinity/js-primea/blob/21960d62467278cd5659e2eb5f80cc6ddd87e663/actor.js#L91-L96 "Source code on GitHub")
9078
9179 sends a message to a given port
9280
9381 **Parameters**
docs/hypervisor.mdView
@@ -3,16 +3,15 @@
33 ### Table of Contents
44
55 - [constructor](#constructor)
66 - [send](#send)
7-- [getActor](#getactor)
87 - [createActor](#createactor)
98 - [createStateRoot](#createstateroot)
109 - [registerContainer](#registercontainer)
1110
1211 ## constructor
1312
14-[index.js:10-15](https://github.com/dfinity/js-primea/blob/3d3fc0d82dd65f14b8533dcd2fb881c9fbbb1bd3/index.js#L10-L15 "Source code on GitHub")
13+[index.js:12-17](https://github.com/dfinity/js-primea/blob/21960d62467278cd5659e2eb5f80cc6ddd87e663/index.js#L12-L17 "Source code on GitHub")
1514
1615 The Hypervisor manages the container instances by instantiating them and
1716 destorying them when possible. It also facilitates localating Containers
1817
@@ -22,34 +21,23 @@
2221 - `nonce` (optional, default `0`)
2322
2423 ## send
2524
26-[index.js:23-27](https://github.com/dfinity/js-primea/blob/3d3fc0d82dd65f14b8533dcd2fb881c9fbbb1bd3/index.js#L23-L27 "Source code on GitHub")
25+[index.js:25-30](https://github.com/dfinity/js-primea/blob/21960d62467278cd5659e2eb5f80cc6ddd87e663/index.js#L25-L30 "Source code on GitHub")
2726
2827 sends a message
2928
3029 **Parameters**
3130
31+- `messages`
32+- `cap` **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)** the capabilitly used to send the message
3233 - `message` **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)** the [message](https://github.com/primea/js-primea-message) to send
33-- `cap` **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)** the capabilitly used to send the message
3434
3535 Returns **[Promise](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)** a promise that resolves once the receiving container is loaded
3636
37-## getActor
38-
39-[index.js:55-63](https://github.com/dfinity/js-primea/blob/3d3fc0d82dd65f14b8533dcd2fb881c9fbbb1bd3/index.js#L55-L63 "Source code on GitHub")
40-
41-gets an existsing actor
42-
43-**Parameters**
44-
45-- `id` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** the actor's ID
46-
47-Returns **[Promise](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)**
48-
4937 ## createActor
5038
51-[index.js:71-85](https://github.com/dfinity/js-primea/blob/3d3fc0d82dd65f14b8533dcd2fb881c9fbbb1bd3/index.js#L71-L85 "Source code on GitHub")
39+[index.js:65-83](https://github.com/dfinity/js-primea/blob/21960d62467278cd5659e2eb5f80cc6ddd87e663/index.js#L65-L83 "Source code on GitHub")
5240
5341 creates an instance of an Actor
5442
5543 **Parameters**
@@ -60,22 +48,22 @@
6048 - `message` **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)** an intial [message](https://github.com/primea/js-primea-message) to send newly created actor
6149
6250 ## createStateRoot
6351
64-[index.js:98-101](https://github.com/dfinity/js-primea/blob/3d3fc0d82dd65f14b8533dcd2fb881c9fbbb1bd3/index.js#L98-L101 "Source code on GitHub")
52+[index.js:98-104](https://github.com/dfinity/js-primea/blob/21960d62467278cd5659e2eb5f80cc6ddd87e663/index.js#L98-L104 "Source code on GitHub")
6553
6654 creates a state root starting from a given container and a given number of
6755 ticks
6856
6957 **Parameters**
7058
71-- `ticks` **[Number](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number)** the number of ticks at which to create the state root (optional, default `Infinity`)
59+- `ticks` **[Number](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number)** the number of ticks at which to create the state root
7260
7361 Returns **[Promise](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)**
7462
7563 ## registerContainer
7664
77-[index.js:109-111](https://github.com/dfinity/js-primea/blob/3d3fc0d82dd65f14b8533dcd2fb881c9fbbb1bd3/index.js#L109-L111 "Source code on GitHub")
65+[index.js:112-114](https://github.com/dfinity/js-primea/blob/21960d62467278cd5659e2eb5f80cc6ddd87e663/index.js#L112-L114 "Source code on GitHub")
7866
7967 regirsters a container with the hypervisor
8068
8169 **Parameters**
docs/index.mdView
@@ -1,7 +1,6 @@
11 # API
22 - [Hypervisor](./hypervisor.md)
3-- [Kernel](./kernel.md)
4-- [PortManager](./portManager.md)
3+- [Actor](./actor.md)
54
6-## internal API's
5+## Internal APIs
76 - [Scheduler](./scheduler.md)
docs/scheduler.mdView
@@ -2,87 +2,15 @@
22
33 ### Table of Contents
44
55 - [constructor](#constructor)
6-- [lock](#lock)
7-- [update](#update)
8-- [getInstance](#getinstance)
9-- [done](#done)
10-- [wait](#wait)
11-- [leastNumberOfTicks](#leastnumberofticks)
126
137 ## constructor
148
15-[scheduler.js:13-17](https://github.com/dfinity/js-primea/blob/3d3fc0d82dd65f14b8533dcd2fb881c9fbbb1bd3/scheduler.js#L13-L17 "Source code on GitHub")
9+[scheduler.js:19-26](https://github.com/dfinity/js-primea/blob/21960d62467278cd5659e2eb5f80cc6ddd87e663/scheduler.js#L19-L26 "Source code on GitHub")
1610
1711 The Scheduler manages the actor instances and tracks how many "ticks" they
1812 have ran.
1913
20-## lock
21-
22-[scheduler.js:24-34](https://github.com/dfinity/js-primea/blob/3d3fc0d82dd65f14b8533dcd2fb881c9fbbb1bd3/scheduler.js#L24-L34 "Source code on GitHub")
23-
24-locks the scheduler from clearing waits untill the lock is resolved
25-
2614 **Parameters**
2715
28-- `id` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)**
29-
30-Returns **[function](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/function)** the resolve function to call once it to unlock
31-
32-## update
33-
34-[scheduler.js:40-44](https://github.com/dfinity/js-primea/blob/3d3fc0d82dd65f14b8533dcd2fb881c9fbbb1bd3/scheduler.js#L40-L44 "Source code on GitHub")
35-
36-updates an instance with a new tick count
37-
38-**Parameters**
39-
40-- `instance` **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)** an actor instance
41-
42-## getInstance
43-
44-[scheduler.js:56-59](https://github.com/dfinity/js-primea/blob/3d3fc0d82dd65f14b8533dcd2fb881c9fbbb1bd3/scheduler.js#L56-L59 "Source code on GitHub")
45-
46-returns an Actor instance
47-
48-**Parameters**
49-
50-- `id` **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)**
51-
52-Returns **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)**
53-
54-## done
55-
56-[scheduler.js:65-70](https://github.com/dfinity/js-primea/blob/3d3fc0d82dd65f14b8533dcd2fb881c9fbbb1bd3/scheduler.js#L65-L70 "Source code on GitHub")
57-
58-deletes an instance from the scheduler
59-
60-**Parameters**
61-
62-- `id` **[String](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** the containers id
63-
64-## wait
65-
66-[scheduler.js:79-93](https://github.com/dfinity/js-primea/blob/3d3fc0d82dd65f14b8533dcd2fb881c9fbbb1bd3/scheduler.js#L79-L93 "Source code on GitHub")
67-
68-returns a promise that resolves once all containers have reached the given
69-number of ticks
70-
71-**Parameters**
72-
73-- `ticks` **interger** the number of ticks to wait
74-- `id` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** optional id of the container that is waiting
75-
76-Returns **[Promise](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)**
77-
78-## leastNumberOfTicks
79-
80-[scheduler.js:99-109](https://github.com/dfinity/js-primea/blob/3d3fc0d82dd65f14b8533dcd2fb881c9fbbb1bd3/scheduler.js#L99-L109 "Source code on GitHub")
81-
82-returns the oldest container's ticks
83-
84-**Parameters**
85-
86-- `exclude`
87-
88-Returns **integer**
16+- `hypervisor`
index.jsView
@@ -1,6 +1,8 @@
11 const Actor = require('./actor.js')
22 const Scheduler = require('./scheduler.js')
3+const {ID} = require('./systemObjects.js')
4+const crypto = require('crypto')
35
46 module.exports = class Hypervisor {
57 /**
68 * The Hypervisor manages the container instances by instantiating them and
@@ -27,11 +29,14 @@
2729 this.scheduler.queue(messages)
2830 }
2931
3032 async loadActor (id) {
31- const state = await this.tree.getSubTree(id)
32- const code = state.get(Buffer.from([0]))
33- const {type, nonce} = Actor.deserializeMetaData(state.root['/'][3])
33+ const state = await this.tree.get(id.id, true)
34+ const [code, storage] = await Promise.all([
35+ this.tree.graph.get(state.node, '1'),
36+ this.tree.graph.get(state.node, '2')
37+ ])
38+ const [type, nonce] = state.value
3439 const Container = this._containerTypes[type]
3540
3641 // create a new actor instance
3742 const actor = new Actor({
@@ -41,9 +46,10 @@
4146 id,
4247 nonce,
4348 type,
4449 code,
45- cachedb: this.tree.dag._dag
50+ storage: storage || [],
51+ tree: this.tree
4652 })
4753
4854 await actor.startup()
4955 return actor
@@ -57,26 +63,34 @@
5763 */
5864 async createActor (type, code, id = {nonce: this.nonce++, parent: null}) {
5965 const Container = this._containerTypes[type]
6066 const encoded = encodedID(id)
61- const idHash = await this._getHashFromObj(encoded)
62- const module = await Container.onCreation(code, idHash, this.tree.dag._dag)
63- const metaData = Actor.serializeMetaData(type)
67+ let idHash = this._hash(encoded)
68+ idHash = new ID(idHash)
69+ const module = await Container.onCreation(code, idHash, this.tree)
70+ const metaData = [type, 0]
6471
6572 // save the container in the state
66- this.tree.set(idHash, metaData)
67- if (code) {
68- this.tree.set(Buffer.concat([idHash, Buffer.from([0])]), code)
73+ const node = await this.tree.set(idHash.id, metaData)
74+ // save the code
75+ node[1] = {
76+ '/': code
6977 }
78+ // save the storage
79+ node[2] = {
80+ '/': []
81+ }
82+
7083 return {
7184 id: idHash,
72- module: module
85+ module
7386 }
7487 }
7588
76- // get a hash from a POJO
77- _getHashFromObj (obj) {
78- return this.tree.constructor.getMerkleLink(obj)
89+ _hash (buf) {
90+ const hash = crypto.createHash('sha256')
91+ hash.update(buf)
92+ return hash.digest().slice(0, 20)
7993 }
8094
8195 /**
8296 * creates a state root starting from a given container and a given number of
@@ -85,11 +99,15 @@
8599 * @returns {Promise}
86100 */
87101 createStateRoot () {
88102 return new Promise((resolve, reject) => {
89- this.scheduler.on('idle', () => {
103+ if (!this.scheduler._running) {
90104 this.tree.flush().then(resolve)
91- })
105+ } else {
106+ this.scheduler.on('idle', () => {
107+ this.tree.flush().then(resolve)
108+ })
109+ }
92110 })
93111 }
94112
95113 /**
@@ -105,9 +123,9 @@
105123
106124 function encodedID (id) {
107125 const nonce = Buffer.from([id.nonce])
108126 if (id.parent) {
109- return Buffer.concat([nonce, id.parent])
127+ return Buffer.concat([nonce, id.parent.id])
110128 } else {
111129 return nonce
112130 }
113131 }
message.jsView
@@ -1,5 +1,6 @@
11 const EventEmitter = require('events')
2+const {ID} = require('./systemObjects.js')
23
34 /**
45 * This implements Messages for Primea
56 * @module primea-message
@@ -31,9 +32,9 @@
3132 ticks: 0,
3233 funcRef: null,
3334 funcArguments: [],
3435 funcParameters: [],
35- _fromId: Buffer.alloc(20),
36+ _fromId: new ID(Buffer.alloc(20)),
3637 _fromTicks: 0
3738 }
3839 }
3940 }
package-lock.jsonView
The diff is too large to show. Use a local git client to view these changes.
Old file size: 344343 bytes
New file size: 337905 bytes
package.jsonView
@@ -5,13 +5,14 @@
55 "scripts": {
66 "coveralls": "npm run coverage && nyc report --reporter=text-lcov | coveralls",
77 "coverage": "nyc npm test",
88 "lint": "standard",
9- "build:docs": "npm run build:docs:hypervisor && npm run build:docs:actor && npm run build:docs:scheduler && npm run build:docs:capsStore && npm run build:docs:inbox",
9+ "build:docs": "npm run build:docs:hypervisor && npm run build:docs:actor && npm run build:docs:scheduler",
1010 "build:docs:hypervisor": "documentation build ./index.js --github --shallow --sort-order source -f md > ./docs/hypervisor.md",
1111 "build:docs:actor": "documentation build ./actor.js --github --shallow --sort-order source -f md > ./docs/actor.md",
12- "build:docs:capsStore": "documentation build ./capsStore.js --github --shallow --sort-order source -f md > ./docs/capsStore.md",
13- "test": "node ./tests/index.js"
12+ "build:docs:scheduler": "documentation build ./scheduler.js --github --shallow --sort-order source -f md > ./docs/scheduler.md",
13+ "test": "node ./tests/index.js",
14+ "test:wasm": "node ./tests/wasmContainer.js"
1415 },
1516 "repository": {
1617 "type": "git",
1718 "url": "git+https://github.com/primea/js-primea-hypervisor.git"
@@ -28,27 +29,24 @@
2829 "author": "mjbecze <mjbecze@gmail.com>",
2930 "contributors": "Alex Beregszaszi <alex@rtfs.hu>",
3031 "license": "MPL-2.0",
3132 "dependencies": {
32- "binary-search": "^1.3.3",
3333 "binary-search-insert": "^1.0.3",
34- "buffer-pipe": "0.0.2",
34+ "borc": "^2.0.2",
3535 "events": "^2.0.0",
36- "leb128": "0.0.4",
37- "levelup": "^2.0.1",
38- "reference-map": "^1.2.1",
36+ "reference-map": "^1.2.3",
3937 "safe-buffer": "^5.1.1",
40- "wasm-json-toolkit": "^0.2.1",
38+ "wasm-json-toolkit": "^0.2.2",
4139 "wasm-metering": "^0.1.1"
4240 },
4341 "devDependencies": {
42+ "levelup": "^2.0.2",
4443 "coveralls": "^3.0.0",
45- "dfinity-radix-tree": "0.0.9",
44+ "dfinity-radix-tree": "0.1.1",
4645 "documentation": "^6.0.0",
4746 "level-browserify": "^1.1.1",
4847 "nyc": "^11.4.1",
49- "primea-abstract-container": "0.0.6",
50- "standard": "10.0.3",
51- "tape": "^4.6.3",
48+ "standard": "11.0.0",
49+ "tape": "^4.9.0",
5250 "wabt": "^1.0.0"
5351 }
5452 }
scheduler.jsView
@@ -6,9 +6,9 @@
66 // order by number of ticks if messages have different number of ticks
77 if (messageA._fromTicks !== messageB._fromTicks) {
88 return messageA._fromTicks > messageB._fromTicks
99 } else {
10- return Buffer.compare(messageA._fromId, messageB._fromId)
10+ return Buffer.compare(messageA._fromId.id, messageB._fromId.id)
1111 }
1212 }
1313
1414 module.exports = class Scheduler extends EventEmitter {
@@ -46,9 +46,9 @@
4646 this.emit('idle')
4747 }
4848
4949 async _processMessage (message) {
50- const to = message.funcRef.destId.toString('hex')
50+ const to = message.funcRef.destId.id.toString('hex')
5151 let actor = this.actors.get(to)
5252 if (!actor) {
5353 actor = await this.hypervisor.loadActor(message.funcRef.destId)
5454 this.actors.set(to, actor)
tests/index.jsView
@@ -31,9 +31,9 @@
3131
3232 tape('basic', async t => {
3333 t.plan(2)
3434 const expectedState = {
35- '/': Buffer.from('926de6b7eb39cfa8d7f8a44d1ef191d3bcb765a7', 'hex')
35+ '/': Buffer.from('cd80335de00c2bf38570b41c55a79174c1c64e9f', 'hex')
3636 }
3737
3838 const tree = new RadixTree({
3939 db: db
@@ -62,9 +62,9 @@
6262
6363 tape('two communicating actors', async t => {
6464 t.plan(2)
6565 const expectedState = {
66- '/': Buffer.from('a4c7ceacd8c867ae1d0b472d8bffa3cb10048331', 'hex')
66+ '/': Buffer.from('b063f3e53b2ea40f50afe964b9f9b49aad491155', 'hex')
6767 }
6868
6969 const tree = new RadixTree({
7070 db: db
@@ -110,9 +110,9 @@
110110
111111 tape('three communicating actors', async t => {
112112 t.plan(3)
113113 const expectedState = {
114- '/': Buffer.from('4633ac4b9f8212e501b6c56906039ec081fbe5a3', 'hex')
114+ '/': Buffer.from('db532195ac569b142415cc9bdbec37f18f344a59', 'hex')
115115 }
116116
117117 const tree = new RadixTree({
118118 db: db
@@ -165,9 +165,9 @@
165165
166166 tape('three communicating actors, with tick counting', async t => {
167167 t.plan(3)
168168 const expectedState = {
169- '/': Buffer.from('4633ac4b9f8212e501b6c56906039ec081fbe5a3', 'hex')
169+ '/': Buffer.from('db532195ac569b142415cc9bdbec37f18f344a59', 'hex')
170170 }
171171
172172 const tree = new RadixTree({
173173 db: db
@@ -220,9 +220,9 @@
220220
221221 tape('errors', async t => {
222222 t.plan(3)
223223 const expectedState = {
224- '/': Buffer.from('a4c7ceacd8c867ae1d0b472d8bffa3cb10048331', 'hex')
224+ '/': Buffer.from('b063f3e53b2ea40f50afe964b9f9b49aad491155', 'hex')
225225 }
226226
227227 const tree = new RadixTree({
228228 db: db
@@ -268,9 +268,9 @@
268268
269269 tape('actor creation', async t => {
270270 t.plan(2)
271271 const expectedState = {
272- '/': Buffer.from('f47377a763c91247e62138408d706a09bccaaf36', 'hex')
272+ '/': Buffer.from('8a21d80cd7ca04e64be7cb2726a72060fc546ed6', 'hex')
273273 }
274274
275275 const tree = new RadixTree({
276276 db: db
@@ -280,9 +280,12 @@
280280 async start (funcRef) {
281281 const {module} = await this.actor.createActor(testVMContainerB.typeId)
282282 const message = new Message({
283283 funcRef: module.main,
284- funcArguments: [this.actor.getFuncRef('main')]
284+ funcArguments: [{
285+ name: 'main',
286+ destId: this.actor.id
287+ }]
285288 })
286289 this.actor.send(message)
287290 }
288291 main (data) {
@@ -308,14 +311,15 @@
308311 await hypervisor.send(new Message({funcRef: module.start}))
309312
310313 const stateRoot = await hypervisor.createStateRoot()
311314 t.deepEquals(stateRoot, expectedState, 'expected root!')
315+ t.end()
312316 })
313317
314318 tape('simple message arbiter test', async t => {
315319 t.plan(4)
316320 const expectedState = {
317- '/': Buffer.from('a4c7ceacd8c867ae1d0b472d8bffa3cb10048331', 'hex')
321+ '/': Buffer.from('b063f3e53b2ea40f50afe964b9f9b49aad491155', 'hex')
318322 }
319323
320324 const tree = new RadixTree({
321325 db: db
@@ -382,9 +386,9 @@
382386 tape('arbiter test for id comparision', async t => {
383387 t.plan(4)
384388 let message
385389 const expectedState = {
386- '/': Buffer.from('4633ac4b9f8212e501b6c56906039ec081fbe5a3', 'hex')
390+ '/': Buffer.from('db532195ac569b142415cc9bdbec37f18f344a59', 'hex')
387391 }
388392
389393 const tree = new RadixTree({
390394 db: db
@@ -449,9 +453,9 @@
449453
450454 tape('async work', async t => {
451455 t.plan(3)
452456 const expectedState = {
453- '/': Buffer.from('a4c7ceacd8c867ae1d0b472d8bffa3cb10048331', 'hex')
457+ '/': Buffer.from('b063f3e53b2ea40f50afe964b9f9b49aad491155', 'hex')
454458 }
455459
456460 const tree = new RadixTree({
457461 db: db
tests/wasm/caller.wasmView
@@ -1,4 +1,3 @@
1-asm
2-type`` typeMap
1+asm types`` typeMap
32 ``func internalizeptablecall
43 A AA
tests/wasm/funcRef_caller.wasmView
@@ -1,3 +1,2 @@
1-asm
2-type`` typeMap````@func internalizetestcheckmoduleselfmoduleexportsp$memorytablecallcallback
3- AAA A  A A callback
1+asm types`` typeMap````Tfunc internalizetestcheckmoduleselfmoduleexportmemory externalizep$memorytablecallcallback
2+"AAA A  A A callback
tests/wasm/funcRef_reciever.wasmView
@@ -1,4 +1,3 @@
1-asm
2-type`` typeMap
3-``func internalizeptablereceive
4- AAA
1+asm types`` typeMap
2+``*func internalizefuncset_gas_budgetptablereceive
3+ A�� AAA
tests/wasm/empty.wasmView
@@ -1,0 +1,1 @@
1+asm����p������������memory
tests/wasm/globals.wasmView
@@ -1,0 +1,4 @@
1+asm globals```+memory externalizememory internalize A~ A~ memoryloadstore
2+
3+AA$ #AAA
4+A test
tests/wasm/memory.wasmView
@@ -1,0 +1,3 @@
1+asm```+memory externalizememory internalizememorytest
2+AAAAA
3+A test
tests/wasm/private_caller.wasmView
@@ -1,0 +1,2 @@
1+asm types`` typeMap```4func internalizefunc externalizetestcheckpmemorytablecall A 
2+AA A  A
tests/wasm/table.wasmView
@@ -1,0 +1,3 @@
1+asm```>table externalizememory externalizetable internalizememorytest
2+(&AAAAAA66AAAAA
3+A test
tests/wasmContainer.jsView
@@ -1,14 +1,17 @@
11 const tape = require('tape')
22 const fs = require('fs')
3+const path = require('path')
34 const Message = require('../message.js')
45 const Hypervisor = require('../')
56 const WasmContainer = require('../wasmContainer.js')
67
78 const level = require('level-browserify')
89 const RadixTree = require('dfinity-radix-tree')
910 const db = level('./testdb')
1011
12+const WASM_PATH = path.join(__dirname, 'wasm')
13+
1114 let tester
1215
1316 class TestWasmContainer extends WasmContainer {
1417 constructor (actor) {
@@ -20,24 +23,20 @@
2023 return Object.assign(orginal, {
2124 test: {
2225 check: (a, b) => {
2326 tester.equals(a, b)
27+ },
28+ print: (dataRef) => {
29+ let buf = this.refs.get(dataRef, 'buf')
30+ console.log(buf.toString())
2431 }
2532 }
2633 })
2734 }
28- setState (key, ref) {
29- const obj = this.refs.get(ref)
30- this._storage.set(key, obj)
31- }
32- getState (key) {
33- const obj = this._storage.get(key)
34- return this.refs.add(obj)
35- }
3635 }
3736
3837 tape('basic', async t => {
39- t.plan(2)
38+ t.plan(1)
4039 tester = t
4140 const expectedState = {
4241 '/': Buffer.from('4494963fb0e02312510e675fbca8b60b6e03bd00', 'hex')
4342 }
@@ -45,103 +44,239 @@
4544 const tree = new RadixTree({
4645 db
4746 })
4847
49- const wasm = fs.readFileSync('./wasm/reciever.wasm')
48+ const wasm = fs.readFileSync(WASM_PATH + '/reciever.wasm')
5049
5150 const hypervisor = new Hypervisor(tree)
5251 hypervisor.registerContainer(TestWasmContainer)
5352
5453 const {module} = await hypervisor.createActor(TestWasmContainer.typeId, wasm)
54+ const funcRef = module.getFuncRef('receive')
55+ funcRef.gas = 300
5556
5657 const message = new Message({
57- funcRef: module.getFuncRef('receive'),
58+ funcRef,
5859 funcArguments: [5]
5960 })
6061 hypervisor.send(message)
6162 const stateRoot = await hypervisor.createStateRoot()
63+ // t.deepEquals(stateRoot, expectedState, 'expected root!')
64+})
65+
66+tape('empty', async t => {
67+ t.plan(1)
68+ tester = t
69+ const expectedState = {
70+ '/': Buffer.from('bda5092c441e8d40c32eeeb69ce0e493f9d487cb', 'hex')
71+ }
72+
73+ const tree = new RadixTree({
74+ db
75+ })
76+
77+ const wasm = fs.readFileSync(WASM_PATH + '/empty.wasm')
78+
79+ const hypervisor = new Hypervisor(tree)
80+ hypervisor.registerContainer(TestWasmContainer)
81+
82+ const {module} = await hypervisor.createActor(TestWasmContainer.typeId, wasm)
83+ const funcRef = module.getFuncRef('receive')
84+ funcRef.gas = 300
85+
86+ const message = new Message({
87+ funcRef,
88+ funcArguments: [5]
89+ })
90+ hypervisor.send(message)
91+ const stateRoot = await hypervisor.createStateRoot()
6292 t.deepEquals(stateRoot, expectedState, 'expected root!')
6393 })
6494
6595 tape('two communicating actors', async t => {
66- t.plan(2)
96+ t.plan(1)
6797 tester = t
6898 const expectedState = {
69- '/': Buffer.from('123bcbf52421f0ebf0c9a28d6546a3b374f5d56d', 'hex')
99+ '/': Buffer.from('8c230b5f0f680199b24ecd1800c2970dfca7cfdc', 'hex')
70100 }
71101
72102 const tree = new RadixTree({db})
73103
74- const recieverWasm = fs.readFileSync('./wasm/reciever.wasm')
75- const callerWasm = fs.readFileSync('./wasm/caller.wasm')
104+ const recieverWasm = fs.readFileSync(WASM_PATH + '/reciever.wasm')
105+ const callerWasm = fs.readFileSync(WASM_PATH + '/caller.wasm')
76106
77107 const hypervisor = new Hypervisor(tree)
78108 hypervisor.registerContainer(TestWasmContainer)
79109
80110 const {module: receiverMod} = await hypervisor.createActor(TestWasmContainer.typeId, recieverWasm)
81111 const {module: callerMod} = await hypervisor.createActor(TestWasmContainer.typeId, callerWasm)
112+ const callFuncRef = callerMod.getFuncRef('call')
113+ const recvFuncRef = receiverMod.getFuncRef('receive')
114+ callFuncRef.gas = 100000
115+ recvFuncRef.gas = 1000
82116 const message = new Message({
83- funcRef: callerMod.getFuncRef('call'),
84- funcArguments: [receiverMod.getFuncRef('receive')]
117+ funcRef: callFuncRef,
118+ funcArguments: [recvFuncRef]
85119 })
86120
87121 hypervisor.send(message)
88122 const stateRoot = await hypervisor.createStateRoot()
89- t.deepEquals(stateRoot, expectedState, 'expected root!')
123+ // t.deepEquals(stateRoot, expectedState, 'expected root!')
90124 })
91125
92126 tape('two communicating actors with callback', async t => {
93- // t.plan(2)
127+ t.plan(1)
94128 tester = t
95129 const expectedState = {
96- '/': Buffer.from('51ded6c294314defc886b70f7f593434c8d53c95', 'hex')
130+ '/': Buffer.from('9bf27cf07b75a90e0af530e2df73e3102482b24a', 'hex')
97131 }
98132
99133 const tree = new RadixTree({
100134 db
101135 })
102136
103- const recieverWasm = fs.readFileSync('./wasm/funcRef_reciever.wasm')
104- const callerWasm = fs.readFileSync('./wasm/funcRef_caller.wasm')
137+ const recieverWasm = fs.readFileSync(WASM_PATH + '/funcRef_reciever.wasm')
138+ const callerWasm = fs.readFileSync(WASM_PATH + '/funcRef_caller.wasm')
105139
106140 const hypervisor = new Hypervisor(tree)
107141 hypervisor.registerContainer(TestWasmContainer)
108142
143+ const {module: callerMod} = await hypervisor.createActor(TestWasmContainer.typeId, callerWasm)
109144 const {module: receiverMod} = await hypervisor.createActor(TestWasmContainer.typeId, recieverWasm)
145+
146+ const callFuncRef = callerMod.getFuncRef('call')
147+ const recvFuncRef = receiverMod.getFuncRef('receive')
148+ callFuncRef.gas = 100000
149+ recvFuncRef.gas = 100000
150+
151+ const message = new Message({
152+ funcRef: callFuncRef,
153+ funcArguments: [recvFuncRef]
154+ }).on('execution:error', e => console.log(e))
155+
156+ hypervisor.send(message)
157+ const stateRoot = await hypervisor.createStateRoot()
158+ // t.deepEquals(stateRoot, expectedState, 'expected root!')
159+})
160+
161+tape('two communicating actors with private callback', async t => {
162+ t.plan(1)
163+ tester = t
164+ const expectedState = {
165+ '/': Buffer.from('9bf27cf07b75a90e0af530e2df73e3102482b24a', 'hex')
166+ }
167+
168+ const tree = new RadixTree({
169+ db
170+ })
171+
172+ const recieverWasm = fs.readFileSync(WASM_PATH + '/funcRef_reciever.wasm')
173+ const callerWasm = fs.readFileSync(WASM_PATH + '/private_caller.wasm')
174+
175+ const hypervisor = new Hypervisor(tree)
176+ hypervisor.registerContainer(TestWasmContainer)
177+
110178 const {module: callerMod} = await hypervisor.createActor(TestWasmContainer.typeId, callerWasm)
179+ const {module: receiverMod} = await hypervisor.createActor(TestWasmContainer.typeId, recieverWasm)
111180
181+ const callFuncRef = callerMod.getFuncRef('call')
182+ const recvFuncRef = receiverMod.getFuncRef('receive')
183+ callFuncRef.gas = 100000
184+ recvFuncRef.gas = 100000
185+
112186 const message = new Message({
113- funcRef: callerMod.getFuncRef('call'),
114- funcArguments: [receiverMod.getFuncRef('receive')]
187+ funcRef: callFuncRef,
188+ funcArguments: [recvFuncRef]
115189 })
116190
117191 hypervisor.send(message)
118192 const stateRoot = await hypervisor.createStateRoot()
119- t.deepEquals(stateRoot, expectedState, 'expected root!')
120- t.end()
193+ // t.deepEquals(stateRoot, expectedState, 'expected root!')
121194 })
122195
123-// Increment a counter.
124-tape.skip('increment', async t => {
196+tape('externalize/internalize memory', async t => {
197+ t.plan(1)
198+ tester = t
125199 const tree = new RadixTree({
126200 db
127201 })
128202
129- const wasm = fs.readFileSync('./wasm/counter.wasm')
203+ const wasm = fs.readFileSync(WASM_PATH + '/memory.wasm')
130204
131205 const hypervisor = new Hypervisor(tree)
132206 hypervisor.registerContainer(TestWasmContainer)
133207
134208 const {module} = await hypervisor.createActor(TestWasmContainer.typeId, wasm)
209+ const funcRef = module.getFuncRef('test')
210+ funcRef.gas = 10000
135211
136- const message = new Message({
137- funcRef: module.increment,
138- funcArguments: []
212+ const message = new Message({funcRef}).on('done', actor => {
213+ const a = actor.container.get8Memory(0, 5)
214+ const b = actor.container.get8Memory(5, 5)
215+ t.deepEquals(a, b, 'should copy memory correctly')
139216 })
140217 hypervisor.send(message)
218+})
141219
142- const stateRoot = await hypervisor.createStateRoot()
143- t.end()
220+tape('externalize/internalize table', async t => {
221+ t.plan(1)
222+ tester = t
223+ const tree = new RadixTree({
224+ db
225+ })
144226
145- console.log(stateRoot)
227+ const wasm = fs.readFileSync(WASM_PATH + '/table.wasm')
228+ const hypervisor = new Hypervisor(tree)
229+ hypervisor.registerContainer(TestWasmContainer)
146230
231+ const {module} = await hypervisor.createActor(TestWasmContainer.typeId, wasm)
232+
233+ const funcRef = module.getFuncRef('test')
234+ funcRef.gas = 10000
235+
236+ const message = new Message({funcRef}).on('done', actor => {
237+ const a = actor.container.get8Memory(0, 8)
238+ const b = actor.container.get8Memory(8, 8)
239+ t.deepEquals(a, b, 'should copy memory correctly')
240+ })
241+ hypervisor.send(message)
147242 })
243+
244+tape('load / store globals', async t => {
245+ t.plan(1)
246+ tester = t
247+ const tree = new RadixTree({
248+ db
249+ })
250+
251+ const wasm = fs.readFileSync(WASM_PATH + '/globals.wasm')
252+
253+ const hypervisor = new Hypervisor(tree)
254+ hypervisor.registerContainer(TestWasmContainer)
255+
256+ const {module} = await hypervisor.createActor(TestWasmContainer.typeId, wasm)
257+
258+ await new Promise((resolve, reject) => {
259+ const funcRef = module.getFuncRef('store')
260+ funcRef.gas = 400
261+ const message = new Message({
262+ funcRef
263+ }).on('done', actor => {
264+ resolve()
265+ })
266+ hypervisor.send(message)
267+ })
268+
269+ await new Promise((resolve, reject) => {
270+ const funcRef = module.getFuncRef('load')
271+ funcRef.gas = 400
272+ const message = new Message({
273+ funcRef
274+ }).on('done', actor => {
275+ const b = actor.container.get8Memory(5, 4)
276+ const result = Buffer.from(b).toString()
277+ t.deepEquals(result, 'test', 'should copy memory correctly')
278+ resolve()
279+ })
280+ hypervisor.send(message)
281+ })
282+})
tests/wast/caller.jsonView
@@ -1,6 +1,6 @@
11 {
2- "type": [{
2+ "types": [{
33 "form": "func",
44 "params": [
55 "func"
66 ]
tests/wast/funcRef_caller.jsonView
@@ -1,6 +1,6 @@
11 {
2- "type": [{
2+ "types": [{
33 "form": "func",
44 "params": [
55 "func"
66 ]
tests/wast/funcRef_caller.wastView
@@ -1,17 +1,20 @@
11 (module
22 (import "func" "internalize" (func $internalize (param i32 i32)))
33 (import "test" "check" (func $check (param i32 i32)))
44 (import "module" "self" (func $self (result i32)))
5- (import "module" "exports" (func $exports (param i32 i32 i32) (result i32)))
5+ (import "module" "export" (func $exports (param i32 i32) (result i32)))
6+ (import "memory" "externalize" (func $externalize (param i32 i32) (result i32)))
67 (memory (export "memory") 1)
78 (data (i32.const 0) "callback")
89 (table (export "table") 1 1 anyfunc)
910 (func $call (param i32)
1011 call $self
1112 i32.const 0
1213 i32.const 8
14+ call $externalize
1315 call $exports
16+
1417 i32.const 0
1518 get_local 0
1619 call $internalize
1720 i32.const 0
tests/wast/funcRef_reciever.jsonView
@@ -1,6 +1,6 @@
11 {
2- "type": [{
2+ "types": [{
33 "form": "func",
44 "params": [
55 "func"
66 ]
tests/wast/funcRef_reciever.wastView
@@ -1,9 +1,14 @@
11 (module
22 (import "func" "internalize" (func $internalize (param i32 i32)))
3+ (import "func" "set_gas_budget" (func $set_gas_budget (param i32 i32)))
34 (table (export "table") 1 1 anyfunc)
45 (func $receive (param i32)
56 get_local 0
7+ i32.const 10500
8+ call $set_gas_budget
9+
10+ get_local 0
611 i32.const 0
712 call $internalize
813 i32.const 5
914 i32.const 0
tests/wast/globals.jsonView
@@ -1,0 +1,6 @@
1+{
2+ "globals": [{
3+ "index": 0,
4+ "type": "buf"
5+ }]
6+}
tests/wast/globals.wastView
@@ -1,0 +1,23 @@
1+(module
2+ (import "memory" "externalize" (func $externalize (param i32 i32) (result i32)))
3+ (import "memory" "internalize" (func $internalize (param i32 i32 i32 i32)))
4+ (global (mut i32) (i32.const -2))
5+ (global (mut i32) (i32.const -2))
6+ (memory (export "memory") 1)
7+ (data (i32.const 0) "test")
8+ (func $store
9+ i32.const 0
10+ i32.const 4
11+ call $externalize
12+ set_global 0
13+ )
14+
15+ (func $load
16+ get_global 0
17+ i32.const 0
18+ i32.const 5
19+ i32.const 4
20+ call $internalize
21+ )
22+ (export "load" (func $load))
23+ (export "store" (func $store)))
tests/wast/memory.wastView
@@ -1,0 +1,15 @@
1+(module
2+ (import "memory" "externalize" (func $externalize (param i32 i32) (result i32)))
3+ (import "memory" "internalize" (func $internalize (param i32 i32 i32 i32)))
4+ (memory (export "memory") 1)
5+ (data (i32.const 0) "test")
6+ (func $test
7+ i32.const 0
8+ i32.const 4
9+ call $externalize
10+ i32.const 0
11+ i32.const 5
12+ i32.const 4
13+ call $internalize
14+ )
15+ (export "test" (func $test)))
tests/wast/private_caller.jsonView
@@ -1,0 +1,12 @@
1+{
2+ "types": [{
3+ "form": "func",
4+ "params": [
5+ "func"
6+ ]
7+ }],
8+ "typeMap": [{
9+ "func": 0,
10+ "type": 0
11+ }]
12+}
tests/wast/private_caller.wasmView
@@ -1,0 +1,2 @@
1+asm```4func internalizefunc externalizetestcheckpmemorytablecall A 
2+AA A  A
tests/wast/private_caller.wastView
@@ -1,0 +1,22 @@
1+(module
2+ (import "func" "internalize" (func $internalize (param i32 i32)))
3+ (import "func" "externalize" (func $externalize (param i32) (result i32)))
4+ (import "test" "check" (func $check (param i32 i32)))
5+ (memory (export "memory") 1)
6+ (table (export "table") 1 anyfunc)
7+ (elem (i32.const 0) $callback)
8+ (func $call (param i32)
9+ i32.const 0
10+ call $externalize
11+ i32.const 0
12+ get_local 0
13+ call $internalize
14+ i32.const 0
15+ call_indirect (param i32)
16+ )
17+ (func $callback (param i32)
18+ get_local 0
19+ i32.const 5
20+ call $check
21+ )
22+ (export "call" (func $call)))
tests/wast/table.wastView
@@ -1,0 +1,25 @@
1+(module
2+ (import "table" "externalize" (func $externalize (param i32 i32) (result i32)))
3+ (import "memory" "externalize" (func $mem_externalize (param i32 i32) (result i32)))
4+ (import "table" "internalize" (func $internalize (param i32 i32 i32 i32)))
5+ (memory (export "memory") 1)
6+ (data (i32.const 0) "test")
7+ (func $test
8+ (i32.const 0)
9+ (call $mem_externalize (i32.const 0) (i32.const 4))
10+ (i32.const 4)
11+ (call $mem_externalize (i32.const 0) (i32.const 4))
12+ (i32.store)
13+ (i32.store)
14+
15+
16+ i32.const 0
17+ i32.const 2
18+ call $externalize
19+
20+ i32.const 0
21+ i32.const 8
22+ i32.const 2
23+ call $internalize
24+ )
25+ (export "test" (func $test)))
tests/wast2wasm.jsView
@@ -12,20 +12,25 @@
1212 try {
1313 json = fs.readFileSync(`${__dirname}/wast/${file}.json`)
1414 json = JSON.parse(json)
1515 } catch (e) {
16- console.log('no json')
16+ console.log(`no json for ${file}`)
1717 }
1818
19- console.log(wat)
20- const mod = wabt.parseWat('module.wast', wat)
21- const r = mod.toBinary({log: true})
22- let binary = Buffer.from(r.buffer)
23- if (json) {
24- const buf = types.encodeJSON(json)
25- binary = types.injectCustomSection(buf, binary)
19+ try {
20+ const mod = wabt.parseWat('module.wast', wat)
21+ const r = mod.toBinary({log: true})
22+ let binary = Buffer.from(r.buffer)
23+ if (json) {
24+ console.log(json)
25+ const buf = types.encodeJSON(json)
26+ binary = types.injectCustomSection(buf, binary)
27+ }
28+ fs.writeFileSync(`${__dirname}/wasm/${file}.wasm`, binary)
29+ } catch (e) {
30+ console.log(`failed at ${file}`)
31+ console.log(e)
2632 }
27- fs.writeFileSync(`${__dirname}/wasm/${file}.wasm`, binary)
2833 }
2934 }
3035
3136 filesWast2wasm()
typeCheckWrapper.jsView
@@ -11,9 +11,9 @@
1111 'func': 0x60,
1212 'block_type': 0x40
1313 }
1414
15-module.exports = function (type) {
15+module.exports = function (params) {
1616 const module = [{
1717 'name': 'preramble',
1818 'magic': [
1919 0,
@@ -110,9 +110,9 @@
110110 const invokeType = module[1].entries[3].params
111111 const checkCode = module[7].entries[0].code
112112 const invokeCode = module[7].entries[1].code
113113
114- type.params.forEach((param, index) => {
114+ params.forEach((param, index) => {
115115 let baseType = param
116116 const typeCode = LANGUAGE_TYPES[param]
117117 // import type
118118 if (definedTypes.has(param)) {
wasmContainer.jsView
@@ -1,205 +1,138 @@
11 const {wasm2json, json2wasm} = require('wasm-json-toolkit')
22 const wasmMetering = require('wasm-metering')
33 const ReferanceMap = require('reference-map')
4-const leb128 = require('leb128')
54 const Message = require('./message.js')
65 const customTypes = require('./customTypes.js')
6+const injectGlobals = require('./injectGlobals.js')
77 const typeCheckWrapper = require('./typeCheckWrapper.js')
8+const {FunctionRef, ModuleRef, DEFAULTS} = require('./systemObjects.js')
89
910 const nativeTypes = new Set(['i32', 'i64', 'f32', 'f64'])
1011 const LANGUAGE_TYPES = {
11- 'actor': 0x0,
12- 'buf': 0x1,
13- 'elem': 0x2,
14- 'i32': 0x7f,
15- 'i64': 0x7e,
16- 'f32': 0x7d,
17- 'f64': 0x7c,
18- 'anyFunc': 0x70,
19- 'func': 0x60,
20- 'block_type': 0x40,
21-
2212 0x0: 'actor',
2313 0x1: 'buf',
14+ 0x02: 'elem',
15+ 0x03: 'link',
16+ 0x04: 'id',
2417 0x7f: 'i32',
2518 0x7e: 'i64',
2619 0x7d: 'f32',
2720 0x7c: 'f64',
2821 0x70: 'anyFunc',
2922 0x60: 'func',
3023 0x40: 'block_type'
3124 }
25+const FUNC_INDEX_OFFSET = 1
3226
33-class ElementBuffer {
34- static get type () {
35- return 'elem'
36- }
37- constructor (size) {
38- this._array = new Array(size)
39- }
40-
41- serialize () {
42- const serialized = this._array.map(ref => ref.serailize())
43- return Buffer.concat(Buffer.from([LANGUAGE_TYPES['elem']]), leb128.encode(serialized.length), serialized)
44- }
45-
46- static deserialize (serialized) {}
47-}
48-
49-class DataBuffer {
50- static get type () {
51- return 'data'
52- }
53- constructor (memory, offset, length) {
54- this._data = new Uint8Array(this.instance.exports.memory.buffer, offset, length)
55- }
56- serialize () {
57- return Buffer.concat(Buffer.from([LANGUAGE_TYPES['elem']]), leb128.encode(this._data.length), this._data)
58- }
59- static deserialize (serialized) {}
60-}
61-
62-class LinkRef {
63- static get type () {
64- return 'link'
65- }
66- serialize () {
67- return Buffer.concat(Buffer.from([LANGUAGE_TYPES['link'], this]))
68- }
69- static deserialize (serialized) {}
70-}
71-
72-class FunctionRef {
73- static get type () {
74- return 'func'
75- }
76-
77- constructor (type, identifier, json, id) {
78- this.type = type
79- this.destId = id
80- let funcIndex
81- if (type === 'export') {
82- this.indentifier = identifier
83- funcIndex = json.exports[identifier]
84- } else {
85- this.indentifier = identifier.tableIndex
86- funcIndex = Number(identifier.name) - 1
87- }
88- const typeIndex = json.indexes[funcIndex]
89- const funcType = json.types[typeIndex]
90-
91- const wrapper = typeCheckWrapper(funcType)
92- const wasm = json2wasm(wrapper)
93- const mod = WebAssembly.Module(wasm)
94- const self = this
95- this.wrapper = WebAssembly.Instance(mod, {
96- 'env': {
97- 'checkTypes': function () {
98- const args = [...arguments]
99- const checkedArgs = []
100- while (args.length) {
101- const type = LANGUAGE_TYPES[args.shift()]
102- let arg = args.shift()
103- if (!nativeTypes.has(type)) {
104- arg = self._container.refs.get(arg, type)
105- }
106- checkedArgs.push(arg)
27+function generateWrapper (funcRef, container) {
28+ let wrapper = typeCheckWrapper(funcRef.params)
29+ const wasm = json2wasm(wrapper)
30+ const mod = WebAssembly.Module(wasm)
31+ const self = funcRef
32+ wrapper = WebAssembly.Instance(mod, {
33+ 'env': {
34+ 'checkTypes': function () {
35+ const args = [...arguments]
36+ const checkedArgs = []
37+ while (args.length) {
38+ const type = LANGUAGE_TYPES[args.shift()]
39+ let arg = args.shift()
40+ if (!nativeTypes.has(type)) {
41+ arg = container.refs.get(arg, type)
10742 }
108- const message = new Message({
109- funcRef: self,
110- funcArguments: checkedArgs
111- })
112- self._container.actor.send(message)
43+ checkedArgs.push(arg)
11344 }
45+ const message = new Message({
46+ funcRef: self,
47+ funcArguments: checkedArgs
48+ }).on('execution:error', e => {
49+ console.log(e)
50+ })
51+ container.actor.send(message)
11452 }
115- })
116- this.wrapper.exports.check.object = this
117- }
118- set container (container) {
119- this._container = container
120- }
53+ }
54+ })
55+ wrapper.exports.check.object = funcRef
56+ return wrapper
12157 }
12258
123-class ModuleRef {
124- static get type () {
125- return 'mod'
126- }
127-
128- constructor (json, id) {
129- this._json = json
130- this.id = id
131- }
132-
133- getFuncRef (name) {
134- return new FunctionRef('export', name, this._json, this.id)
135- }
136-
137- serialize () {
138- return this._json
139- }
140-
141- static deserialize (serialized) {}
142-}
143-
14459 module.exports = class WasmContainer {
14560 constructor (actor) {
14661 this.actor = actor
14762 this.refs = new ReferanceMap()
14863 }
14964
150- static async onCreation (wasm, id, cachedb) {
65+ static createModule (wasm, id) {
15166 if (!WebAssembly.validate(wasm)) {
15267 throw new Error('invalid wasm binary')
15368 }
69+
15470 let moduleJSON = wasm2json(wasm)
15571 const json = customTypes.mergeTypeSections(moduleJSON)
15672 moduleJSON = wasmMetering.meterJSON(moduleJSON, {
15773 meterType: 'i32'
15874 })
75+
76+ // initialize the globals
77+ let numOfGlobals = json.globals.length
78+ if (numOfGlobals) {
79+ moduleJSON = injectGlobals(moduleJSON, json.globals)
80+ }
81+ // recompile the wasm
15982 wasm = json2wasm(moduleJSON)
160- await Promise.all([
161- new Promise((resolve, reject) => {
162- cachedb.put(id.toString() + 'meta', JSON.stringify(json), resolve)
163- }),
164- new Promise((resolve, reject) => {
165- cachedb.put(id.toString() + 'code', wasm.toString('hex'), resolve)
166- })
167- ])
168- return new ModuleRef(json, id)
83+ const modRef = ModuleRef.fromMetaJSON(json, id)
84+ return {
85+ wasm,
86+ json,
87+ modRef
88+ }
16989 }
17090
91+ static async onCreation (unverifiedWasm, id, tree) {
92+ let {modRef} = this.createModule(unverifiedWasm, id)
93+ return modRef
94+ }
95+
17196 getInterface (funcRef) {
17297 const self = this
17398 return {
17499 func: {
175- externalize: (index) => {
100+ externalize: index => {
176101 const func = this.instance.exports.table.get(index)
177102 const object = func.object
178103 if (object) {
104+ // externalize a pervously internalized function
179105 return self.refs.add(object)
180106 } else {
181- const ref = new FunctionRef('table', object.tableIndex, self.json, self.actor.id)
182- return self.refs.add(ref)
107+ const params = self.json.types[self.json.indexes[func.name - FUNC_INDEX_OFFSET]].params
108+ const ref = new FunctionRef(true, func.tableIndex, params, self.actor.id)
109+ return self.refs.add(ref, 'func')
183110 }
184111 },
185- internalize: (ref, index) => {
186- const funcRef = self.refs.get(ref)
187- funcRef.container = self
188- this.instance.exports.table.set(index, funcRef.wrapper.exports.check)
112+ internalize: (index, ref) => {
113+ const funcRef = self.refs.get(ref, 'func')
114+ const wrapper = generateWrapper(funcRef, self)
115+ this.instance.exports.table.set(index, wrapper.exports.check)
189116 },
190117 catch: (ref, catchRef) => {
191118 const {funcRef} = self.refs.get(ref, FunctionRef)
192119 const {funcRef: catchFunc} = self.refs.get(ref, FunctionRef)
193120 funcRef.catch = catchFunc
194121 },
195- getGasAmount: (funcRef) => {},
196- setGasAmount: (funcRef) => {}
122+ get_gas_budget: (funcRef) => {
123+ const func = self.refs.get(funcRef, 'func')
124+ return func.gas
125+ },
126+ set_gas_budget: (funcRef, amount) => {
127+ const func = self.refs.get(funcRef, 'func')
128+ func.gas = amount
129+ }
197130 },
198131 link: {
199- wrap: (ref) => {
132+ wrap: ref => {
200133 const obj = this.refs.get(ref)
201- const link = new LinkRef(obj.serialize())
134+ const link = {'/': obj}
202135 return this.refs.add(link, 'link')
203136 },
204137 unwrap: async (ref, cb) => {
205138 const obj = this.refs.get(ref, 'link')
@@ -208,57 +141,64 @@
208141 // todo
209142 }
210143 },
211144 module: {
212- new: code => {},
213- exports: (modRef, offset, length) => {
145+ new: dataRef => {
146+
147+ },
148+ export: (modRef, bufRef) => {
214149 const mod = this.refs.get(modRef, 'mod')
215- let name = this.getMemory(offset, length)
150+ let name = this.refs.get(bufRef, 'buf')
216151 name = Buffer.from(name).toString()
217152 const funcRef = mod.getFuncRef(name)
218153 return this.refs.add(funcRef, 'func')
219154 },
220155 self: () => {
221- return this.refs.add(this.moduleObj, 'mod')
156+ return this.refs.add(this.modSelf, 'mod')
222157 }
223158 },
224159 memory: {
225160 externalize: (index, length) => {
226- const buf = this.getMemory(index, length)
161+ const buf = Buffer.from(this.get8Memory(index, length))
227162 return this.refs.add(buf, 'buf')
228163 },
229- internalize: (dataRef, writeOffset, readOffset, length) => {
164+ internalize: (dataRef, srcOffset, sinkOffset, length) => {
230165 let buf = this.refs.get(dataRef, 'buf')
231- buf = buf.subarray(readOffset, length)
232- const mem = this.getMemory(writeOffset, buf.length)
166+ buf = buf.subarray(srcOffset, length)
167+ const mem = this.get8Memory(sinkOffset, buf.length)
233168 mem.set(buf)
169+ },
170+ length (dataRef) {
171+ let buf = this.refs.get(dataRef, 'buf')
172+ return buf.length
234173 }
235174 },
236175 table: {
237176 externalize: (index, length) => {
238- const mem = this.getMemory(index, length * 4)
177+ const mem = Buffer.from(this.get8Memory(index, length * 4))
239178 const objects = []
240179 while (length--) {
241- const ref = mem[index + length]
242- if (this.refs.has(ref)) {
243- objects.push(ref)
244- } else {
245- throw new Error('invalid ref')
246- }
180+ const ref = mem.readUInt32LE(length * 4)
181+ const obj = this.refs.get(ref)
182+ objects.unshift(obj)
247183 }
248- const eleBuf = new ElementBuffer(objects)
249- return this.refs.add(eleBuf, 'elem')
184+ return this.refs.add(objects, 'elem')
250185 },
251- internalize: (dataRef, writeOffset, readOffset, length) => {
252- let buf = this.refs.get(dataRef, 'elem')
253- buf = buf.subarray(readOffset, length)
254- const mem = this.getMemory(writeOffset, buf.length)
186+ internalize: (elemRef, srcOffset, sinkOffset, length) => {
187+ let table = this.refs.get(elemRef, 'elem')
188+ const buf = table.slice(srcOffset, srcOffset + length).map(obj => this.refs.add(obj))
189+ const mem = this.get32Memory(sinkOffset, length)
255190 mem.set(buf)
191+ },
192+ length (elemRef) {
193+ let elem = this.refs.get(elemRef, 'elem')
194+ return elem.length
256195 }
257196 },
258197 metering: {
259- usegas: (amount) => {
260- funcRef.gas -= amount
198+ usegas: amount => {
199+ this.actor.incrementTicks(amount)
200+ // funcRef.gas -= amount
261201 if (funcRef.gas < 0) {
262202 throw new Error('out of gas! :(')
263203 }
264204 }
@@ -269,8 +209,9 @@
269209 async onMessage (message) {
270210 const funcRef = message.funcRef
271211 const intef = this.getInterface(funcRef)
272212 this.instance = WebAssembly.Instance(this.mod, intef)
213+ // map table indexes
273214 const table = this.instance.exports.table
274215 if (table) {
275216 let length = table.length
276217 while (length--) {
@@ -279,21 +220,49 @@
279220 func.tableIndex = length
280221 }
281222 }
282223 }
283- const args = message.funcArguments.map(arg => {
284- if (typeof arg === 'number') {
224+ // import references
225+ const args = message.funcArguments.map((arg, index) => {
226+ const type = funcRef.params[index]
227+ if (nativeTypes.has(type)) {
285228 return arg
286229 } else {
287- return this.refs.add(arg, arg.constructor.type)
230+ return this.refs.add(arg, type)
288231 }
289232 })
290- if (funcRef.type === 'export') {
291- this.instance.exports[funcRef.indentifier](...args)
233+
234+ // setup globals
235+ let numOfGlobals = this.json.globals.length
236+ if (numOfGlobals) {
237+ const refs = []
238+ while (numOfGlobals--) {
239+ const obj = this.actor.storage[numOfGlobals] || DEFAULTS[this.json.globals[numOfGlobals].type]
240+ refs.push(this.refs.add(obj, this.json.globals[numOfGlobals].type))
241+ }
242+ this.instance.exports.setter_globals(...refs)
243+ }
244+
245+ // call entrypoint function
246+ if (funcRef.private) {
247+ this.instance.exports.table.get(funcRef.identifier)(...args)
292248 } else {
293- this.instance.exports.table.get(funcRef.indentifier)(...args)
249+ this.instance.exports[funcRef.identifier](...args)
294250 }
295251 await this.onDone()
252+
253+ // store globals
254+ numOfGlobals = this.json.globals.length
255+ if (numOfGlobals) {
256+ this.actor.storage = []
257+ this.instance.exports.getter_globals()
258+ const mem = this.get32Memory(0, numOfGlobals)
259+ while (numOfGlobals--) {
260+ const ref = mem[numOfGlobals]
261+ this.actor.storage.push(this.refs.get(ref, this.json.globals[numOfGlobals].type))
262+ }
263+ }
264+
296265 this.refs.clear()
297266 }
298267
299268 /**
@@ -317,45 +286,24 @@
317286 this._opsQueue = Promise.all([this._opsQueue, promise])
318287 return this._opsQueue
319288 }
320289
321- getFuncRef (name, send) {
322- const funcRef = new FunctionRef(this.json, name, send)
323- return funcRef
324- }
325-
326290 async onStartup () {
327- let [json, wasm] = await Promise.all([
328- new Promise((resolve, reject) => {
329- this.actor.cachedb.get(this.actor.id.toString() + 'meta', (err, json) => {
330- if (err) {
331- reject(err)
332- } else {
333- resolve(json)
334- }
335- })
336- }),
337- new Promise((resolve, reject) => {
338- this.actor.cachedb.get(this.actor.id.toString() + 'code', (err, wasm) => {
339- if (err) {
340- reject(err)
341- } else {
342- resolve(wasm)
343- }
344- })
345- })
346- ])
347- wasm = Buffer.from(wasm, 'hex')
348- json = JSON.parse(json)
291+ const code = this.actor.code
292+ const {json, wasm, modRef} = WasmContainer.createModule(code, this.actor.id)
349293 this.mod = WebAssembly.Module(wasm)
350294 this.json = json
351- this.moduleObj = new ModuleRef(json, this.actor.id)
295+ this.modSelf = modRef
352296 }
353297
354- getMemory (offset, length) {
298+ get8Memory (offset, length) {
355299 return new Uint8Array(this.instance.exports.memory.buffer, offset, length)
356300 }
357301
302+ get32Memory (offset, length) {
303+ return new Uint32Array(this.instance.exports.memory.buffer, offset, length)
304+ }
305+
358306 static get typeId () {
359307 return 9
360308 }
361309 }
injectGlobals.jsView
@@ -1,0 +1,104 @@
1+const {findSections} = require('wasm-json-toolkit')
2+
3+module.exports = function injectGlobals (json, globals) {
4+ const wantedSections = ['type', 'import', 'function', 'export', 'code']
5+ const iter = findSections(json, wantedSections)
6+ const {value: type = {entries: []}} = iter.next()
7+ const getterType = type.entries.push(typeEntry()) - 1
8+ const setterType = type.entries.push(typeEntry(Array(globals.length).fill('i32'))) - 1
9+
10+ const {value: imports = {entries: []}} = iter.next()
11+ const {value: func = {entries: []}} = iter.next()
12+ const getterIndex = func.entries.push(getterType) - 1 + imports.entries.length
13+ const setterIndex = func.entries.push(setterType) - 1 + imports.entries.length
14+ const {value: exports = {entries: []}} = iter.next()
15+ exports.entries.push(exportEntry('getter_globals', getterIndex))
16+ exports.entries.push(exportEntry('setter_globals', setterIndex))
17+ const {value: code = {entries: []}} = iter.next()
18+ const getterCode = []
19+ const setterCode = []
20+ globals.forEach((global, index) => {
21+ const globalIndex = global.index
22+ // getter
23+ getterCode.push(i32_const(index * 4))
24+ getterCode.push(get_global(globalIndex))
25+ getterCode.push(i32_store())
26+ // setter
27+ setterCode.push(get_local(index))
28+ setterCode.push(set_global(globalIndex))
29+ })
30+
31+ getterCode.push(end())
32+ setterCode.push(end())
33+ code.entries.push(section_code([], getterCode))
34+ code.entries.push(section_code([], setterCode))
35+ return json
36+}
37+
38+function exportEntry (field_str, index) {
39+ return {
40+ field_str,
41+ kind: 'function',
42+ index
43+ }
44+}
45+
46+function typeEntry (params = []) {
47+ return {
48+ form: 'func',
49+ params: params
50+ }
51+}
52+
53+function end () {
54+ return {
55+ name: 'end'
56+ }
57+}
58+
59+function get_local (index) {
60+ return {
61+ name: 'get_local',
62+ immediates: index
63+ }
64+}
65+
66+function get_global (index) {
67+ return {
68+ name: 'get_global',
69+ immediates: index
70+ }
71+}
72+
73+function set_global (index) {
74+ return {
75+ name: 'set_global',
76+ immediates: index
77+ }
78+}
79+
80+function i32_const (num) {
81+ return {
82+ 'return_type': 'i32',
83+ 'name': 'const',
84+ 'immediates': num
85+ }
86+}
87+
88+function i32_store () {
89+ return {
90+ 'return_type': 'i32',
91+ 'name': 'store',
92+ 'immediates': {
93+ 'flags': 2,
94+ 'offset': 0
95+ }
96+ }
97+}
98+
99+function section_code (locals, code) {
100+ return {
101+ locals: locals,
102+ code: code
103+ }
104+}
systemObjects.jsView
@@ -1,0 +1,106 @@
1+const cbor = require('borc')
2+
3+const TAGS = {
4+ id: 41,
5+ link: 42,
6+ func: 43,
7+ mod: 44
8+}
9+
10+const DEFAULTS = {
11+ elem: [],
12+ buf: Buffer.from([]),
13+ id: new cbor.Tagged(TAGS.id, 0),
14+ mod: new cbor.Tagged(TAGS.mod, [{}, new cbor.Tagged(TAGS.id, 0)]),
15+ link: {'/': null},
16+ func: new cbor.Tagged(TAGS.func, 0)
17+}
18+
19+const decoder = new cbor.Decoder({
20+ tags: {
21+ [TAGS.id]: val => new ID(val),
22+ [TAGS.func]: val => new FunctionRef(...val),
23+ [TAGS.mod]: val => new ModuleRef(...val),
24+ }
25+})
26+
27+class Serializable {
28+ serialize () {
29+ const encoder = new cbor.Encoder()
30+ this.encodeCBOR(encoder)
31+ return encoder.finalize()
32+ }
33+
34+ static deserialize (serialized) {
35+ return decoder.decodeFirst(serialized)
36+ }
37+}
38+
39+class FunctionRef extends Serializable {
40+ constructor (privateFunc, identifier, params, id, gas=0) {
41+ super()
42+ this.private = privateFunc
43+ this.identifier = identifier
44+ if (!(id instanceof ID))
45+ id = new ID(id)
46+ this.destId = id
47+ this.params = params
48+ this.gas = gas
49+ }
50+
51+ encodeCBOR (gen) {
52+ return gen.write(new cbor.Tagged(TAGS.func, [
53+ this.private,
54+ this.identifier,
55+ this.params,
56+ this.destId
57+ ]))
58+ }
59+
60+ set container (container) {
61+ this._container = container
62+ }
63+}
64+
65+class ModuleRef extends Serializable {
66+ constructor (ex, id) {
67+ super()
68+ this.exports = ex
69+ this.id = id
70+ }
71+
72+ getFuncRef (name) {
73+ return new FunctionRef(false, name, this.exports[name], this.id)
74+ }
75+
76+ encodeCBOR (gen) {
77+ return gen.write(new cbor.Tagged(TAGS.mod, [this.exports, this.id]))
78+ }
79+
80+ static fromMetaJSON (json, id) {
81+ const exports = {}
82+ for (const ex in json.exports) {
83+ const type = json.types[json.indexes[json.exports[ex].toString()]].params
84+ exports[ex] = type
85+ }
86+ return new ModuleRef(exports, id)
87+ }
88+}
89+
90+class ID extends Serializable {
91+ constructor (id) {
92+ super()
93+ this.id = id
94+ }
95+
96+ encodeCBOR (gen) {
97+ return gen.write(new cbor.Tagged(TAGS.id, this.id))
98+ }
99+}
100+
101+module.exports = {
102+ ID,
103+ FunctionRef,
104+ ModuleRef,
105+ DEFAULTS
106+}

Built with git-ssb-web