git ssb

0+

wanderer🌟 / js-primea-hypervisor



Commit 7c6e94b073aaac86243093e7d533ecd1cbdb587d

seprated out id

Signed-off-by: wanderer <mjbecze@gmail.com>
wanderer committed on 2/28/2018, 8:30:54 PM
Parent: 918662450986924c9a68f772d475dc794e4d7127

Files changed

actor.jschanged
index.jschanged
message.jschanged
package-lock.jsonchanged
package.jsonchanged
scheduler.jschanged
tests/index.jschanged
tests/wasmContainer.jschanged
wasmContainer.jschanged
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
@@ -105,18 +102,12 @@
105102 this.hypervisor.scheduler.queue([message])
106103 }
107104
108105 static serializeMetaData (type, nonce = 0) {
109- const p = new Pipe()
110- leb128.write(type, p)
111- leb128.write(nonce, p)
112- return p.buffer
106+ return [type, nonce]
113107 }
114108
115- static deserializeMetaData (buffer) {
116- const pipe = new Pipe(buffer)
117- const type = leb128.read(pipe)
118- const nonce = leb128.read(pipe)
109+ static deserializeMetaData ([type, nonce]) {
119110 return {
120111 nonce,
121112 type
122113 }
index.jsView
@@ -1,6 +1,7 @@
11 const Actor = require('./actor.js')
22 const Scheduler = require('./scheduler.js')
3+const {ID} = require('./systemObjects.js')
34
45 module.exports = class Hypervisor {
56 /**
67 * The Hypervisor manages the container instances by instantiating them and
@@ -27,9 +28,9 @@
2728 this.scheduler.queue(messages)
2829 }
2930
3031 async loadActor (id) {
31- const state = await this.tree.getSubTree(id)
32+ const state = await this.tree.getSubTree(id.id)
3233 const code = state.get(Buffer.from([0]))
3334 const {type, nonce} = Actor.deserializeMetaData(state.root['/'][3])
3435 const Container = this._containerTypes[type]
3536
@@ -57,16 +58,17 @@
5758 */
5859 async createActor (type, code, id = {nonce: this.nonce++, parent: null}) {
5960 const Container = this._containerTypes[type]
6061 const encoded = encodedID(id)
61- const idHash = await this._getHashFromObj(encoded)
62- const module = await Container.onCreation(code, idHash, this.tree.dag._dag)
62+ let idHash = await this._getHashFromObj(encoded)
63+ idHash = new ID(idHash)
64+ const module = await Container.onCreation(code, idHash, this.tree)
6365 const metaData = Actor.serializeMetaData(type)
6466
6567 // save the container in the state
66- this.tree.set(idHash, metaData)
68+ this.tree.set(idHash.id, metaData)
6769 if (code) {
68- this.tree.set(Buffer.concat([idHash, Buffer.from([0])]), code)
70+ this.tree.set(Buffer.concat([idHash.id, Buffer.from([0])]), code)
6971 }
7072 return {
7173 id: idHash,
7274 module: module
@@ -105,9 +107,9 @@
105107
106108 function encodedID (id) {
107109 const nonce = Buffer.from([id.nonce])
108110 if (id.parent) {
109- return Buffer.concat([nonce, id.parent])
111+ return Buffer.concat([nonce, id.parent.id])
110112 } else {
111113 return nonce
112114 }
113115 }
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: 336834 bytes
New file size: 338011 bytes
package.jsonView
@@ -28,13 +28,11 @@
2828 "author": "mjbecze <mjbecze@gmail.com>",
2929 "contributors": "Alex Beregszaszi <alex@rtfs.hu>",
3030 "license": "MPL-2.0",
3131 "dependencies": {
32- "binary-search": "^1.3.3",
3332 "binary-search-insert": "^1.0.3",
34- "buffer-pipe": "0.0.2",
33+ "borc": "^2.0.2",
3534 "events": "^2.0.0",
36- "leb128": "0.0.4",
3735 "levelup": "^2.0.2",
3836 "reference-map": "^1.2.1",
3937 "safe-buffer": "^5.1.1",
4038 "wasm-json-toolkit": "^0.2.2",
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('a5e1aaebec14b7f144d6a7e007b148aa7c56804c', '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('bc0af44b691ef57b362df8b11c274742147900cd', '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('86e066f60fe2f722befbc29f128948f6487a207a', '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('86e066f60fe2f722befbc29f128948f6487a207a', '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('bc0af44b691ef57b362df8b11c274742147900cd', '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('544ae05bc8831cc69c5524bc3a51c0d4806e9d60', 'hex')
273273 }
274274
275275 const tree = new RadixTree({
276276 db: db
@@ -308,14 +308,15 @@
308308 await hypervisor.send(new Message({funcRef: module.start}))
309309
310310 const stateRoot = await hypervisor.createStateRoot()
311311 t.deepEquals(stateRoot, expectedState, 'expected root!')
312+ t.end()
312313 })
313314
314315 tape('simple message arbiter test', async t => {
315316 t.plan(4)
316317 const expectedState = {
317- '/': Buffer.from('a4c7ceacd8c867ae1d0b472d8bffa3cb10048331', 'hex')
318+ '/': Buffer.from('bc0af44b691ef57b362df8b11c274742147900cd', 'hex')
318319 }
319320
320321 const tree = new RadixTree({
321322 db: db
@@ -382,9 +383,9 @@
382383 tape('arbiter test for id comparision', async t => {
383384 t.plan(4)
384385 let message
385386 const expectedState = {
386- '/': Buffer.from('4633ac4b9f8212e501b6c56906039ec081fbe5a3', 'hex')
387+ '/': Buffer.from('86e066f60fe2f722befbc29f128948f6487a207a', 'hex')
387388 }
388389
389390 const tree = new RadixTree({
390391 db: db
@@ -449,9 +450,9 @@
449450
450451 tape('async work', async t => {
451452 t.plan(3)
452453 const expectedState = {
453- '/': Buffer.from('a4c7ceacd8c867ae1d0b472d8bffa3cb10048331', 'hex')
454+ '/': Buffer.from('bc0af44b691ef57b362df8b11c274742147900cd', 'hex')
454455 }
455456
456457 const tree = new RadixTree({
457458 db: db
tests/wasmContainer.jsView
@@ -157,9 +157,9 @@
157157 })
158158 hypervisor.send(message)
159159 })
160160
161-tape.skip('store globals', async t => {
161+tape('load / store globals', async t => {
162162 t.plan(1)
163163 tester = t
164164 const tree = new RadixTree({
165165 db
@@ -176,11 +176,8 @@
176176 const message = new Message({
177177 funcRef: module.getFuncRef('store')
178178 }).on('done', actor => {
179179 resolve()
180- // const a = actor.container.getMemory(0, 8)
181- // const b = actor.container.getMemory(8, 8)
182- // t.deepEquals(a, b, 'should copy memory correctly')
183180 })
184181 hypervisor.send(message)
185182 })
186183
@@ -188,11 +185,11 @@
188185 const message = new Message({
189186 funcRef: module.getFuncRef('load')
190187 }).on('done', actor => {
191188 resolve()
192- // const a = actor.container.getMemory(0, 8)
193- // const b = actor.container.getMemory(8, 8)
194- // t.deepEquals(a, b, 'should copy memory correctly')
189+ const b = actor.container.getMemory(5, 4)
190+ const result = Buffer.from(b).toString()
191+ t.deepEquals(result, 'test', 'should copy memory correctly')
195192 })
196193 hypervisor.send(message)
197194 })
198195 })
wasmContainer.jsView
@@ -4,9 +4,27 @@
44 const Message = require('./message.js')
55 const customTypes = require('./customTypes.js')
66 const injectGlobals = require('./injectGlobals.js')
77 const typeCheckWrapper = require('./typeCheckWrapper.js')
8+const {FunctionRef} = require('./systemObjects.js')
9+const cbor = require('borc')
810
11+const TAGS = {
12+ link: 42,
13+ id: 43,
14+ func: 43,
15+ mod: 44
16+}
17+
18+const DEFAULTS = {
19+ elem: [],
20+ buf: Buffer.from([]),
21+ id: new cbor.Tagged(TAGS.id, 0),
22+ mod: new cbor.Tagged(TAGS.mod, [{}, new cbor.Tagged(TAGS.id, 0)]),
23+ link: {'/': null},
24+ func: new cbor.Tagged(TAGS.func, 0)
25+}
26+
927 const nativeTypes = new Set(['i32', 'i64', 'f32', 'f64'])
1028 const LANGUAGE_TYPES = {
1129 'actor': 0x0,
1230 'buf': 0x1,
@@ -34,56 +52,36 @@
3452 0x60: 'func',
3553 0x40: 'block_type'
3654 }
3755
38-class FunctionRef {
39- constructor (location, identifier, params, id) {
40- this.location = location
41- this.identifier = identifier
42- this.destId = id
43- this.params = params
44-
45- }
46-
47- generateWrapper (container) {
48- let wrapper = typeCheckWrapper(this.params)
49- const wasm = json2wasm(wrapper)
50- const mod = WebAssembly.Module(wasm)
51- const self = this
52- wrapper = WebAssembly.Instance(mod, {
53- 'env': {
54- 'checkTypes': function () {
55- const args = [...arguments]
56- const checkedArgs = []
57- while (args.length) {
58- const type = LANGUAGE_TYPES[args.shift()]
59- let arg = args.shift()
60- if (!nativeTypes.has(type)) {
61- arg = container.refs.get(arg, type)
62- }
63- checkedArgs.push(arg)
56+function generateWrapper (funcRef, container) {
57+ let wrapper = typeCheckWrapper(funcRef.params)
58+ const wasm = json2wasm(wrapper)
59+ const mod = WebAssembly.Module(wasm)
60+ const self = funcRef
61+ wrapper = WebAssembly.Instance(mod, {
62+ 'env': {
63+ 'checkTypes': function () {
64+ const args = [...arguments]
65+ const checkedArgs = []
66+ while (args.length) {
67+ const type = LANGUAGE_TYPES[args.shift()]
68+ let arg = args.shift()
69+ if (!nativeTypes.has(type)) {
70+ arg = container.refs.get(arg, type)
6471 }
65- const message = new Message({
66- funcRef: self,
67- funcArguments: checkedArgs
68- })
69- container.actor.send(message)
72+ checkedArgs.push(arg)
7073 }
74+ const message = new Message({
75+ funcRef: self,
76+ funcArguments: checkedArgs
77+ })
78+ container.actor.send(message)
7179 }
72- })
73- wrapper.exports.check.object = this
74- return wrapper
75- }
76-
77- encodeCBOR (gen) {
78- return gen.write({
79- '>': {}
80- })
81- }
82-
83- set container (container) {
84- this._container = container
85- }
80+ }
81+ })
82+ wrapper.exports.check.object = funcRef
83+ return wrapper
8684 }
8785
8886 class ModuleRef {
8987 constructor (ex, id) {
@@ -91,20 +89,13 @@
9189 this.id = id
9290 }
9391
9492 getFuncRef (name) {
95- return new FunctionRef('export', name, this.exports[name], this.id)
93+ return new FunctionRef(false, name, this.exports[name], this.id)
9694 }
9795
9896 encodeCBOR (gen) {
99- return gen.write({
100- '#': {
101- exports: this.exports,
102- id: {
103- '@': this.id
104- }
105- }
106- })
97+ return gen.write(new cbor.Tagged(TAGS.mod, [this.exports, new cbor.Tagged(TAGS.id, this.id)]))
10798 }
10899
109100 static fromMetaJSON (json, id) {
110101 const exports = {}
@@ -123,27 +114,38 @@
123114 this.actor = actor
124115 this.refs = new ReferanceMap()
125116 }
126117
127- static async onCreation (wasm, id, cachedb) {
118+ static async onCreation (wasm, id, tree) {
119+ const cachedb = tree.dag._dag
128120 if (!WebAssembly.validate(wasm)) {
129121 throw new Error('invalid wasm binary')
130122 }
131123 let moduleJSON = wasm2json(wasm)
132124 const json = customTypes.mergeTypeSections(moduleJSON)
133125 moduleJSON = wasmMetering.meterJSON(moduleJSON, {
134126 meterType: 'i32'
135127 })
136- if (json.globals.length) {
128+
129+ // initialize the globals
130+ let numOfGlobals = json.globals.length
131+ if (numOfGlobals) {
137132 moduleJSON = injectGlobals(moduleJSON, json.globals)
133+ const storage = []
134+ while (numOfGlobals--) {
135+ const type = json.globals[numOfGlobals].type
136+ storage.push(DEFAULTS[type])
137+ }
138+ tree.set(Buffer.concat([id.id, Buffer.from([1])]), storage)
138139 }
140+ // recompile the wasm
139141 wasm = json2wasm(moduleJSON)
140142 await Promise.all([
141143 new Promise((resolve, reject) => {
142- cachedb.put(id.toString() + 'meta', JSON.stringify(json), resolve)
144+ cachedb.put(id.id.toString() + 'meta', JSON.stringify(json), resolve)
143145 }),
144146 new Promise((resolve, reject) => {
145- cachedb.put(id.toString() + 'code', wasm.toString('hex'), resolve)
147+ cachedb.put(id.id.toString() + 'code', wasm.toString('hex'), resolve)
146148 })
147149 ])
148150 return ModuleRef.fromMetaJSON(json, id)
149151 }
@@ -157,16 +159,20 @@
157159 const object = func.object
158160 if (object) {
159161 return self.refs.add(object)
160162 } else {
161- const ref = new FunctionRef('table', object.tableIndex, self.json, self.actor.id)
163+ const ref = new FunctionRef(true, object.tableIndex, self.json, self.actor.id)
162164 return self.refs.add(ref)
163165 }
164166 },
165167 internalize: (ref, index) => {
166168 const funcRef = self.refs.get(ref, 'func')
167- const wrapper = funcRef.generateWrapper(self)
168- this.instance.exports.table.set(index, wrapper.exports.check)
169+ try {
170+ const wrapper = generateWrapper(funcRef, self)
171+ this.instance.exports.table.set(index, wrapper.exports.check)
172+ } catch (e) {
173+ console.log(e)
174+ }
169175 },
170176 catch: (ref, catchRef) => {
171177 const {funcRef} = self.refs.get(ref, FunctionRef)
172178 const {funcRef: catchFunc} = self.refs.get(ref, FunctionRef)
@@ -242,12 +248,12 @@
242248 }
243249 }
244250
245251 async onMessage (message) {
246- try {
247252 const funcRef = message.funcRef
248253 const intef = this.getInterface(funcRef)
249254 this.instance = WebAssembly.Instance(this.mod, intef)
255+ // map table indexes
250256 const table = this.instance.exports.table
251257 if (table) {
252258 let length = table.length
253259 while (length--) {
@@ -256,39 +262,51 @@
256262 func.tableIndex = length
257263 }
258264 }
259265 }
266+ // import references
260267 const args = message.funcArguments.map((arg, index) => {
261268 const type = funcRef.params[index]
262269 if (nativeTypes.has(type)) {
263270 return arg
264271 } else {
265272 return this.refs.add(arg, type)
266273 }
267274 })
268- if (funcRef.location === 'export') {
275+
276+ // setup globals
277+ let numOfGlobals = this.json.globals.length
278+ if (numOfGlobals) {
279+ const refs = []
280+ while (numOfGlobals--) {
281+ const obj = this.storage[numOfGlobals]
282+ refs.push(this.refs.add(obj, this.json.globals[numOfGlobals].type))
283+ }
284+ this.instance.exports.setter_globals(...refs)
285+ }
286+
287+ // call entrypoint function
288+ if (funcRef.private) {
289+ this.instance.exports.table.get(funcRef.identifier)(...args)
290+ } else {
269291 this.instance.exports[funcRef.identifier](...args)
270- } else {
271- this.instance.exports.table.get(funcRef.identifier)(...args)
272292 }
273293 await this.onDone()
274294
275- let numOfGlobals = this.json.globals.length
295+ numOfGlobals = this.json.globals.length
276296 if (numOfGlobals) {
277- const storage = []
297+ this.storage = []
278298 this.instance.exports.getter_globals()
279299 const mem = new Uint32Array(this.instance.exports.memory.buffer, 0, numOfGlobals)
280300 while (numOfGlobals--) {
281301 const ref = mem[numOfGlobals]
282- storage.push(this.refs.get(ref, this.json.globals[numOfGlobals].type))
302+ this.storage.push(this.refs.get(ref, this.json.globals[numOfGlobals].type))
283303 }
284- this.actor.state.set(Buffer.from([1]), storage)
304+
305+ this.actor.state.set(Buffer.from([1]), this.storage)
285306 }
286307
287308 this.refs.clear()
288- } catch (e) {
289- console.log(e)
290- }
291309 }
292310
293311 /**
294312 * returns a promise that resolves when the wasm instance is done running
@@ -312,35 +330,41 @@
312330 return this._opsQueue
313331 }
314332
315333 async onStartup () {
316- let [json, wasm] = await Promise.all([
334+ let [json, wasm, storage] = await Promise.all([
317335 new Promise((resolve, reject) => {
318- this.actor.cachedb.get(this.actor.id.toString() + 'meta', (err, json) => {
336+ this.actor.cachedb.get(this.actor.id.id.toString() + 'meta', (err, json) => {
319337 if (err) {
320338 reject(err)
321339 } else {
322340 resolve(json)
323341 }
324342 })
325343 }),
326344 new Promise((resolve, reject) => {
327- this.actor.cachedb.get(this.actor.id.toString() + 'code', (err, wasm) => {
345+ this.actor.cachedb.get(this.actor.id.id.toString() + 'code', (err, wasm) => {
328346 if (err) {
329347 reject(err)
330348 } else {
331349 resolve(wasm)
332350 }
333351 })
334- })
352+ }),
353+ this.actor.state.get(Buffer.from([1]))
335354 ])
355+ this.storage = storage
336356 wasm = Buffer.from(wasm, 'hex')
337357 json = JSON.parse(json)
338358 this.mod = WebAssembly.Module(wasm)
339359 this.json = json
340360 this.modSelf = ModuleRef.fromMetaJSON(json, this.actor.id)
341361 }
342362
363+ onShutdown () {
364+
365+ }
366+
343367 getMemory (offset, length) {
344368 return new Uint8Array(this.instance.exports.memory.buffer, offset, length)
345369 }
346370

Built with git-ssb-web