git ssb

0+

wanderer🌟 / js-primea-wasm-container



Commit 0f31d31650ad897c852214495d044937472b54b9

add support for i64

wanderer committed on 3/29/2018, 11:56:19 PM
Parent: 17f8d0b0c260370c4b7e8406de2c84ce1586d3fa

Files changed

index.jschanged
package.jsonchanged
tests/index.jschanged
tests/wasm/table.wasmchanged
tests/wast/table.wastchanged
typeCheckWrapper.jschanged
index.jsView
@@ -18,10 +18,16 @@
1818 return new ModuleRef(exports, id)
1919 }
2020
2121 function generateWrapper (funcRef, container) {
22+ // check if the wrapper has been generated
23+ if (funcRef.wrapper) {
24+ return funcRef.wrapper
25+ }
2226 let wrapper = typeCheckWrapper(funcRef.params)
2327 const wasm = json2wasm(wrapper)
28+ const fs = require('fs')
29+ fs.writeFileSync('./checker.wasm', wasm)
2430 const mod = WebAssembly.Module(wasm)
2531 const self = funcRef
2632 wrapper = WebAssembly.Instance(mod, {
2733 'env': {
@@ -32,10 +38,15 @@
3238 const type = annotations.LANGUAGE_TYPES_BIN[args.shift()]
3339 let arg = args.shift()
3440 if (!nativeTypes.has(type)) {
3541 arg = container.refs.get(arg, type)
42+ checkedArgs.push(arg)
43+ } else if (type === 'i64') {
44+ checkedArgs.push(arg)
45+ checkedArgs.push(args.shift())
46+ } else {
47+ checkedArgs.push(arg)
3648 }
37- checkedArgs.push(arg)
3849 }
3950 const message = new Message({
4051 funcRef: self,
4152 funcArguments: checkedArgs
@@ -43,8 +54,10 @@
4354 container.actor.send(message)
4455 }
4556 }
4657 })
58+ // cache the wrapper
59+ funcRef.wrapper = wrapper
4760 wrapper.exports.check.object = funcRef
4861 return wrapper
4962 }
5063
@@ -88,9 +101,9 @@
88101 const self = this
89102 return {
90103 func: {
91104 externalize: index => {
92- const func = this.instance.exports.table.get(index)
105+ const func = self.instance.exports.table.get(index)
93106 const object = func.object
94107 if (object) {
95108 // externalize a pervously internalized function
96109 return self.refs.add(object)
@@ -106,15 +119,10 @@
106119 },
107120 internalize: (index, ref) => {
108121 const funcRef = self.refs.get(ref, 'func')
109122 const wrapper = generateWrapper(funcRef, self)
110- this.instance.exports.table.set(index, wrapper.exports.check)
123+ self.instance.exports.table.set(index, wrapper.exports.check)
111124 },
112- // catch: (ref, catchRef) => {
113- // const {funcRef} = self.refs.get(ref, FunctionRef)
114- // const {funcRef: catchFunc} = self.refs.get(ref, FunctionRef)
115- // funcRef.catch = catchFunc
116- // },
117125 get_gas_budget: (funcRef) => {
118126 const func = self.refs.get(funcRef, 'func')
119127 return func.gas
120128 },
@@ -124,79 +132,79 @@
124132 }
125133 },
126134 link: {
127135 wrap: ref => {
128- const obj = this.refs.get(ref)
136+ const obj = self.refs.get(ref)
129137 const link = {'/': obj}
130- return this.refs.add(link, 'link')
138+ return self.refs.add(link, 'link')
131139 },
132140 unwrap: async (ref, cb) => {
133- const obj = this.refs.get(ref, 'link')
134- const promise = this.actor.tree.dataStore.get(obj)
135- await this._opsQueue.push(promise)
141+ const obj = self.refs.get(ref, 'link')
142+ const promise = self.actor.tree.dataStore.get(obj)
143+ await self._opsQueue.push(promise)
136144 }
137145 },
138146 module: {
139147 new: dataRef => {
140- const mod = this.actor.createActor(dataRef)
141- return this.refs.add(mod, 'mod')
148+ const mod = self.actor.createActor(dataRef)
149+ return self.refs.add(mod, 'mod')
142150 },
143151 export: (modRef, dataRef) => {
144- const mod = this.refs.get(modRef, 'mod')
145- let name = this.refs.get(dataRef, 'data')
152+ const mod = self.refs.get(modRef, 'mod')
153+ let name = self.refs.get(dataRef, 'data')
146154 name = Buffer.from(name).toString()
147155 const funcRef = mod.getFuncRef(name)
148- return this.refs.add(funcRef, 'func')
156+ return self.refs.add(funcRef, 'func')
149157 },
150158 self: () => {
151- return this.refs.add(this.modSelf, 'mod')
159+ return self.refs.add(this.modSelf, 'mod')
152160 }
153161 },
154162 memory: {
155163 externalize: (index, length) => {
156164 const data = Buffer.from(this.get8Memory(index, length))
157- return this.refs.add(data, 'data')
165+ return self.refs.add(data, 'data')
158166 },
159167 internalize: (dataRef, srcOffset, sinkOffset, length) => {
160- let data = this.refs.get(dataRef, 'data')
168+ let data = self.refs.get(dataRef, 'data')
161169 data = data.subarray(srcOffset, length)
162- const mem = this.get8Memory(sinkOffset, data.length)
170+ const mem = self.get8Memory(sinkOffset, data.length)
163171 mem.set(data)
164172 },
165173 length (dataRef) {
166- let data = this.refs.get(dataRef, 'data')
174+ let data = self.refs.get(dataRef, 'data')
167175 return data.length
168176 }
169177 },
170- table: {
178+ elem: {
171179 externalize: (index, length) => {
172180 const mem = Buffer.from(this.get8Memory(index, length * 4))
173181 const objects = []
174182 while (length--) {
175183 const ref = mem.readUInt32LE(length * 4)
176- const obj = this.refs.get(ref)
184+ const obj = self.refs.get(ref)
177185 objects.unshift(obj)
178186 }
179187 return this.refs.add(objects, 'elem')
180188 },
181189 internalize: (elemRef, srcOffset, sinkOffset, length) => {
182- let table = this.refs.get(elemRef, 'elem')
183- const buf = table.slice(srcOffset, srcOffset + length).map(obj => this.refs.add(obj))
184- const mem = this.get32Memory(sinkOffset, length)
190+ let table = self.refs.get(elemRef, 'elem')
191+ const buf = table.slice(srcOffset, srcOffset + length).map(obj => self.refs.add(obj))
192+ const mem = self.get32Memory(sinkOffset, length)
185193 mem.set(buf)
186194 },
187195 length (elemRef) {
188- let elem = this.refs.get(elemRef, 'elem')
196+ let elem = self.refs.get(elemRef, 'elem')
189197 return elem.length
190198 }
191199 },
192200 metering: {
193201 usegas: amount => {
194- this.actor.incrementTicks(amount)
202+ self.actor.incrementTicks(amount)
195203 funcRef.gas -= amount
196- if (funcRef.gas < 0) {
197- throw new Error('out of gas! :(')
198- }
204+ // if (funcRef.gas < 0) {
205+ // throw new Error('out of gas! :(')
206+ // }
199207 }
200208 }
201209 }
202210 }
@@ -216,15 +224,21 @@
216224 }
217225 }
218226 }
219227 // import references
220- const args = message.funcArguments.map((arg, index) => {
221- const type = funcRef.params[index]
228+ let index = 0
229+ const args = []
230+ message.funcRef.params.forEach(type => {
231+ const arg = message.funcArguments[index]
222232 if (nativeTypes.has(type)) {
223- return arg
233+ args.push(arg)
234+ if (type === 'i64') {
235+ args.push(message.funcArguments[++index])
236+ }
224237 } else {
225- return this.refs.add(arg, type)
238+ args.push(this.refs.add(arg, type))
226239 }
240+ index++
227241 })
228242
229243 // setup globals
230244 let numOfGlobals = this.json.persist.length
@@ -237,13 +251,18 @@
237251 this.instance.exports.setter_globals(...refs)
238252 }
239253
240254 // call entrypoint function
255+ let wasmFunc
241256 if (funcRef.identifier[0]) {
242- this.instance.exports.table.get(funcRef.identifier[1])(...args)
257+ wasmFunc = this.instance.exports.table.get(funcRef.identifier[1])
243258 } else {
244- this.instance.exports[funcRef.identifier[1]](...args)
259+ wasmFunc = this.instance.exports[funcRef.identifier[1]]
245260 }
261+
262+ const wrapper = generateWrapper(funcRef)
263+ wrapper.exports.table.set(0, wasmFunc)
264+ wrapper.exports.invoke(...args)
246265 await this.onDone()
247266
248267 // store globals
249268 numOfGlobals = this.json.persist.length
package.jsonView
@@ -32,9 +32,9 @@
3232 "wabt": "^1.0.0"
3333 },
3434 "dependencies": {
3535 "borc": "^2.0.2",
36- "primea-annotations": "0.0.2",
36+ "primea-annotations": "0.0.3",
3737 "primea-objects": "0.0.1",
3838 "reference-map": "1.2.3",
3939 "wasm-json-toolkit": "^0.2.3",
4040 "wasm-metering": "^0.1.1"
tests/index.jsView
@@ -4,8 +4,9 @@
44 const {Message} = require('primea-objects')
55 const Hypervisor = require('primea-hypervisor')
66 const WasmContainer = require('../')
77
8+const annotations = require('primea-annotations')
89 const level = require('level-browserify')
910 const RadixTree = require('dfinity-radix-tree')
1011 const db = level('./testdb')
1112
@@ -19,22 +20,65 @@
1920 this._storage = new Map()
2021 }
2122 getInterface (funcRef) {
2223 const orginal = super.getInterface(funcRef)
24+ const self = this
2325 return Object.assign(orginal, {
2426 test: {
2527 check: (a, b) => {
2628 tester.equals(a, b)
2729 },
2830 print: (dataRef) => {
29- let buf = this.refs.get(dataRef, 'buf')
31+ console.log(dataRef, self.refs)
32+ let buf = self.refs.get(dataRef, 'data')
3033 console.log(buf.toString())
3134 }
3235 }
3336 })
3437 }
3538 }
3639
40+tape.skip('bwasic', async t => {
41+ // t.plan(1)
42+ tester = t
43+
44+ const typeInfo = {
45+ 'types': [{
46+ 'form': 'func',
47+ 'params': [
48+ 'i64',
49+ 'data'
50+ ]
51+ }],
52+ 'typeMap': [{
53+ 'func': 46,
54+ 'type': 0
55+ }]
56+ }
57+
58+ const tree = new RadixTree({db})
59+
60+ let wasm = fs.readFileSync('./test.wasm')
61+ wasm = annotations.encodeAndInject(typeInfo, wasm)
62+
63+ const hypervisor = new Hypervisor(tree)
64+ hypervisor.registerContainer(TestWasmContainer)
65+
66+ const {module} = await hypervisor.createActor(TestWasmContainer.typeId, wasm)
67+ const funcRef = module.getFuncRef('#main')
68+ funcRef.gas = 322000
69+
70+ const message = new Message({
71+ funcRef
72+ }).on('execution:error', e => {
73+ console.log(e)
74+ })
75+ hypervisor.send(message)
76+ // const stateRoot = await hypervisor.createStateRoot()
77+ // t.deepEquals(stateRoot, expectedState, 'expected root!')
78+ t.end()
79+})
80+
3781 tape('basic', async t => {
3882 t.plan(1)
3983 tester = t
4084
tests/wasm/table.wasmView
@@ -1,3 +1,3 @@
1-asm```>table externalizememory externalizetable internalizememorytest
1+asm```<elem externalizememory externalizeelem internalizememorytest
22 (&AAAAAA66AAAAA
33 A test
tests/wast/table.wastView
@@ -1,8 +1,8 @@
11 (module
2- (import "table" "externalize" (func $externalize (param i32 i32) (result i32)))
2+ (import "elem" "externalize" (func $externalize (param i32 i32) (result i32)))
33 (import "memory" "externalize" (func $mem_externalize (param i32 i32) (result i32)))
4- (import "table" "internalize" (func $internalize (param i32 i32 i32 i32)))
4+ (import "elem" "internalize" (func $internalize (param i32 i32 i32 i32)))
55 (memory (export "memory") 1)
66 (data (i32.const 0) "test")
77 (func $test
88 (i32.const 0)
typeCheckWrapper.jsView
@@ -89,17 +89,18 @@
8989 'code': []
9090 }]
9191 }]
9292
93- const definedTypes = new Set(['actor', 'func', 'buf'])
93+ const definedTypes = new Set(['anyref', 'module', 'func', 'data', 'elem', 'link', 'id'])
9494 const setGlobals = []
9595 const importType = module[1].entries[0].params
9696 const checkType = module[1].entries[1].params
9797 const invokerType = module[1].entries[2].params
9898 const invokeType = module[1].entries[3].params
99- const checkCode = module[7].entries[0].code
100- const invokeCode = module[7].entries[1].code
99+ let checkCode = module[7].entries[0].code
100+ let invokeCode = module[7].entries[1].code
101101
102+ let invokeIndex = 0
102103 params.forEach((param, index) => {
103104 let baseType = param
104105 const typeCode = LANGUAGE_TYPES_STRG[param]
105106 // import type
@@ -111,47 +112,153 @@
111112
112113 // check import
113114 importType.push('i32')
114115 importType.push('i32')
115- checkCode.push({
116- 'return_type': 'i32',
117- 'name': 'const',
118- 'immediates': typeCode
119- })
120- checkCode.push({
121- 'name': 'get_local',
122- 'immediates': index
123- })
124- invokeCode.push({
125- 'name': 'get_local',
126- 'immediates': index
127- })
116+ checkCode.push(i32_const(typeCode))
117+ if (baseType === 'i64') {
118+ importType.push('i32')
119+
120+ // splits an i64 into 2 i32
121+ const spliti64 = [
122+ get_local(index),
123+ i64_const(32),
124+ shr_u(),
125+ wrap_i64(),
126+ get_local(index),
127+ wrap_i64()]
128+
129+ checkCode = checkCode.concat(spliti64)
130+
131+ const i32wrapCode = [
132+ get_local(invokeIndex), {
133+ 'return_type': 'i64',
134+ 'name': 'extend_u/i32'
135+ }, {
136+ 'return_type': 'i64',
137+ 'name': 'const',
138+ 'immediates': '32'
139+ }, {
140+ 'return_type': 'i64',
141+ 'name': 'shl'
142+ },
143+ get_local(++invokeIndex), {
144+ 'return_type': 'i64',
145+ 'name': 'extend_u/i32'
146+ }, {
147+ 'return_type': 'i64',
148+ 'name': 'add'
149+ }
150+ ]
151+
152+ invokeCode = invokeCode.concat(i32wrapCode)
153+ invokerType.push('i32')
154+ } else {
155+ checkCode.push(get_local(index))
156+ invokeCode.push(get_local(invokeIndex))
157+ }
158+ invokerType.push('i32')
128159 // check export
129160 checkType.push(baseType)
130161 // invoke
131162 invokeType.push(baseType)
132- invokerType.push(baseType)
163+ invokeIndex++
133164 })
134165
135- module[7].entries[0].code = checkCode.concat(setGlobals, [{
166+ module[7].entries[0].code = checkCode.concat(setGlobals, [call(0), end()])
167+ invokeCode.push(i32_const(0))
168+ invokeCode.push(call_indirect(3))
169+ invokeCode.push(end())
170+ module[7].entries[1].code = invokeCode
171+ return module
172+}
173+
174+function call (index) {
175+ return {
136176 'name': 'call',
137- 'immediates': '0'
138- }, {
139- 'name': 'end'
140- }])
141- invokeCode.push({
142- 'return_type': 'i32',
143- 'name': 'const',
144- 'immediates': '0'
145- })
146- invokeCode.push({
177+ 'immediates': index
178+ }
179+}
180+
181+function call_indirect (index) {
182+ return {
147183 'name': 'call_indirect',
148184 'immediates': {
149- 'index': 3,
185+ 'index': index,
150186 'reserved': 0
151187 }
152- })
153- invokeCode.push({
154- 'name': 'end'
155- })
156- return module
188+ }
157189 }
190+
191+function typeEntry (params = []) {
192+ return {
193+ form: 'func',
194+ params: params
195+ }
196+}
197+
198+function end () {
199+ return {
200+ name: 'end'
201+ }
202+}
203+
204+function get_local (index) {
205+ return {
206+ name: 'get_local',
207+ immediates: index
208+ }
209+}
210+
211+function get_global (index) {
212+ return {
213+ name: 'get_global',
214+ immediates: index
215+ }
216+}
217+
218+function set_global (index) {
219+ return {
220+ name: 'set_global',
221+ immediates: index
222+ }
223+}
224+
225+function i32_const (num) {
226+ return {
227+ 'return_type': 'i32',
228+ 'name': 'const',
229+ 'immediates': num
230+ }
231+}
232+
233+function i64_const (num) {
234+ return {
235+ 'return_type': 'i64',
236+ 'name': 'const',
237+ 'immediates': num
238+ }
239+}
240+
241+function i32_store () {
242+ return {
243+ 'return_type': 'i32',
244+ 'name': 'store',
245+ 'immediates': {
246+ 'flags': 2,
247+ 'offset': 0
248+ }
249+ }
250+}
251+
252+function shr_u() {
253+ return {
254+ 'return_type': 'i64',
255+ 'name': 'shr_u'
256+ }
257+}
258+
259+function wrap_i64() {
260+ return {
261+ 'return_type': 'i32',
262+ 'name': 'wrap/i64'
263+ }
264+}

Built with git-ssb-web