git ssb

0+

wanderer🌟 / js-primea-hypervisor



Tree: cd5644a350c66679340731cc00c9fcf16834bdb9

Files: cd5644a350c66679340731cc00c9fcf16834bdb9 / customTypes.js

5501 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, stream)
57 }
58 return stream
59}
60
61function decodeGlobals (buf) {
62 const stream = new Stream(Buffer.from(buf))
63 let numOfEntries = leb.unsigned.read(stream)
64 const json = []
65 while (numOfEntries--) {
66 json.push(leb.unsigned.readBn(stream).toNumber())
67 }
68 return json
69}
70
71function encodeTypeMap (json, stream) {
72 leb.unsigned.write(json.length, stream)
73 for (let entry of json) {
74 leb.unsigned.write(entry.func, stream)
75 leb.unsigned.write(entry.type, stream)
76 }
77 return stream
78}
79
80function decodeTypeMap (buf) {
81 const stream = new Stream(Buffer.from(buf))
82 let numOfEntries = leb.unsigned.read(stream)
83 const json = []
84 while (numOfEntries--) {
85 json.push({
86 func: leb.unsigned.readBn(stream).toNumber(),
87 type: leb.unsigned.readBn(stream).toNumber()
88 })
89 }
90 return json
91}
92
93function encodeType (json, stream = new Stream()) {
94 let binEntries = new Stream()
95
96 leb.unsigned.write(json.length, binEntries)
97 for (let entry of json) {
98 // a single type entry binary encoded
99 binEntries.write([LANGUAGE_TYPES[entry.form]]) // the form
100
101 const len = entry.params.length // number of parameters
102 leb.unsigned.write(len, binEntries)
103 if (len !== 0) {
104 binEntries.write(entry.params.map(type => LANGUAGE_TYPES[type])) // the paramter types
105 }
106
107 binEntries.write([entry.return_type ? 1 : 0]) // number of return types
108 if (entry.return_type) {
109 binEntries.write([LANGUAGE_TYPES[entry.return_type]])
110 }
111 }
112
113 stream.write(binEntries.buffer)
114 return stream
115}
116
117function decodeType (buf) {
118 const stream = new Stream(Buffer.from(buf))
119 const numberOfEntries = leb.unsigned.readBn(stream).toNumber()
120 const json = []
121 for (let i = 0; i < numberOfEntries; i++) {
122 let type = stream.read(1)[0]
123 const entry = {
124 form: LANGUAGE_TYPES[type],
125 params: []
126 }
127
128 let paramCount = leb.unsigned.readBn(stream).toNumber()
129
130 // parse the entries
131 while (paramCount--) {
132 const type = stream.read(1)[0]
133 entry.params.push(LANGUAGE_TYPES[type])
134 }
135 const numOfReturns = leb.unsigned.readBn(stream).toNumber()
136 if (numOfReturns) {
137 type = stream.read(1)[0]
138 entry.return_type = LANGUAGE_TYPES[type]
139 }
140
141 json.push(entry)
142 }
143 return json
144}
145
146function injectCustomSection (custom, wasm) {
147 const preramble = wasm.subarray(0, 8)
148 const body = wasm.subarray(8)
149 return Buffer.concat([preramble, custom, body])
150}
151
152function inject (wasm, json) {
153 const buf = encodeJSON(json)
154 return injectCustomSection(buf, wasm)
155}
156
157function mergeTypeSections (json) {
158 const result = {
159 types: [],
160 indexes: {},
161 exports: {},
162 globals: []
163 }
164
165 const wantedSections = ['types', 'typeMap', 'globals', 'type', 'import', 'function', 'export']
166 const iterator = findSections(json, wantedSections)
167 const mappedFuncs = new Map()
168 const mappedTypes = new Map()
169 const {value: customType} = iterator.next()
170 if (customType) {
171 const type = decodeType(customType.payload)
172 result.types = type
173 }
174 let {value: typeMap} = iterator.next()
175 if (typeMap) {
176 decodeTypeMap(typeMap.payload).forEach(map => mappedFuncs.set(map.func, map.type))
177 }
178
179 let {value: globals} = iterator.next()
180 if (globals) {
181 result.globals = decodeGlobals(globals.payload)
182 }
183
184 const {value: type} = iterator.next()
185 const {value: imports = {entries: []}} = iterator.next()
186 const {value: functions} = iterator.next()
187 functions.entries.forEach((typeIndex, funcIndex) => {
188 let customIndex = mappedFuncs.get(funcIndex)
189 if (customIndex === undefined) {
190 customIndex = mappedTypes.get(typeIndex)
191 }
192 if (customIndex === undefined) {
193 customIndex = result.types.push(type.entries[typeIndex]) - 1
194 mappedTypes.set(typeIndex, customIndex)
195 }
196 result.indexes[funcIndex + imports.entries.length] = customIndex
197 })
198
199 const {value: exports = {entries: []}} = iterator.next()
200 exports.entries.forEach(entry => {
201 if (entry.kind === 'function') {
202 result.exports[entry.field_str] = entry.index
203 }
204 })
205 return result
206}
207
208module.exports = {
209 injectCustomSection,
210 inject,
211 decodeType,
212 decodeTypeMap,
213 decodeGlobals,
214 encodeType,
215 encodeTypeMap,
216 encodeJSON,
217 mergeTypeSections
218}
219

Built with git-ssb-web