git ssb

0+

wanderer🌟 / js-primea-hypervisor



Tree: 337e581214f9ce5a65ecad94f1830a0dc0891124

Files: 337e581214f9ce5a65ecad94f1830a0dc0891124 / wasmContainer.js

7017 bytesRaw
1const {wasm2json, json2wasm} = require('wasm-json-toolkit')
2const wasmMetering = require('wasm-metering')
3const customTypes = require('./customTypes.js')
4const typeCheckWrapper = require('./typeCheckWrapper.js')
5const ReferanceMap = require('reference-map')
6
7const nativeTypes = new Set(['i32', 'i64', 'f32', 'f64'])
8const 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
30class FunctionRef {
31 constructor (name, json, id) {
32 this.name = name
33 this.destId = id
34 this.args = []
35 const typeIndex = json.typeMap[name]
36 const type = json.type[typeIndex]
37 const wrapper = typeCheckWrapper(type)
38 const wasm = json2wasm(wrapper)
39 this.mod = WebAssembly.Module(wasm)
40 const self = this
41 const instance = WebAssembly.Instance(this.mod, {
42 'env': {
43 'checkTypes': function () {
44 const args = [...arguments]
45 while (args.length) {
46 const type = LANGUAGE_TYPES[args.shift()]
47 let arg = args.shift()
48 if (!nativeTypes.has(type)) {
49 arg = self._container.refs.get(arg)
50 if (arg.type !== type) {
51 throw new Error('invalid type')
52 }
53 }
54 self.args.push({
55 arg,
56 type
57 })
58 }
59 self._container.sendMessage(instance)
60 }
61 }
62 })
63 this.wrapper = instance
64 }
65 set container (container) {
66 this._container = container
67 }
68}
69
70module.exports = class WasmContainer {
71 constructor (actor) {
72 this.actor = actor
73 this.refs = new ReferanceMap()
74 }
75
76 static onCreation (wasm, id, cachedb) {
77 WebAssembly.validate(wasm)
78 let moduleJSON = wasm2json(wasm)
79 const json = mergeTypeSections(moduleJSON)
80 moduleJSON = wasmMetering.meterJSON(moduleJSON, {
81 meterType: 'i32'
82 })
83 wasm = json2wasm(moduleJSON)
84 cachedb.put(id.toString() + 'meta', json)
85 cachedb.put(id.toString() + 'code', wasm.toString('hex'))
86 const refs = {}
87 Object.keys(json.typeMap).forEach(key => {
88 refs[key] = new FunctionRef(key, json, id)
89 })
90 return refs
91 }
92
93 sendMessage () {
94 console.log('send')
95 }
96
97 getInteface (funcRef) {
98 const self = this
99 return {
100 func: {
101 externalize: () => {},
102 internalize: (ref, index) => {
103 const {type, arg} = self.refs.get(ref)
104 if (type !== 'funcRef') {
105 throw new Error('invalid type')
106 }
107 arg.container = self
108 this.instance.exports.table.set(index, arg.wrapper.exports.check)
109 },
110 catch: (ref, catchRef) => {
111 const {funcRef} = self.refs.get(ref, FunctionRef)
112 const {funcRef: catchFunc} = self.refs.get(ref, FunctionRef)
113 funcRef.catch = catchFunc
114 },
115 getGasAmount: () => {},
116 setGasAmount: () => {}
117 },
118 storage: {
119 load: () => {},
120 store: () => {},
121 delete: () => {}
122 },
123 link: {
124 wrap: (ref) => {
125 const obj = this.refs.get(ref)
126 obj.seriarlize()
127 },
128 unwrap: () => {}
129 },
130 databuf: {
131 create: () => {},
132 load8: () => {},
133 load16: () => {},
134 load32: () => {},
135 load64: () => {},
136 store8: () => {},
137 store16: () => {},
138 store32: () => {},
139 store64: () => {},
140 copy: () => {}
141 },
142 elembuf: {
143 create: () => {},
144 load: () => {},
145 store: () => {},
146 delete: () => {}
147 },
148 test: {
149 check: (a, b) => {
150 console.log('$$$$', a, b)
151 }
152 },
153 metering: {
154 usegas: (amount) => {
155 funcRef.gas -= amount
156 if (funcRef.gas < 0) {
157 throw new Error('out of gas! :(')
158 }
159 }
160 }
161 }
162 }
163
164 onMessage (message) {
165 const funcRef = message.funcRef
166 const intef = this.getInteface(funcRef)
167 this.instance = WebAssembly.Instance(this.mod, intef)
168 const args = message.funcArguments.map(arg => {
169 if (typeof arg === 'number') {
170 return arg
171 } else {
172 return this.refs.add(arg)
173 }
174 })
175 this.instance.exports[funcRef.name](...args)
176 }
177
178 getFuncRef (name, send) {
179 const funcRef = new FunctionRef(this.json, name, send)
180 return funcRef
181 }
182
183 async onStartup () {
184 let [json, wasm] = await Promise.all([
185 new Promise((resolve, reject) => {
186 this.actor.cachedb.get(this.actor.id.toString() + 'meta', (err, json) => {
187 if (err) {
188 reject(err)
189 } else {
190 resolve(json)
191 }
192 })
193 }),
194 new Promise((resolve, reject) => {
195 this.actor.cachedb.get(this.actor.id.toString() + 'code', (err, wasm) => {
196 if (err) {
197 reject(err)
198 } else {
199 resolve(wasm)
200 }
201 })
202 })
203 ])
204 wasm = Buffer.from(wasm, 'hex')
205 this.mod = WebAssembly.Module(wasm)
206 this.json = json
207 }
208
209 static get typeId () {
210 return 9
211 }
212}
213
214function mergeTypeSections (json) {
215 const typeInfo = {
216 typeMap: [],
217 type: []
218 }
219 let typeSection = {
220 'entries': []
221 }
222 let importSection = {
223 'entries': []
224 }
225 let functionSection = {
226 'entries': []
227 }
228 let exportSection = {
229 'entries': []
230 }
231 json.forEach(section => {
232 switch (section.name) {
233 case 'type':
234 typeSection = section
235 break
236 case 'export':
237 exportSection = section
238 break
239 case 'import':
240 importSection = section
241 break
242 case 'function':
243 functionSection = section
244 break
245 case 'custom':
246 switch (section.sectionName) {
247 case 'type':
248 typeInfo.type = customTypes.decodeType(section.payload)
249 break
250 case 'typeMap':
251 typeInfo.typeMap = customTypes.decodeTypeMap(section.payload)
252 break
253 }
254 break
255 }
256 })
257
258 const foundTypes = new Map()
259 const mappedFuncs = new Map()
260 const newTypeMap = {}
261 typeInfo.typeMap.forEach(map => mappedFuncs.set(map.func, map.type))
262 for (let exprt of exportSection.entries) {
263 if (exprt.kind === 'function') {
264 if (!mappedFuncs.has(exprt.index)) {
265 const typeIndex = functionSection.entries[exprt.index - importSection.entries.length]
266 if (!foundTypes.has(typeIndex)) {
267 const customIndex = typeInfo.type.push(typeSection.entries[typeIndex]) - 1
268 foundTypes.set(typeIndex, customIndex)
269 }
270 const customIndex = foundTypes.get(typeIndex)
271 newTypeMap[exprt.field_str] = customIndex
272 } else {
273 newTypeMap[exprt.field_str] = mappedFuncs.get(exprt.index)
274 }
275 }
276 }
277
278 typeInfo.typeMap = newTypeMap
279 return typeInfo
280}
281

Built with git-ssb-web