git ssb

0+

wanderer🌟 / js-primea-hypervisor



Tree: 225da49428f17d7ef0fc980e3dbd3cda8967ae99

Files: 225da49428f17d7ef0fc980e3dbd3cda8967ae99 / customTypes.js

5655 bytesRaw
1const Stream = require('buffer-pipe')
2const leb = require('leb128')
3const {findSections} = require('wasm-json-toolkit')
4
5const LANGUAGE_TYPES = {
6 'actor': 0x0,
7 'buf': 0x1,
8 'i32': 0x7f,
9 'i64': 0x7e,
10 'f32': 0x7d,
11 'f64': 0x7c,
12 'anyFunc': 0x70,
13 'func': 0x60,
14 'block_type': 0x40,
15
16 0x0: 'actor',
17 0x1: 'buf',
18 0x7f: 'i32',
19 0x7e: 'i64',
20 0x7d: 'f32',
21 0x7c: 'f64',
22 0x70: 'anyFunc',
23 0x60: 'func',
24 0x40: 'block_type'
25}
26
27function encodeJSON (json) {
28 const stream = new Stream()
29 encodeCustomSection('types', json, stream, encodeType)
30 encodeCustomSection('typeMap', json, stream, encodeTypeMap)
31 encodeCustomSection('globals', json, stream, encodeGlobals)
32
33 return stream.buffer
34}
35
36function encodeCustomSection (name, json, stream, encodingFunc) {
37 let payload = new Stream()
38 json = json[name]
39
40 if (json) {
41 stream.write([0])
42 // encode type
43 leb.unsigned.write(name.length, payload)
44 payload.write(name)
45 encodingFunc(json, payload)
46 // write the size of the payload
47 leb.unsigned.write(payload.bytesWrote, stream)
48 stream.write(payload.buffer)
49 }
50 return stream
51}
52
53function encodeGlobals (json, stream) {
54 leb.unsigned.write(json.length, stream)
55 for (const entry of json) {
56 leb.unsigned.write(entry.index, stream)
57 leb.unsigned.write(LANGUAGE_TYPES[entry.type], stream)
58 }
59 return stream
60}
61
62function decodeGlobals (buf) {
63 const stream = new Stream(Buffer.from(buf))
64 let numOfEntries = leb.unsigned.read(stream)
65 const json = []
66 while (numOfEntries--) {
67 json.push({
68 index: leb.unsigned.readBn(stream).toNumber(),
69 type: LANGUAGE_TYPES[leb.unsigned.readBn(stream).toNumber()]
70 })
71 }
72 return json
73}
74
75function encodeTypeMap (json, stream) {
76 leb.unsigned.write(json.length, stream)
77 for (let entry of json) {
78 leb.unsigned.write(entry.func, stream)
79 leb.unsigned.write(entry.type, stream)
80 }
81 return stream
82}
83
84function decodeTypeMap (buf) {
85 const stream = new Stream(Buffer.from(buf))
86 let numOfEntries = leb.unsigned.read(stream)
87 const json = []
88 while (numOfEntries--) {
89 json.push({
90 func: leb.unsigned.readBn(stream).toNumber(),
91 type: leb.unsigned.readBn(stream).toNumber()
92 })
93 }
94 return json
95}
96
97function encodeType (json, stream = new Stream()) {
98 let binEntries = new Stream()
99
100 leb.unsigned.write(json.length, binEntries)
101 for (let entry of json) {
102 // a single type entry binary encoded
103 binEntries.write([LANGUAGE_TYPES[entry.form]]) // the form
104
105 const len = entry.params.length // number of parameters
106 leb.unsigned.write(len, binEntries)
107 if (len !== 0) {
108 binEntries.write(entry.params.map(type => LANGUAGE_TYPES[type])) // the paramter types
109 }
110
111 binEntries.write([entry.return_type ? 1 : 0]) // number of return types
112 if (entry.return_type) {
113 binEntries.write([LANGUAGE_TYPES[entry.return_type]])
114 }
115 }
116
117 stream.write(binEntries.buffer)
118 return stream
119}
120
121function decodeType (buf) {
122 const stream = new Stream(Buffer.from(buf))
123 const numberOfEntries = leb.unsigned.readBn(stream).toNumber()
124 const json = []
125 for (let i = 0; i < numberOfEntries; i++) {
126 let type = stream.read(1)[0]
127 const entry = {
128 form: LANGUAGE_TYPES[type],
129 params: []
130 }
131
132 let paramCount = leb.unsigned.readBn(stream).toNumber()
133
134 // parse the entries
135 while (paramCount--) {
136 const type = stream.read(1)[0]
137 entry.params.push(LANGUAGE_TYPES[type])
138 }
139 const numOfReturns = leb.unsigned.readBn(stream).toNumber()
140 if (numOfReturns) {
141 type = stream.read(1)[0]
142 entry.return_type = LANGUAGE_TYPES[type]
143 }
144
145 json.push(entry)
146 }
147 return json
148}
149
150function injectCustomSection (custom, wasm) {
151 const preramble = wasm.subarray(0, 8)
152 const body = wasm.subarray(8)
153 return Buffer.concat([preramble, custom, body])
154}
155
156function inject (wasm, json) {
157 const buf = encodeJSON(json)
158 return injectCustomSection(buf, wasm)
159}
160
161function mergeTypeSections (json) {
162 const result = {
163 types: [],
164 indexes: {},
165 exports: {},
166 globals: []
167 }
168
169 const wantedSections = ['types', 'typeMap', 'globals', 'type', 'import', 'function', 'export']
170 const iterator = findSections(json, wantedSections)
171 const mappedFuncs = new Map()
172 const mappedTypes = new Map()
173 const {value: customType} = iterator.next()
174 if (customType) {
175 const type = decodeType(customType.payload)
176 result.types = type
177 }
178 let {value: typeMap} = iterator.next()
179 if (typeMap) {
180 decodeTypeMap(typeMap.payload).forEach(map => mappedFuncs.set(map.func, map.type))
181 }
182
183 let {value: globals} = iterator.next()
184 if (globals) {
185 result.globals = decodeGlobals(globals.payload)
186 }
187
188 const {value: type} = iterator.next()
189 const {value: imports = {entries: []}} = iterator.next()
190 const {value: functions} = iterator.next()
191 functions.entries.forEach((typeIndex, funcIndex) => {
192 let customIndex = mappedFuncs.get(funcIndex)
193 if (customIndex === undefined) {
194 customIndex = mappedTypes.get(typeIndex)
195 }
196 if (customIndex === undefined) {
197 customIndex = result.types.push(type.entries[typeIndex]) - 1
198 mappedTypes.set(typeIndex, customIndex)
199 }
200 result.indexes[funcIndex + imports.entries.length] = customIndex
201 })
202
203 const {value: exports = {entries: []}} = iterator.next()
204 exports.entries.forEach(entry => {
205 if (entry.kind === 'function') {
206 result.exports[entry.field_str] = entry.index
207 }
208 })
209 return result
210}
211
212module.exports = {
213 injectCustomSection,
214 inject,
215 decodeType,
216 decodeTypeMap,
217 decodeGlobals,
218 encodeType,
219 encodeTypeMap,
220 encodeJSON,
221 mergeTypeSections
222}
223

Built with git-ssb-web