-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathtest2.nim
More file actions
241 lines (190 loc) · 9.23 KB
/
test2.nim
File metadata and controls
241 lines (190 loc) · 9.23 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
import std/[strformat, options, strutils, macros, genasts, unicode, tables]
import wasmtime, wit_host
type MyContext = ref object
counter: int
callbacks: Table[uint32, ptr ComponentFuncT]
instanceToComponent: Table[ptr ComponentInstanceT, ptr ComponentT]
currentInstance: ptr ComponentInstanceT = nil
type MyBlob = object
i: int = 1
blobName: string
arr: seq[uint8]
type Callback = object
data: uint32
key: uint32
drop: proc()
# proc `=copy`*(a: var Callback, b: Callback) {.error.}
# proc `=copy`*(a: var MyBlob, b: MyBlob) {.error.}
proc `=destroy`*(b: Callback) =
if b.data != 0:
echo "[host] --------------------------------- delete Callback ", b.data, b.key
b.drop()
proc `=destroy`*(b: MyBlob) =
if b.i != 0:
echo "[host] --------------------------------- delete MyBlob ", b
# todo: auto generate unique type id for each resource
template typeId*(_: typedesc[MyBlob]): int = 69
template typeId*(_: typedesc[Callback]): int = 420
when defined(witRebuild):
static: hint("Rebuilding test.wit")
importWit "wasm/wit", MyContext:
world = "host"
mapName "blob", MyBlob
else:
static: hint("Using cached test.wit (host.nim)")
include host
proc testInterfaceNewBlob(host: MyContext, store: ptr ComponentContextT, init: seq[uint8]): MyBlob =
result = MyBlob(blobName: "constr" & $host.counter, arr: init)
host.counter.inc
proc testInterfaceWrite(host: MyContext, store: ptr ComponentContextT, self: var MyBlob, bytes: seq[uint8]) =
self.arr.add bytes
proc testInterfaceRead(host: MyContext, store: ptr ComponentContextT, self: var MyBlob, n: int32): seq[uint8] =
defer:
echo "[host] ############################# read ", self, ", ", n, " -> ", result
let l = min(self.arr.len, n.int)
return self.arr[0..<l]
proc testInterfaceMerge(host: MyContext, store: ptr ComponentContextT, lhs: sink MyBlob, rhs: sink MyBlob): MyBlob =
echo "[host] ================================== merge ", lhs, ", ", rhs
result = MyBlob(blobName: "merge" & $host.counter, arr: lhs.arr & rhs.arr)
host.counter.inc
proc testInterfacePrint(host: MyContext, store: ptr ComponentContextT, lhs: var MyBlob, rhs: var MyBlob) =
echo "[host] ================================== print ", lhs, ", ", rhs
proc testInterfaceBarBaz(host: MyContext, store: ptr ComponentContextT, a: int32, b: float32): float32 =
result = a.float32 - b
proc envTestNoParams2(host: MyContext, store: ptr ComponentContextT, b: Baz) =
echo "[host] envTestNoParams2 ", b
proc testInterfaceTestNoParams(host: MyContext, store: ptr ComponentContextT) =
echo "[host] testInterfaceTestNoParams"
proc testInterfaceTestSimpleParams(host: MyContext, store: ptr ComponentContextT,
a: int8, b: int16, c: int32, d: int64, e: uint8, f: uint16, g: uint32, h: uint64, i: float32,
j: float64, k: bool, l: Rune) =
echo &"[host] {a}, {b}, {c}, {d}, {e}, {f}, {g}, {h}, {i}, {j}, {k}, {l}"
proc testInterfaceTestSimpleParamsPtr(host: MyContext, store: ptr ComponentContextT,
a: int8, b: int16, c: int32, d: int64, e: uint8, f: uint16, g: uint32, h: uint64, i: float32,
j: float64, k: bool, l: Rune, m: int32, n: int32, o: int32, p: int32, q: int32) =
echo &"[host] {a}, {b}, {c}, {d}, {e}, {f}, {g}, {h}, {i}, {j}, {k}, {l}, {m}, {n}, {o}, {p}, {q}"
proc callbackTypesNewCallback(host: MyContext, store: ptr ComponentContextT, data: uint32, key: uint32, drop: uint32): Callback =
proc dropImpl() =
host.callbacks.withValue(drop, fun):
echo "[host] Call drop for ", data
fun[].call(store, [data.toVal], []).okOr(err):
echo "[host] Failed to call dealloc callback for key ", key, ": ", err.msg
do:
echo "[host] No dealloc callback registered for key ", key
Callback(data: data, key: key, drop: dropImpl)
proc callbackTypesData(host: MyContext, store: ptr ComponentContextT, self: var Callback): uint32 =
self.data
proc callbackTypesKey(host: MyContext, store: ptr ComponentContextT, self: var Callback): uint32 =
self.key
proc testInterfaceAddCallback(host: MyContext, store: ptr ComponentContextT, env: string, name: string): uint32 =
echo &"[host] testInterfaceAddCallback {env}, {name}"
let instance = host.currentInstance
var component: ptr ComponentT = host.instanceToComponent[instance]
let instanceIndex = if env != "":
component.getExport(env)
else:
ComponentExportIndexT.none
echo instanceIndex
let exportIndex = component.getExport(name, instanceIndex)
if exportIndex.isNone:
echo &"[host] Failed to find export ", name, " in ", instanceIndex
return uint32.high
var fun: ptr ComponentFuncT = nil
if not instance.getFuncByIndex(store, exportIndex.get, fun.addr):
echo "[host] Failed to get func"
return
let key = host.callbacks.len.uint32
host.callbacks[key] = fun
key
proc testInterfaceTestSimpleReturn(host: MyContext, store: ptr ComponentContextT, x: int32): int32 =
echo "[host] testInterfaceTestSimpleReturn ", x
return x * 2
proc testInterfaceTestSimpleReturn2(host: MyContext, store: ptr ComponentContextT, x: int8): int8 =
echo "[host] testInterfaceTestSimpleReturn2 ", x
return x * 2
proc testInterfaceTestSimpleReturnPtr(host: MyContext, store: ptr ComponentContextT, x: int8): Bar =
echo "[host] testInterfaceTestSimpleReturnPtr ", x
return Bar(a: 123, b: 456.789, c: "ü".runeAt(0), d: true)
proc testInterfaceTestSimpleReturnPtr2(host: MyContext; store: ptr ComponentContextT): Baz =
return Baz(x: "uiae", c: Foo(x: "xvlc"), f: @[Foo(x: "1"), Foo(x: "9"), Foo(x: "6")], d: (111, 222.333), gbruh: @[{Lame}, {SoLame}, {Cool, SoLame}, {Cool, Lame}, {SoLame, Lame}, {Cool, SoLame, Lame}], g: BlockDevice, h: {Lame, SoLame}, e: 666.int32.some, k: @[Bar(a: 123, b: 456.789, c: "ü".runeAt(0), d: true), Bar(a: 987, b: 654.321, c: "ö".runeAt(0), d: false)])
proc call(instance: ptr ComponentInstanceT, context: ptr ComponentContextT, name: string, params: openArray[ComponentValT], nresults: static[int]) =
var f: ptr ComponentFuncT = nil
if not instance.getFunc(context, name.cstring, name.len.csize_t, f.addr):
echo &"[host] Failed to get func '{name}'"
return
if f == nil:
echo &"[host] Failed to get func '{name}'"
return
var res: array[max(nresults, 1), ComponentValT]
echo &"[host] ------------------------------- call {name}, {params} -------------------------------------"
f.call(context, params, res.toOpenArray(0, nresults - 1)).okOr(e):
echo &"[host] Failed to call func '{name}': ", e.msg
return
if nresults > 0:
echo &"[host] call func {name} -> {res}"
proc main(): WasmtimeResult[void] =
echo "[host] Start main"
let config = newConfig()
let engine = newEngine(config)
let linker = engine.newComponentLinker()
var trap: ptr WasmTrapT = nil
let store = engine.newComponentStore(nil, nil)
# defer: store.delete()
var instance2: ptr ComponentInstanceT = nil
var ctx = MyContext(counter: 1)
linker.defineComponent(ctx).okOr(err):
echo "[host] Failed to define component: ", err.msg
return
linker.linkWasi(trap.addr).okOr(err):
echo "[host] Failed to link wasi: ", err.msg
return
trap.okOr(err):
echo "[host][trap] Failed to link wasi: ", err.msg
return
echo "[host] read file 1"
let component1 = engine.newComponent(readFile("tests/wasm/plugin1.c.wasm")).okOr(err):
echo "[host] Failed to create wasm component: ", err.msg
return
# Define gue functions for callbacks
component1.iterateImports proc(path: string, name: string, typ: ComponentItemType) =
# echo "[host] path: ", path, ", name: ", name, ", typ: ", typ
if (path == "callbacks" or path.endsWith("/callbacks")) and name.startsWith("invoke-"):
echo "[host] define path: ", path, ", name: ", name, ", typ: ", typ
let e = linker.defineFunc(path, name):
# echo "[host] ----------------- ", path, "#", name, ": ", parameters
let cb = ?store.resourceHostData(parameters[0].addr, Callback)
ctx.callbacks.withValue(cb.key, fun):
?fun[].call(store, parameters, results)
do:
echo "[host] No callback registered for key ", cb.key
return
?store.resourceDrop(parameters[0].addr)
echo "[host] read file 2"
let component2 = engine.newComponent(readFile("tests/wasm/plugin2.c.wasm")).okOr(err):
echo "[host] Failed to create wasm component: ", err.msg
return
echo "[host] create instance"
var instance: ptr ComponentInstanceT = nil
linker.instantiate(store.context, component1, instance.addr, trap.addr).okOr(err):
echo "[host] Failed to create component instance: ", err.msg
return
ctx.instanceToComponent[instance] = component1
linker.defineInstance(store.context, component1, instance).okOr(err):
echo "[host] Failed to define instance in linker: ", err.msg
return
echo "[host] create instance"
linker.instantiate(store.context, component2, instance2.addr, trap.addr).okOr(err):
echo "[host] Failed to create component instance 2: ", err.msg
return
ctx.instanceToComponent[instance2] = component2
trap.okOr(err):
echo "[host][trap] Failed to create component instance: ", err.msg
return
assert instance != nil
ctx.currentInstance = instance2
instance2.call(store.context, "start", [], 0)
ctx.currentInstance = instance
instance.call(store.context, "start", [], 0)
echo "[host] ------------ Finished main"
echo main()
echo "no crash"