Commit d386ffea54d493af4f2eb1eeadc633dd579cdbe3
intial stab at new interface
Signed-off-by: wanderer <mjbecze@gmail.com>wanderer committed on 2/2/2018, 6:56:19 PM
Parent: c779344f6653a07ed5e2695bca74c9cbd0c66a19
Files changed
actor.js | changed |
customTypes.js | changed |
package-lock.json | changed |
package.json | changed |
scheduler.js | changed |
tests/wasm/addTwo.wasm | deleted |
tests/wasm/caller.wasm | added |
tests/wasm/reciever.wasm | added |
tests/wast/addTwo.wast | deleted |
tests/wast/caller.json | added |
tests/wast/caller.wast | added |
tests/wast/reciever.json | added |
tests/wast/reciever.wast | added |
tests/typeChecking.js | added |
tests/wasmContainer.js | deleted |
typeCheckWrapper.js | added |
wasmContainer.js | added |
actor.js | ||
---|---|---|
@@ -18,36 +18,8 @@ | ||
18 | 18 | this.ticks = 0 |
19 | 19 | this.running = false |
20 | 20 | } |
21 | 21 | |
22 | - /** | |
23 | - * adds a message to this actor's message queue | |
24 | - * @param {string} portName | |
25 | - * @param {object} message | |
26 | - */ | |
27 | - queue (message) { | |
28 | - this.inbox.push(message) | |
29 | - | |
30 | - if (!this.running) { | |
31 | - this.running = true | |
32 | - return this._startMessageLoop() | |
33 | - } | |
34 | - } | |
35 | - | |
36 | - // waits for the next message | |
37 | - async _startMessageLoop () { | |
38 | - // this ensure we only every have one loop running at a time | |
39 | - while (this.inbox.length) { | |
40 | - const message = this.inbox.shift() | |
41 | - if (message._fromTicks > this.ticks) { | |
42 | - this.hypervisor.scheduler.update(this.ticks, message._fromTicks) | |
43 | - this.ticks = message._fromTicks | |
44 | - } | |
45 | - await this.runMessage(message) | |
46 | - } | |
47 | - this.running = false | |
48 | - } | |
49 | - | |
50 | 22 | serializeMetaData () { |
51 | 23 | return Actor.serializeMetaData(this.type, this.nonce) |
52 | 24 | } |
53 | 25 | |
@@ -57,25 +29,8 @@ | ||
57 | 29 | destId: this.id |
58 | 30 | } |
59 | 31 | } |
60 | 32 | |
61 | - static serializeMetaData (type, nonce = 0) { | |
62 | - const p = new Pipe() | |
63 | - leb128.write(type, p) | |
64 | - leb128.write(nonce, p) | |
65 | - return p.buffer | |
66 | - } | |
67 | - | |
68 | - static deserializeMetaData (buffer) { | |
69 | - const pipe = new Pipe(buffer) | |
70 | - const type = leb128.read(pipe) | |
71 | - const nonce = leb128.read(pipe) | |
72 | - return { | |
73 | - nonce, | |
74 | - type | |
75 | - } | |
76 | - } | |
77 | - | |
78 | 33 | /** |
79 | 34 | * Runs the shutdown routine for the actor |
80 | 35 | */ |
81 | 36 | async shutdown () { |
@@ -96,8 +51,11 @@ | ||
96 | 51 | * @param {String} method - which method to run |
97 | 52 | * @returns {Promise} |
98 | 53 | */ |
99 | 54 | async runMessage (message) { |
55 | + if (message._fromTicks > this.ticks) { | |
56 | + this.ticks = message._fromTicks | |
57 | + } | |
100 | 58 | try { |
101 | 59 | this.currentMessage = message |
102 | 60 | await this.instance.exports[message.funcRef.name](...message.funcArguments) |
103 | 61 | } catch (e) { |
@@ -110,11 +68,9 @@ | ||
110 | 68 | * updates the number of ticks that the actor has run |
111 | 69 | * @param {Number} count - the number of ticks to add |
112 | 70 | */ |
113 | 71 | incrementTicks (count) { |
114 | - const oldValue = this.ticks | |
115 | 72 | this.ticks += count |
116 | - this.hypervisor.scheduler.update(oldValue, this.ticks) | |
117 | 73 | } |
118 | 74 | |
119 | 75 | /** |
120 | 76 | * creates an actor |
@@ -146,5 +102,22 @@ | ||
146 | 102 | message._fromId = this.id |
147 | 103 | |
148 | 104 | this.hypervisor.scheduler.queue([message]) |
149 | 105 | } |
106 | + | |
107 | + static serializeMetaData (type, nonce = 0) { | |
108 | + const p = new Pipe() | |
109 | + leb128.write(type, p) | |
110 | + leb128.write(nonce, p) | |
111 | + return p.buffer | |
112 | + } | |
113 | + | |
114 | + static deserializeMetaData (buffer) { | |
115 | + const pipe = new Pipe(buffer) | |
116 | + const type = leb128.read(pipe) | |
117 | + const nonce = leb128.read(pipe) | |
118 | + return { | |
119 | + nonce, | |
120 | + type | |
121 | + } | |
122 | + } | |
150 | 123 | } |
customTypes.js | ||
---|---|---|
@@ -59,10 +59,10 @@ | ||
59 | 59 | let numOfEntries = leb.unsigned.read(stream) |
60 | 60 | const json = [] |
61 | 61 | while (numOfEntries--) { |
62 | 62 | json.push({ |
63 | - func: leb.unsigned.read(stream), | |
64 | - type: leb.unsigned.read(stream) | |
63 | + func: leb.unsigned.readBn(stream).toNumber(), | |
64 | + type: leb.unsigned.readBn(stream).toNumber() | |
65 | 65 | }) |
66 | 66 | } |
67 | 67 | return json |
68 | 68 | } |
@@ -126,10 +126,16 @@ | ||
126 | 126 | const body = wasm.subarray(8) |
127 | 127 | return Buffer.concat([preramble, custom, body]) |
128 | 128 | } |
129 | 129 | |
130 | +function inject (wasm, json) { | |
131 | + const buf = encodeJSON(json) | |
132 | + return injectCustomSection(buf, wasm) | |
133 | +} | |
134 | + | |
130 | 135 | module.exports = { |
131 | 136 | injectCustomSection, |
137 | + inject, | |
132 | 138 | decodeType, |
133 | 139 | decodeTypeMap, |
134 | 140 | encodeType, |
135 | 141 | encodeTypeMap, |
package-lock.json | ||
---|---|---|
The diff is too large to show. Use a local git client to view these changes. Old file size: 341262 bytes New file size: 342441 bytes |
package.json | ||
---|---|---|
@@ -33,10 +33,12 @@ | ||
33 | 33 | "binary-search-insert": "^1.0.3", |
34 | 34 | "buffer-pipe": "0.0.2", |
35 | 35 | "events": "^1.1.1", |
36 | 36 | "leb128": "0.0.4", |
37 | + "reference-map": "^1.1.0", | |
37 | 38 | "safe-buffer": "^5.1.1", |
38 | - "wasm-json-toolkit": "^0.2.0" | |
39 | + "wasm-json-toolkit": "^0.2.0", | |
40 | + "wasm-metering": "^0.1.1" | |
39 | 41 | }, |
40 | 42 | "devDependencies": { |
41 | 43 | "coveralls": "^3.0.0", |
42 | 44 | "dfinity-radix-tree": "0.0.9", |
scheduler.js | ||
---|---|---|
@@ -45,22 +45,14 @@ | ||
45 | 45 | this.actors.clear() |
46 | 46 | this.emit('idle') |
47 | 47 | } |
48 | 48 | |
49 | - // enable for concurrency | |
50 | - update (oldTicks, ticks) { | |
51 | - } | |
52 | - | |
53 | 49 | async _processMessage (message) { |
54 | 50 | const to = message.funcRef.destId.toString('hex') |
55 | 51 | let actor = this.actors.get(to) |
56 | 52 | if (!actor) { |
57 | 53 | actor = await this.hypervisor.loadActor(message.funcRef.destId) |
58 | 54 | this.actors.set(to, actor) |
59 | 55 | } |
60 | - const promise = new Promise((resolve, reject) => { | |
61 | - message.on('done', resolve) | |
62 | - }) | |
63 | - actor.queue(message) | |
64 | - return promise | |
56 | + return actor.runMessage(message) | |
65 | 57 | } |
66 | 58 | } |
tests/wast/addTwo.wast | ||
---|---|---|
@@ -1,8 +1,0 @@ | ||
1 | -(module | |
2 | - (func $addTwo (param i32 i32) | |
3 | - get_local 0 | |
4 | - get_local 1 | |
5 | - i32.add | |
6 | - drop | |
7 | - ) | |
8 | - (export "addTwo" (func $addTwo))) |
tests/wast/caller.json | ||
---|---|---|
@@ -1,0 +1,12 @@ | ||
1 | +{ | |
2 | + "type": [{ | |
3 | + "form": "func", | |
4 | + "params": [ | |
5 | + "func" | |
6 | + ] | |
7 | + }], | |
8 | + "typeMap": [{ | |
9 | + "func": 0, | |
10 | + "type": 0 | |
11 | + }] | |
12 | +} |
tests/wast/caller.wast | ||
---|---|---|
@@ -1,0 +1,11 @@ | ||
1 | +(module | |
2 | + (import "func" "internalize" (func $internalize (param i32 i32) (result i32))) | |
3 | + (table (export "table") 1 1 anyfunc) | |
4 | + (func $call (param i32) | |
5 | + i32.const 5 | |
6 | + get_local 0 | |
7 | + i32.const 0 | |
8 | + call $internalize | |
9 | + call_indirect (param i32) | |
10 | + ) | |
11 | + (export "call" (func $call))) |
tests/wast/reciever.wast | ||
---|---|---|
@@ -1,0 +1,8 @@ | ||
1 | +(module | |
2 | + (import "test" "check" (func $check (param i32 i32))) | |
3 | + (func $receive (param i32) | |
4 | + get_local 0 | |
5 | + i32.const 5 | |
6 | + call $check | |
7 | + ) | |
8 | + (export "receive" (func $receive))) |
tests/typeChecking.js | ||
---|---|---|
@@ -1,0 +1,33 @@ | ||
1 | +const customTypes = require('../customTypes.js') | |
2 | +const WasmContainer = require('../wasmContainer.js') | |
3 | +const fs = require('fs') | |
4 | + | |
5 | +async function main () { | |
6 | + let callerJSON = JSON.parse(fs.readFileSync('./wast/caller.json')) | |
7 | + let callerWasm = fs.readFileSync('./wasm/caller.wasm') | |
8 | + callerWasm = customTypes.inject(callerWasm, callerJSON) | |
9 | + | |
10 | + let recieverJSON = JSON.parse(fs.readFileSync('./wast/reciever.json')) | |
11 | + let recieverWasm = fs.readFileSync('./wasm/reciever.wasm') | |
12 | + recieverWasm = customTypes.inject(recieverWasm, recieverJSON) | |
13 | + | |
14 | + const callerContainer = new WasmContainer() | |
15 | + callerContainer.onCreation(callerWasm) | |
16 | + callerJSON = callerContainer.json | |
17 | + | |
18 | + const recieverContainer = new WasmContainer() | |
19 | + recieverContainer.onCreation(recieverWasm) | |
20 | + recieverJSON = recieverContainer.json | |
21 | + | |
22 | + const callFuncRef = callerContainer.getFuncRef('call') | |
23 | + | |
24 | + const funcRef = recieverContainer.getFuncRef('receive') | |
25 | + callFuncRef.args.push({ | |
26 | + type: 'funcRef', | |
27 | + arg: funcRef | |
28 | + }) | |
29 | + | |
30 | + callerContainer.onMessage(callFuncRef) | |
31 | +} | |
32 | + | |
33 | +main() |
tests/wasmContainer.js | ||
---|---|---|
@@ -1,15 +1,0 @@ | ||
1 | -const fs = require('fs') | |
2 | -const tape = require('tape') | |
3 | -const WasmContainer = require('../wasmContainer.js') | |
4 | -// const Message = require('../message.js') | |
5 | -// const Hypervisor = require('../') | |
6 | - | |
7 | -// const level = require('level-browserify') | |
8 | -// const RadixTree = require('dfinity-radix-tree') | |
9 | -// const db = level('./testdb') | |
10 | -tape('basic', async t => { | |
11 | - const addTwoBin = fs.readFileSync(`${__dirname}/wasm/addTwo.wasm`) | |
12 | - const exports = WasmContainer.actorRef(addTwoBin, 'test') | |
13 | - console.log(exports) | |
14 | - t.end() | |
15 | -}) |
typeCheckWrapper.js | ||
---|---|---|
@@ -1,0 +1,166 @@ | ||
1 | +const LANGUAGE_TYPES = { | |
2 | + 'actor': 0x0, | |
3 | + 'buf': 0x1, | |
4 | + 'i32': 0x7f, | |
5 | + 'i64': 0x7e, | |
6 | + 'f32': 0x7d, | |
7 | + 'f64': 0x7c, | |
8 | + 'anyFunc': 0x70, | |
9 | + 'func': 0x60, | |
10 | + 'block_type': 0x40 | |
11 | +} | |
12 | + | |
13 | +module.exports = function generateWrapper (type) { | |
14 | + const module = [{ | |
15 | + 'name': 'preramble', | |
16 | + 'magic': [ | |
17 | + 0, | |
18 | + 97, | |
19 | + 115, | |
20 | + 109 | |
21 | + ], | |
22 | + 'version': [ | |
23 | + 1, | |
24 | + 0, | |
25 | + 0, | |
26 | + 0 | |
27 | + ] | |
28 | + }, { | |
29 | + 'name': 'type', | |
30 | + 'entries': [{ | |
31 | + 'form': 'func', | |
32 | + 'params': [ | |
33 | + ] | |
34 | + }, { | |
35 | + 'form': 'func', | |
36 | + 'params': [ | |
37 | + // imported check | |
38 | + ] | |
39 | + }, { | |
40 | + 'form': 'func', | |
41 | + 'params': [ | |
42 | + // exported check | |
43 | + ] | |
44 | + }, { | |
45 | + 'form': 'func', | |
46 | + 'params': [ | |
47 | + // invoke | |
48 | + ] | |
49 | + }] | |
50 | + }, { | |
51 | + 'name': 'import', | |
52 | + 'entries': [{ | |
53 | + 'moduleStr': 'env', | |
54 | + 'fieldStr': 'checkTypes', | |
55 | + 'kind': 'function', | |
56 | + 'type': 0 | |
57 | + }] | |
58 | + }, { | |
59 | + 'name': 'function', | |
60 | + 'entries': [ | |
61 | + 1, | |
62 | + 2 | |
63 | + ] | |
64 | + }, { | |
65 | + 'name': 'table', | |
66 | + 'entries': [{ | |
67 | + 'elementType': 'anyFunc', | |
68 | + 'limits': { | |
69 | + 'flags': 1, | |
70 | + 'intial': 1, | |
71 | + 'maximum': 1 | |
72 | + } | |
73 | + }] | |
74 | + }, { | |
75 | + 'name': 'global', | |
76 | + 'entries': [] | |
77 | + }, { | |
78 | + 'name': 'export', | |
79 | + 'entries': [{ | |
80 | + 'field_str': 'table', | |
81 | + 'kind': 'table', | |
82 | + 'index': 0 | |
83 | + }, { | |
84 | + 'field_str': 'invoke', | |
85 | + 'kind': 'function', | |
86 | + 'index': 2 | |
87 | + }, { | |
88 | + 'field_str': 'check', | |
89 | + 'kind': 'function', | |
90 | + 'index': 1 | |
91 | + }] | |
92 | + }, { | |
93 | + 'name': 'code', | |
94 | + 'entries': [{ | |
95 | + 'locals': [], | |
96 | + 'code': [] | |
97 | + }, { | |
98 | + 'locals': [], | |
99 | + 'code': [] | |
100 | + }] | |
101 | + }] | |
102 | + const definedTypes = new Set(['actor', 'func', 'buf']) | |
103 | + const setGlobals = [] | |
104 | + const importType = module[1].entries[0].params | |
105 | + const checkType = module[1].entries[1].params | |
106 | + const invokerType = module[1].entries[2].params | |
107 | + const invokeType = module[1].entries[3].params | |
108 | + const checkCode = module[7].entries[0].code | |
109 | + const invokeCode = module[7].entries[1].code | |
110 | + | |
111 | + type.params.forEach((param, index) => { | |
112 | + let baseType = param | |
113 | + const typeCode = LANGUAGE_TYPES[param] | |
114 | + // import type | |
115 | + if (definedTypes.has(param)) { | |
116 | + baseType = 'i32' | |
117 | + } else { | |
118 | + baseType = param | |
119 | + } | |
120 | + | |
121 | + // check import | |
122 | + importType.push('i32') | |
123 | + importType.push('i32') | |
124 | + checkCode.push({ | |
125 | + 'return_type': 'i32', | |
126 | + 'name': 'const', | |
127 | + 'immediates': typeCode | |
128 | + }) | |
129 | + checkCode.push({ | |
130 | + 'name': 'get_local', | |
131 | + 'immediates': index | |
132 | + }) | |
133 | + invokeCode.push({ | |
134 | + 'name': 'get_local', | |
135 | + 'immediates': index | |
136 | + }) | |
137 | + // check export | |
138 | + checkType.push(baseType) | |
139 | + // invoke | |
140 | + invokeType.push(baseType) | |
141 | + invokerType.push(baseType) | |
142 | + }) | |
143 | + | |
144 | + module[7].entries[0].code = checkCode.concat(setGlobals, [{ | |
145 | + 'name': 'call', | |
146 | + 'immediates': '0' | |
147 | + }, { | |
148 | + 'name': 'end' | |
149 | + }]) | |
150 | + invokeCode.push({ | |
151 | + 'return_type': 'i32', | |
152 | + 'name': 'const', | |
153 | + 'immediates': '0' | |
154 | + }) | |
155 | + invokeCode.push({ | |
156 | + 'name': 'call_indirect', | |
157 | + 'immediates': { | |
158 | + 'index': 3, | |
159 | + 'reserved': 0 | |
160 | + } | |
161 | + }) | |
162 | + invokeCode.push({ | |
163 | + 'name': 'end' | |
164 | + }) | |
165 | + return module | |
166 | +} |
wasmContainer.js | ||
---|---|---|
@@ -1,0 +1,227 @@ | ||
1 | +const {wasm2json, json2wasm} = require('wasm-json-toolkit') | |
2 | +const wasmMetering = require('wasm-metering') | |
3 | +const customTypes = require('./customTypes.js') | |
4 | +const typeCheckWrapper = require('./typeCheckWrapper.js') | |
5 | +const ReferanceMap = require('reference-map') | |
6 | + | |
7 | +const nativeTypes = new Set(['i32', 'i64', 'f32', 'f64']) | |
8 | +const LANGUAGE_TYPES = { | |
9 | + 'actor': 0x0, | |
10 | + 'buf': 0x1, | |
11 | + 'i32': 0x7f, | |
12 | + 'i64': 0x7e, | |
13 | + 'f32': 0x7d, | |
14 | + 'f64': 0x7c, | |
15 | + 'anyFunc': 0x70, | |
16 | + 'func': 0x60, | |
17 | + 'block_type': 0x40, | |
18 | + | |
19 | + 0x0: 'actor', | |
20 | + 0x1: 'buf', | |
21 | + 0x7f: 'i32', | |
22 | + 0x7e: 'i64', | |
23 | + 0x7d: 'f32', | |
24 | + 0x7c: 'f64', | |
25 | + 0x70: 'anyFunc', | |
26 | + 0x60: 'func', | |
27 | + 0x40: 'block_type' | |
28 | +} | |
29 | + | |
30 | +class Ref { | |
31 | + serialize () {} | |
32 | +} | |
33 | + | |
34 | +class FunctionRef { | |
35 | + constructor (json, name) { | |
36 | + this.name = name | |
37 | + this.args = [] | |
38 | + const typeIndex = json.typeMap[name] | |
39 | + const type = json.type[typeIndex] | |
40 | + const wrapper = typeCheckWrapper(type) | |
41 | + const wasm = json2wasm(wrapper) | |
42 | + this.mod = WebAssembly.Module(wasm) | |
43 | + const self = this | |
44 | + const instance = WebAssembly.Instance(this.mod, { | |
45 | + 'env': { | |
46 | + 'checkTypes': function () { | |
47 | + const args = [...arguments] | |
48 | + while (args.length) { | |
49 | + const type = LANGUAGE_TYPES[args.shift()] | |
50 | + let arg = args.shift() | |
51 | + if (!nativeTypes.has(type)) { | |
52 | + arg = self._container.refs.get(arg) | |
53 | + if (arg.type !== type) { | |
54 | + throw new Error('invalid type') | |
55 | + } | |
56 | + } | |
57 | + self.args.push({ | |
58 | + arg, | |
59 | + type | |
60 | + }) | |
61 | + } | |
62 | + self._container.sendMessage(instance) | |
63 | + } | |
64 | + } | |
65 | + }) | |
66 | + this.wrapper = instance | |
67 | + } | |
68 | + set container (container) { | |
69 | + this._container = container | |
70 | + } | |
71 | +} | |
72 | + | |
73 | +module.exports = class WasmContainer { | |
74 | + constructor () { | |
75 | + this.refs = new ReferanceMap() | |
76 | + } | |
77 | + onCreation (wasm) { | |
78 | + let moduleJSON = wasm2json(wasm) | |
79 | + this.json = mergeTypeSections(moduleJSON) | |
80 | + moduleJSON = wasmMetering.meterJSON(moduleJSON, { | |
81 | + meterType: 'i32' | |
82 | + }) | |
83 | + this.wasm = json2wasm(moduleJSON) | |
84 | + this.mod = WebAssembly.Module(this.wasm) | |
85 | + } | |
86 | + | |
87 | + sendMessage () { | |
88 | + console.log('send') | |
89 | + } | |
90 | + | |
91 | + onMessage (funcRef) { | |
92 | + const self = this | |
93 | + const instance = WebAssembly.Instance(this.mod, { | |
94 | + func: { | |
95 | + externalize: () => {}, | |
96 | + internalize: (ref, index) => { | |
97 | + const {type, arg} = self.refs.get(ref, FunctionRef) | |
98 | + arg.container = self | |
99 | + instance.exports.table.set(index, arg.wrapper.exports.check) | |
100 | + }, | |
101 | + catch: (ref, catchRef) => { | |
102 | + const {funcRef} = self.refs.get(ref, FunctionRef) | |
103 | + const {funcRef: catchFunc} = self.refs.get(ref, FunctionRef) | |
104 | + funcRef.catch = catchFunc | |
105 | + }, | |
106 | + getGasAmount: () => {}, | |
107 | + setGasAmount: () => {} | |
108 | + }, | |
109 | + storage: { | |
110 | + load: () => {}, | |
111 | + store: () => {}, | |
112 | + delete: () => {} | |
113 | + }, | |
114 | + link: { | |
115 | + wrap: (ref) => { | |
116 | + const obj = this.refs.get(ref) | |
117 | + obj.seriarlize() | |
118 | + }, | |
119 | + unwrap: () => {} | |
120 | + }, | |
121 | + databuf: { | |
122 | + create: () => {}, | |
123 | + load8: () => {}, | |
124 | + load16: () => {}, | |
125 | + load32: () => {}, | |
126 | + load64: () => {}, | |
127 | + store8: () => {}, | |
128 | + store16: () => {}, | |
129 | + store32: () => {}, | |
130 | + store64: () => {}, | |
131 | + copy: () => {} | |
132 | + }, | |
133 | + elembuf: { | |
134 | + create: () => {}, | |
135 | + load: () => {}, | |
136 | + store: () => {}, | |
137 | + delete: () => {} | |
138 | + }, | |
139 | + test: { | |
140 | + check: (a, b) => { | |
141 | + console.log('$$$$', a, b) | |
142 | + } | |
143 | + }, | |
144 | + metering: { | |
145 | + usegas: () => {} | |
146 | + } | |
147 | + }) | |
148 | + const args = funcRef.args.map(arg => { | |
149 | + if (nativeTypes.has(arg.type)) { | |
150 | + return arg.arg | |
151 | + } else { | |
152 | + return this.refs.add(arg) | |
153 | + } | |
154 | + }) | |
155 | + instance.exports[funcRef.name](...args) | |
156 | + } | |
157 | + | |
158 | + getFuncRef (name, send) { | |
159 | + const funcRef = new FunctionRef(this.json, name, send) | |
160 | + return funcRef | |
161 | + } | |
162 | +} | |
163 | + | |
164 | +function mergeTypeSections (json) { | |
165 | + const typeInfo = {} | |
166 | + let typeSection = { | |
167 | + 'entries': [] | |
168 | + } | |
169 | + let importSection = { | |
170 | + 'entries': [] | |
171 | + } | |
172 | + let functionSection = { | |
173 | + 'entries': [] | |
174 | + } | |
175 | + let exportSection = { | |
176 | + 'entries': [] | |
177 | + } | |
178 | + json.forEach(section => { | |
179 | + switch (section.name) { | |
180 | + case 'type': | |
181 | + typeSection = section | |
182 | + break | |
183 | + case 'export': | |
184 | + exportSection = section | |
185 | + break | |
186 | + case 'import': | |
187 | + importSection = section | |
188 | + break | |
189 | + case 'function': | |
190 | + functionSection = section | |
191 | + break | |
192 | + case 'custom': | |
193 | + switch (section.sectionName) { | |
194 | + case 'type': | |
195 | + typeInfo.type = customTypes.decodeType(section.payload) | |
196 | + break | |
197 | + case 'typeMap': | |
198 | + typeInfo.typeMap = customTypes.decodeTypeMap(section.payload) | |
199 | + break | |
200 | + } | |
201 | + break | |
202 | + } | |
203 | + }) | |
204 | + | |
205 | + const foundTypes = new Map() | |
206 | + const mappedFuncs = new Map() | |
207 | + const newTypeMap = {} | |
208 | + typeInfo.typeMap.forEach(map => mappedFuncs.set(map.func, map.type)) | |
209 | + for (let exprt of exportSection.entries) { | |
210 | + if (exprt.kind === 'function') { | |
211 | + if (!mappedFuncs.has(exprt.index)) { | |
212 | + const typeIndex = functionSection.entries[exprt.index - importSection.entries.length] | |
213 | + if (!foundTypes.has(typeIndex)) { | |
214 | + const customIndex = typeInfo.type.push(typeSection.entries[typeIndex]) - 1 | |
215 | + foundTypes.set(typeIndex, customIndex) | |
216 | + } | |
217 | + const customIndex = foundTypes.get(typeIndex) | |
218 | + newTypeMap[exprt.field_str] = customIndex | |
219 | + } else { | |
220 | + newTypeMap[exprt.field_str] = mappedFuncs.get(exprt.index) | |
221 | + } | |
222 | + } | |
223 | + } | |
224 | + | |
225 | + typeInfo.typeMap = newTypeMap | |
226 | + return typeInfo | |
227 | +} |
Built with git-ssb-web