git ssb

0+

wanderer🌟 / js-primea-hypervisor



Tree: e1f7b0f1b9dc6898db308a95307211a4ea191e3c

Files: e1f7b0f1b9dc6898db308a95307211a4ea191e3c / wasmContainer.js

6921 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 metering: {
149 usegas: (amount) => {
150 funcRef.gas -= amount
151 if (funcRef.gas < 0) {
152 throw new Error('out of gas! :(')
153 }
154 }
155 }
156 }
157 }
158
159 onMessage (message) {
160 const funcRef = message.funcRef
161 const intef = this.getInteface(funcRef)
162 this.instance = WebAssembly.Instance(this.mod, intef)
163 const args = message.funcArguments.map(arg => {
164 if (typeof arg === 'number') {
165 return arg
166 } else {
167 return this.refs.add(arg)
168 }
169 })
170 this.instance.exports[funcRef.name](...args)
171 }
172
173 getFuncRef (name, send) {
174 const funcRef = new FunctionRef(this.json, name, send)
175 return funcRef
176 }
177
178 async onStartup () {
179 let [json, wasm] = await Promise.all([
180 new Promise((resolve, reject) => {
181 this.actor.cachedb.get(this.actor.id.toString() + 'meta', (err, json) => {
182 if (err) {
183 reject(err)
184 } else {
185 resolve(json)
186 }
187 })
188 }),
189 new Promise((resolve, reject) => {
190 this.actor.cachedb.get(this.actor.id.toString() + 'code', (err, wasm) => {
191 if (err) {
192 reject(err)
193 } else {
194 resolve(wasm)
195 }
196 })
197 })
198 ])
199 wasm = Buffer.from(wasm, 'hex')
200 this.mod = WebAssembly.Module(wasm)
201 this.json = json
202 }
203
204 static get typeId () {
205 return 9
206 }
207}
208
209function mergeTypeSections (json) {
210 const typeInfo = {
211 typeMap: [],
212 type: []
213 }
214 let typeSection = {
215 'entries': []
216 }
217 let importSection = {
218 'entries': []
219 }
220 let functionSection = {
221 'entries': []
222 }
223 let exportSection = {
224 'entries': []
225 }
226 json.forEach(section => {
227 switch (section.name) {
228 case 'type':
229 typeSection = section
230 break
231 case 'export':
232 exportSection = section
233 break
234 case 'import':
235 importSection = section
236 break
237 case 'function':
238 functionSection = section
239 break
240 case 'custom':
241 switch (section.sectionName) {
242 case 'type':
243 typeInfo.type = customTypes.decodeType(section.payload)
244 break
245 case 'typeMap':
246 typeInfo.typeMap = customTypes.decodeTypeMap(section.payload)
247 break
248 }
249 break
250 }
251 })
252
253 const foundTypes = new Map()
254 const mappedFuncs = new Map()
255 const newTypeMap = {}
256 typeInfo.typeMap.forEach(map => mappedFuncs.set(map.func, map.type))
257 for (let exprt of exportSection.entries) {
258 if (exprt.kind === 'function') {
259 if (!mappedFuncs.has(exprt.index)) {
260 const typeIndex = functionSection.entries[exprt.index - importSection.entries.length]
261 if (!foundTypes.has(typeIndex)) {
262 const customIndex = typeInfo.type.push(typeSection.entries[typeIndex]) - 1
263 foundTypes.set(typeIndex, customIndex)
264 }
265 const customIndex = foundTypes.get(typeIndex)
266 newTypeMap[exprt.field_str] = customIndex
267 } else {
268 newTypeMap[exprt.field_str] = mappedFuncs.get(exprt.index)
269 }
270 }
271 }
272
273 typeInfo.typeMap = newTypeMap
274 return typeInfo
275}
276

Built with git-ssb-web