wardite 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Steepfile +1 -0
- data/examples/grayscale.rb +64 -0
- data/exe/wardite +11 -5
- data/lib/wardite/instruction.rb +10 -9
- data/lib/wardite/load.rb +20 -10
- data/lib/wardite/revisitor.rb +92 -0
- data/lib/wardite/value.rb +6 -22
- data/lib/wardite/version.rb +1 -1
- data/lib/wardite/wasi/consts.rb +129 -0
- data/lib/wardite/wasi.rb +268 -7
- data/lib/wardite/wasm_module.rb +53 -0
- data/lib/wardite.rb +74 -105
- data/misc/proposals/rubykaigi2025.md +46 -0
- data/misc/slides/fib.c +4 -0
- data/misc/slides/fib.html +13 -0
- data/misc/slides/image-1.png +0 -0
- data/misc/slides/image-2.png +0 -0
- data/misc/slides/image.png +0 -0
- data/misc/slides/tokyo12.html +614 -0
- data/misc/slides/tokyo12.md +624 -0
- data/sig/fcntl.rbs +7 -0
- data/sig/generated/wardite/instruction.rbs +2 -0
- data/sig/generated/wardite/load.rbs +2 -3
- data/sig/generated/wardite/revisitor.rbs +25 -0
- data/sig/generated/wardite/value.rbs +3 -10
- data/sig/generated/wardite/wasi/consts.rbs +137 -0
- data/sig/generated/wardite/wasi.rbs +62 -5
- data/sig/generated/wardite/wasm_module.rbs +42 -0
- data/sig/generated/wardite.rbs +24 -19
- metadata +18 -3
- data/examples/add.wasm +0 -0
data/lib/wardite/wasi.rb
CHANGED
@@ -1,16 +1,161 @@
|
|
1
1
|
# rbs_inline: enabled
|
2
|
+
|
3
|
+
require "wardite/wasm_module"
|
4
|
+
require "wardite/wasi/consts"
|
5
|
+
require "securerandom"
|
6
|
+
require "fcntl"
|
7
|
+
|
2
8
|
module Wardite
|
3
9
|
class WasiSnapshotPreview1
|
4
10
|
include ValueHelper
|
11
|
+
include WasmModule
|
5
12
|
|
6
|
-
attr_accessor :fd_table #: Array[IO]
|
13
|
+
attr_accessor :fd_table #: Array[(IO|File)]
|
14
|
+
attr_accessor :argv #: Array[String]
|
7
15
|
|
8
|
-
|
16
|
+
# @rbs argv: Array[String]
|
17
|
+
# @rbs return: void
|
18
|
+
def initialize(argv: [])
|
9
19
|
@fd_table = [
|
10
20
|
STDIN,
|
11
21
|
STDOUT,
|
12
22
|
STDERR,
|
13
23
|
]
|
24
|
+
@argv = argv
|
25
|
+
end
|
26
|
+
|
27
|
+
# @rbs store: Store
|
28
|
+
# @rbs args: Array[wasmValue]
|
29
|
+
# @rbs return: Object
|
30
|
+
def args_get(store, args)
|
31
|
+
arg_offsets_p = args[0].value
|
32
|
+
arg_data_buf_p = args[1].value
|
33
|
+
if !arg_data_buf_p.is_a?(Integer)
|
34
|
+
raise ArgumentError, "invalid type of args: #{args.inspect}"
|
35
|
+
end
|
36
|
+
|
37
|
+
arg_offsets = [] #: Array[Integer]
|
38
|
+
arg_data_slice = [] #: Array[String]
|
39
|
+
current_offset = arg_data_buf_p
|
40
|
+
@argv.each do |arg|
|
41
|
+
arg_offsets << current_offset
|
42
|
+
arg_data_slice << arg
|
43
|
+
current_offset += arg.size + 1
|
44
|
+
end
|
45
|
+
arg_data = arg_data_slice.join("\0") + "\0"
|
46
|
+
|
47
|
+
memory = store.memories[0]
|
48
|
+
memory.data[arg_data_buf_p...(arg_data_buf_p + arg_data.size)] = arg_data
|
49
|
+
|
50
|
+
arg_offsets.each_with_index do |offset, i|
|
51
|
+
data_begin = arg_offsets_p + i * 4
|
52
|
+
memory.data[data_begin...(data_begin + 4)] = [offset].pack("I!")
|
53
|
+
end
|
54
|
+
|
55
|
+
0
|
56
|
+
end
|
57
|
+
|
58
|
+
# @rbs store: Store
|
59
|
+
# @rbs args: Array[wasmValue]
|
60
|
+
# @rbs return: Object
|
61
|
+
def args_sizes_get(store, args)
|
62
|
+
argc_p = args[0].value
|
63
|
+
arglen_p = args[1].value
|
64
|
+
argc = @argv.length
|
65
|
+
arglen = @argv.map{|arg| arg.size + 1}.sum
|
66
|
+
|
67
|
+
memory = store.memories[0]
|
68
|
+
memory.data[argc_p...(argc_p+4)] = [argc].pack("I!")
|
69
|
+
memory.data[arglen_p...(arglen_p+4)] = [arglen].pack("I!")
|
70
|
+
0
|
71
|
+
end
|
72
|
+
|
73
|
+
# @rbs store: Store
|
74
|
+
# @rbs args: Array[wasmValue]
|
75
|
+
# @rbs return: Object
|
76
|
+
def environ_sizes_get(store, args)
|
77
|
+
envc_p = args[0].value
|
78
|
+
envlen_p = args[1].value
|
79
|
+
envc = ENV.length
|
80
|
+
envlen = ENV.map{|k,v| k.size + v.size + 1}.sum
|
81
|
+
|
82
|
+
memory = store.memories[0]
|
83
|
+
memory.data[envc_p...(envc_p+4)] = [envc].pack("I!")
|
84
|
+
memory.data[envlen_p...(envlen_p+4)] = [envlen].pack("I!")
|
85
|
+
0
|
86
|
+
end
|
87
|
+
|
88
|
+
# @rbs store: Store
|
89
|
+
# @rbs args: Array[wasmValue]
|
90
|
+
# @rbs return: Object
|
91
|
+
def environ_get(store, args)
|
92
|
+
environ_offsets_p = args[0].value
|
93
|
+
environ_data_buf_p = args[1].value
|
94
|
+
if !environ_data_buf_p.is_a?(Integer)
|
95
|
+
raise ArgumentError, "invalid type of args: #{args.inspect}"
|
96
|
+
end
|
97
|
+
|
98
|
+
environ_offsets = [] #: Array[Integer]
|
99
|
+
environ_data_slice = [] #: Array[String]
|
100
|
+
current_offset = environ_data_buf_p
|
101
|
+
ENV.each do |k, v|
|
102
|
+
environ_offsets << current_offset
|
103
|
+
environ_data_slice << "#{k}=#{v}"
|
104
|
+
current_offset += "#{k}=#{v}".size + 1
|
105
|
+
end
|
106
|
+
environ_data = environ_data_slice.join("\0") + "\0"
|
107
|
+
|
108
|
+
memory = store.memories[0]
|
109
|
+
memory.data[environ_data_buf_p...(environ_data_buf_p + environ_data.size)] = environ_data
|
110
|
+
|
111
|
+
environ_offsets.each_with_index do |offset, i|
|
112
|
+
data_begin = environ_offsets_p + i * 4
|
113
|
+
memory.data[data_begin...(data_begin + 4)] = [offset].pack("I!")
|
114
|
+
end
|
115
|
+
|
116
|
+
0
|
117
|
+
end
|
118
|
+
|
119
|
+
# @rbs store: Store
|
120
|
+
# @rbs args: Array[wasmValue]
|
121
|
+
# @rbs return: Object
|
122
|
+
def clock_time_get(store, args)
|
123
|
+
clock_id = args[0].value
|
124
|
+
# we dont use precision...
|
125
|
+
_precision = args[1].value
|
126
|
+
timebuf64 = args[2].value
|
127
|
+
if clock_id != 0 # - CLOCKID_REALTIME
|
128
|
+
# raise NotImplementedError, "CLOCKID_REALTIME is an only supported id"
|
129
|
+
return -255
|
130
|
+
end
|
131
|
+
# timestamp in nanoseconds
|
132
|
+
now = Time.now.to_i * 1_000_000
|
133
|
+
|
134
|
+
memory = store.memories[0]
|
135
|
+
now_packed = [now].pack("Q!")
|
136
|
+
memory.data[timebuf64...(timebuf64+8)] = now_packed
|
137
|
+
0
|
138
|
+
end
|
139
|
+
|
140
|
+
# @rbs store: Store
|
141
|
+
# @rbs args: Array[wasmValue]
|
142
|
+
# @rbs return: Object
|
143
|
+
def fd_prestat_get(store, args)
|
144
|
+
fd = args[0].value.to_i
|
145
|
+
prestat_offset = args[1].value.to_i
|
146
|
+
if fd >= @fd_table.size
|
147
|
+
return Wasi::EBADF
|
148
|
+
end
|
149
|
+
file = @fd_table[fd]
|
150
|
+
if !file.is_a?(File)
|
151
|
+
return Wasi::EBADF
|
152
|
+
end
|
153
|
+
name = file.path
|
154
|
+
memory = store.memories[0]
|
155
|
+
# Zero-value 8-bit tag, and 3-byte zero-value padding
|
156
|
+
memory.data[prestat_offset...(prestat_offset+4)] = [0].pack("I!")
|
157
|
+
memory.data[(prestat_offset+4)...(prestat_offset+8)] = [name.size].pack("I!")
|
158
|
+
0
|
14
159
|
end
|
15
160
|
|
16
161
|
# @rbs store: Store
|
@@ -29,6 +174,7 @@ module Wardite
|
|
29
174
|
raise Wardite::ArgumentError, "args too short"
|
30
175
|
end
|
31
176
|
file = self.fd_table[fd]
|
177
|
+
return Wasi::EBADF if !file
|
32
178
|
memory = store.memories[0]
|
33
179
|
nwritten = 0
|
34
180
|
iovs_len.times do
|
@@ -45,11 +191,126 @@ module Wardite
|
|
45
191
|
0
|
46
192
|
end
|
47
193
|
|
48
|
-
# @rbs
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
194
|
+
# @rbs store: Store
|
195
|
+
# @rbs args: Array[wasmValue]
|
196
|
+
# @rbs return: Object
|
197
|
+
def fd_read(store, args)
|
198
|
+
iargs = args.map do |elm|
|
199
|
+
if elm.is_a?(I32)
|
200
|
+
elm.value
|
201
|
+
else
|
202
|
+
raise Wardite::ArgumentError, "invalid type of args: #{args.inspect}"
|
203
|
+
end
|
204
|
+
end #: Array[Integer]
|
205
|
+
fd, iovs, iovs_len, rp = *iargs
|
206
|
+
if !fd || !iovs || !iovs_len || !rp
|
207
|
+
raise Wardite::ArgumentError, "args too short"
|
208
|
+
end
|
209
|
+
file = self.fd_table[fd]
|
210
|
+
return Wasi::EBADF if !file
|
211
|
+
memory = store.memories[0]
|
212
|
+
nread = 0
|
213
|
+
|
214
|
+
iovs_len.times do
|
215
|
+
start = unpack_le_int(memory.data[iovs...(iovs+4)])
|
216
|
+
iovs += 4
|
217
|
+
slen = unpack_le_int(memory.data[iovs...(iovs+4)])
|
218
|
+
iovs += 4
|
219
|
+
buf = file.read(slen)
|
220
|
+
if !buf
|
221
|
+
return Wasi::EFAULT
|
222
|
+
end
|
223
|
+
memory.data[start...(start+slen)] = buf
|
224
|
+
nread += slen
|
225
|
+
end
|
226
|
+
|
227
|
+
memory.data[rp...(rp+4)] = [nread].pack("I!")
|
228
|
+
0
|
229
|
+
end
|
230
|
+
|
231
|
+
# @rbs store: Store
|
232
|
+
# @rbs args: Array[wasmValue]
|
233
|
+
# @rbs return: Object
|
234
|
+
def fd_fdstat_get(store, args)
|
235
|
+
fd = args[0].value.to_i
|
236
|
+
fdstat_offset = args[1].value.to_i
|
237
|
+
if fd >= @fd_table.size
|
238
|
+
return Wasi::EBADF
|
239
|
+
end
|
240
|
+
file = @fd_table[fd]
|
241
|
+
fdflags = 0
|
242
|
+
if file.is_a?(IO)
|
243
|
+
fdflags |= Wasi::FD_APPEND
|
244
|
+
else
|
245
|
+
if (Fcntl::O_APPEND & file.fcntl(Fcntl::F_GETFL, 0)) != 0
|
246
|
+
fdflags |= Wasi::FD_APPEND
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
if (Fcntl::O_NONBLOCK & file.fcntl(Fcntl::F_GETFL, 0)) != 0
|
251
|
+
fdflags |= Wasi::FD_NONBLOCK
|
252
|
+
end
|
253
|
+
|
254
|
+
stat = file.stat #: File::Stat
|
255
|
+
ftype = Wasi.to_ftype(stat.ftype)
|
256
|
+
|
257
|
+
fs_right_base = 0
|
258
|
+
fs_right_inheriting = 0
|
259
|
+
|
260
|
+
case ftype
|
261
|
+
when Wasi::FILETYPE_DIRECTORY
|
262
|
+
fs_right_base = Wasi::RIGHT_DIR_RIGHT_BASE
|
263
|
+
fs_right_inheriting = Wasi::RIGHT_FILE_RIGHT_BASE | Wasi::RIGHT_DIR_RIGHT_BASE
|
264
|
+
when Wasi::FILETYPE_CHARACTER_DEVICE
|
265
|
+
fs_right_base = Wasi::RIGHT_FILE_RIGHT_BASE & \
|
266
|
+
(~Wasi::RIGHT_FD_SEEK) & (~Wasi::RIGHT_FD_TELL)
|
267
|
+
else
|
268
|
+
fs_right_base = Wasi::RIGHT_FILE_RIGHT_BASE
|
269
|
+
end
|
270
|
+
|
271
|
+
memory = store.memories[0]
|
272
|
+
|
273
|
+
binformat = [fdflags, ftype, 0, 0, 0, 0, fs_right_base, fs_right_inheriting]
|
274
|
+
.pack("SSC4QQ")
|
275
|
+
memory.data[fdstat_offset...(fdstat_offset+binformat.size)] = binformat
|
276
|
+
0
|
277
|
+
end
|
278
|
+
|
279
|
+
# @rbs store: Store
|
280
|
+
# @rbs args: Array[wasmValue]
|
281
|
+
# @rbs return: Object
|
282
|
+
def fd_filestat_get(store, args)
|
283
|
+
fd = args[0].value.to_i
|
284
|
+
filestat_offset = args[1].value.to_i
|
285
|
+
if fd >= @fd_table.size
|
286
|
+
return Wasi::EBADF
|
287
|
+
end
|
288
|
+
file = @fd_table[fd]
|
289
|
+
stat = file.stat #: File::Stat
|
290
|
+
memory = store.memories[0]
|
291
|
+
binformat = [stat.dev, stat.ino, Wasi.to_ftype(stat.ftype), stat.nlink, stat.size, stat.atime.to_i, stat.mtime.to_i, stat.ctime.to_i].pack("Q8")
|
292
|
+
memory.data[filestat_offset...(filestat_offset+binformat.size)] = binformat
|
293
|
+
0
|
294
|
+
end
|
295
|
+
|
296
|
+
# @rbs store: Store
|
297
|
+
# @rbs args: Array[wasmValue]
|
298
|
+
# @rbs return: Object
|
299
|
+
def proc_exit(store, args)
|
300
|
+
exit_code = args[0].value
|
301
|
+
exit(exit_code)
|
302
|
+
end
|
303
|
+
|
304
|
+
# @rbs store: Store
|
305
|
+
# @rbs args: Array[wasmValue]
|
306
|
+
# @rbs return: Object
|
307
|
+
def random_get(store, args)
|
308
|
+
buf = args[0].value.to_i
|
309
|
+
buflen = args[1].value.to_i
|
310
|
+
randoms = SecureRandom.random_bytes(buflen) #: String
|
311
|
+
memory = store.memories[0]
|
312
|
+
memory.data[buf...(buf+buflen)] = randoms
|
313
|
+
0
|
53
314
|
end
|
54
315
|
|
55
316
|
private
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# rbs_inline: enabled
|
2
|
+
|
3
|
+
module Wardite
|
4
|
+
# @rbs!
|
5
|
+
# interface _WasmCallable
|
6
|
+
# def call: (Store, Array[wasmValue]) -> wasmFuncReturn
|
7
|
+
# def []: (Store, Array[wasmValue]) -> wasmFuncReturn
|
8
|
+
# end
|
9
|
+
|
10
|
+
# @rbs!
|
11
|
+
# type wasmModuleSrc = Hash[Symbol, _WasmCallable] | WasmModule | HashModule
|
12
|
+
# type wasmModule = WasmModule | HashModule
|
13
|
+
|
14
|
+
module WasmModule
|
15
|
+
# @rbs fnname: Symbol
|
16
|
+
# @rbs store: Store
|
17
|
+
# @rbs args: Array[wasmValue]
|
18
|
+
# @rbs return: wasmFuncReturn
|
19
|
+
def invoke(fnname, store, *args)
|
20
|
+
self.__send__(fnname, store, args)
|
21
|
+
end
|
22
|
+
|
23
|
+
# @rbs fnname: Symbol
|
24
|
+
# @rbs return: _WasmCallable
|
25
|
+
def callable(fnname)
|
26
|
+
self.method(fnname)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
class HashModule
|
31
|
+
attr_accessor :hash #: Hash[Symbol, _WasmCallable]
|
32
|
+
|
33
|
+
# @rbs ha: Hash[Symbol, _WasmCallable]
|
34
|
+
def initialize(hash)
|
35
|
+
@hash = hash
|
36
|
+
end
|
37
|
+
|
38
|
+
# @rbs fnname: Symbol
|
39
|
+
# @rbs store: Store
|
40
|
+
# @rbs args: Array[wasmValue]
|
41
|
+
# @rbs return: wasmFuncReturn
|
42
|
+
def invoke(fnname, store, *args)
|
43
|
+
fn = self.hash[fnname.to_sym]
|
44
|
+
fn.call(store, args)
|
45
|
+
end
|
46
|
+
|
47
|
+
# @rbs fnname: Symbol
|
48
|
+
# @rbs return: _WasmCallable
|
49
|
+
def callable(fnname)
|
50
|
+
self.hash[fnname.to_sym]
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
data/lib/wardite.rb
CHANGED
@@ -20,8 +20,6 @@ require_relative "wardite/alu_f32.generated"
|
|
20
20
|
require_relative "wardite/alu_f64.generated"
|
21
21
|
require_relative "wardite/convert.generated"
|
22
22
|
|
23
|
-
require_relative "wardite/wasi"
|
24
|
-
|
25
23
|
require "stringio"
|
26
24
|
|
27
25
|
module Wardite
|
@@ -38,13 +36,23 @@ module Wardite
|
|
38
36
|
|
39
37
|
attr_accessor :exports #: Exports
|
40
38
|
|
41
|
-
attr_reader :import_object #: Hash[Symbol,
|
39
|
+
attr_reader :import_object #: Hash[Symbol, wasmModule]
|
40
|
+
|
41
|
+
attr_accessor :wasi #: WasiSnapshotPreview1?
|
42
42
|
|
43
|
-
# @rbs import_object: Hash[Symbol,
|
43
|
+
# @rbs import_object: Hash[Symbol, wasmModuleSrc]
|
44
44
|
# @rbs &blk: (Instance) -> void
|
45
45
|
def initialize(import_object, &blk)
|
46
|
+
@wasi = nil
|
47
|
+
|
46
48
|
blk.call(self)
|
47
|
-
|
49
|
+
import_object.each_pair do |k, v|
|
50
|
+
if v.is_a?(Hash)
|
51
|
+
import_object[k] = HashModule.new(v)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
@import_object = import_object #: Hash[Symbol, wasmModule]
|
48
56
|
|
49
57
|
@store = Store.new(self)
|
50
58
|
@exports = Exports.new(self.export_section, store)
|
@@ -281,7 +289,8 @@ module Wardite
|
|
281
289
|
|
282
290
|
case fn
|
283
291
|
when WasmFunction
|
284
|
-
invoke_internal(fn)
|
292
|
+
r = invoke_internal(fn)
|
293
|
+
r
|
285
294
|
when ExternalFunction
|
286
295
|
invoke_external(fn)
|
287
296
|
else
|
@@ -313,25 +322,7 @@ module Wardite
|
|
313
322
|
raise LoadError, "stack too short"
|
314
323
|
end
|
315
324
|
self.stack = drained_stack(local_start)
|
316
|
-
|
317
|
-
wasm_function.locals_count.each_with_index do |count, i|
|
318
|
-
typ = wasm_function.locals_type[i]
|
319
|
-
count.times do
|
320
|
-
case typ
|
321
|
-
when :i32, :u32
|
322
|
-
locals.push I32(0)
|
323
|
-
when :i64, :u64
|
324
|
-
locals.push I64(0)
|
325
|
-
when :f32
|
326
|
-
locals.push F32(0.0)
|
327
|
-
when :f64
|
328
|
-
locals.push F64(0.0)
|
329
|
-
else
|
330
|
-
$stderr.puts "warning: unknown type #{typ.inspect}. default to I32"
|
331
|
-
locals.push I32(0)
|
332
|
-
end
|
333
|
-
end
|
334
|
-
end
|
325
|
+
locals.concat(wasm_function.default_locals)
|
335
326
|
|
336
327
|
arity = wasm_function.retsig.size
|
337
328
|
frame = Frame.new(-1, stack.size, wasm_function.body, arity, locals)
|
@@ -473,7 +464,7 @@ module Wardite
|
|
473
464
|
when :block
|
474
465
|
block = insn.operand[0]
|
475
466
|
raise EvalError, "block op without block" if !block.is_a?(Block)
|
476
|
-
next_pc =
|
467
|
+
next_pc = insn.meta[:end_pos]
|
477
468
|
label = Label.new(:block, next_pc, stack.size, block.result_size)
|
478
469
|
frame.labels.push(label)
|
479
470
|
|
@@ -481,19 +472,19 @@ module Wardite
|
|
481
472
|
block = insn.operand[0]
|
482
473
|
raise EvalError, "loop op without block" if !block.is_a?(Block)
|
483
474
|
start = frame.pc
|
484
|
-
|
485
|
-
label = Label.new(:loop,
|
475
|
+
next_pc = insn.meta[:end_pos]
|
476
|
+
label = Label.new(:loop, next_pc, stack.size, block.result_size, start)
|
486
477
|
frame.labels.push(label)
|
487
478
|
|
488
479
|
when :if
|
489
480
|
block = insn.operand[0]
|
490
481
|
raise EvalError, "if op without block" if !block.is_a?(Block)
|
491
|
-
cond = stack.pop
|
482
|
+
cond = stack.pop
|
492
483
|
raise EvalError, "cond not found" if !cond.is_a?(I32)
|
493
|
-
next_pc =
|
484
|
+
next_pc = insn.meta[:end_pos]
|
494
485
|
|
495
486
|
if cond.value.zero?
|
496
|
-
frame.pc =
|
487
|
+
frame.pc = insn.meta[:else_pos]
|
497
488
|
end
|
498
489
|
|
499
490
|
if frame.pc == next_pc
|
@@ -740,38 +731,6 @@ module Wardite
|
|
740
731
|
raise e
|
741
732
|
end
|
742
733
|
|
743
|
-
# @rbs ops: Array[Op]
|
744
|
-
# @rbs pc_start: Integer
|
745
|
-
# @rbs return: Integer
|
746
|
-
def fetch_ops_while_else_or_end(ops, pc_start)
|
747
|
-
cursor = pc_start
|
748
|
-
depth = 0
|
749
|
-
loop {
|
750
|
-
cursor += 1
|
751
|
-
inst = ops[cursor]
|
752
|
-
case inst&.code
|
753
|
-
when nil
|
754
|
-
raise EvalError, "end op not found"
|
755
|
-
when :if
|
756
|
-
depth += 1
|
757
|
-
when :else
|
758
|
-
if depth == 0
|
759
|
-
return cursor
|
760
|
-
end
|
761
|
-
# do not touch depth
|
762
|
-
when :end
|
763
|
-
if depth == 0
|
764
|
-
return cursor
|
765
|
-
else
|
766
|
-
depth -= 1
|
767
|
-
end
|
768
|
-
else
|
769
|
-
# nop
|
770
|
-
end
|
771
|
-
}
|
772
|
-
raise "[BUG] unreachable"
|
773
|
-
end
|
774
|
-
|
775
734
|
# @rbs labels: Array[Label]
|
776
735
|
# @rbs stack: Array[wasmValue]
|
777
736
|
# @rbs level: Integer
|
@@ -797,33 +756,6 @@ module Wardite
|
|
797
756
|
pc
|
798
757
|
end
|
799
758
|
|
800
|
-
# @rbs ops: Array[Op]
|
801
|
-
# @rbs pc_start: Integer
|
802
|
-
# @rbs return: Integer
|
803
|
-
def fetch_ops_while_end(ops, pc_start)
|
804
|
-
cursor = pc_start
|
805
|
-
depth = 0
|
806
|
-
loop {
|
807
|
-
cursor += 1
|
808
|
-
inst = ops[cursor]
|
809
|
-
case inst&.code
|
810
|
-
when nil
|
811
|
-
raise EvalError, "end op not found"
|
812
|
-
when :if, :block, :loop
|
813
|
-
depth += 1
|
814
|
-
when :end
|
815
|
-
if depth == 0
|
816
|
-
return cursor
|
817
|
-
else
|
818
|
-
depth -= 1
|
819
|
-
end
|
820
|
-
else
|
821
|
-
# nop
|
822
|
-
end
|
823
|
-
}
|
824
|
-
raise "[BUG] unreachable"
|
825
|
-
end
|
826
|
-
|
827
759
|
# unwind the stack and put return value if exists
|
828
760
|
# @rbs sp: Integer
|
829
761
|
# @rbs arity: Integer
|
@@ -947,7 +879,7 @@ module Wardite
|
|
947
879
|
class Store
|
948
880
|
attr_accessor :funcs #: Array[WasmFunction|ExternalFunction]
|
949
881
|
|
950
|
-
|
882
|
+
attr_accessor :modules #: Hash[Symbol, wasmModule]
|
951
883
|
|
952
884
|
attr_accessor :memories #: Array[Memory]
|
953
885
|
|
@@ -966,21 +898,19 @@ module Wardite
|
|
966
898
|
|
967
899
|
import_section = inst.import_section
|
968
900
|
@funcs = []
|
901
|
+
@modules = inst.import_object
|
969
902
|
|
970
903
|
if type_section && func_section && code_section
|
971
904
|
import_section.imports.each do |desc|
|
972
905
|
callsig = type_section.defined_types[desc.sig_index]
|
973
906
|
retsig = type_section.defined_results[desc.sig_index]
|
974
|
-
|
975
|
-
if
|
907
|
+
target_module = self.modules[desc.module_name.to_sym]
|
908
|
+
if target_module.nil?
|
976
909
|
raise ::NameError, "module #{desc.module_name} not found"
|
977
910
|
end
|
978
|
-
|
979
|
-
if !imported_proc
|
980
|
-
raise ::NameError, "function #{desc.module_name}.#{desc.name} not found"
|
981
|
-
end
|
911
|
+
target_name = desc.name.to_sym
|
982
912
|
|
983
|
-
ext_function = ExternalFunction.new(callsig, retsig
|
913
|
+
ext_function = ExternalFunction.new(target_module, target_name, callsig, retsig)
|
984
914
|
self.funcs << ext_function
|
985
915
|
end
|
986
916
|
|
@@ -1272,7 +1202,10 @@ module Wardite
|
|
1272
1202
|
end
|
1273
1203
|
|
1274
1204
|
# TODO: common interface btw. WasmFunction and ExternalFunction?
|
1205
|
+
# may be _WasmCallable?
|
1275
1206
|
class WasmFunction
|
1207
|
+
include ValueHelper
|
1208
|
+
|
1276
1209
|
attr_accessor :callsig #: Array[Symbol]
|
1277
1210
|
|
1278
1211
|
attr_accessor :retsig #: Array[Symbol]
|
@@ -1281,6 +1214,8 @@ module Wardite
|
|
1281
1214
|
|
1282
1215
|
attr_accessor :findex #: Integer
|
1283
1216
|
|
1217
|
+
attr_accessor :default_locals #: Array[wasmValue]
|
1218
|
+
|
1284
1219
|
# @rbs callsig: Array[Symbol]
|
1285
1220
|
# @rbs retsig: Array[Symbol]
|
1286
1221
|
# @rbs code_body: CodeSection::CodeBody
|
@@ -1291,6 +1226,7 @@ module Wardite
|
|
1291
1226
|
|
1292
1227
|
@code_body = code_body
|
1293
1228
|
@findex = 0 # for debug
|
1229
|
+
@default_locals = construct_default_locals
|
1294
1230
|
end
|
1295
1231
|
|
1296
1232
|
# @rbs return: Array[Op]
|
@@ -1308,6 +1244,30 @@ module Wardite
|
|
1308
1244
|
code_body.locals_count
|
1309
1245
|
end
|
1310
1246
|
|
1247
|
+
# @rbs return: Array[wasmValue]
|
1248
|
+
def construct_default_locals
|
1249
|
+
locals = [] #: Array[wasmValue]
|
1250
|
+
locals_count.each_with_index do |count, i|
|
1251
|
+
typ = locals_type[i]
|
1252
|
+
count.times do
|
1253
|
+
case typ
|
1254
|
+
when :i32, :u32
|
1255
|
+
locals.push I32(0)
|
1256
|
+
when :i64, :u64
|
1257
|
+
locals.push I64(0)
|
1258
|
+
when :f32
|
1259
|
+
locals.push F32(0.0)
|
1260
|
+
when :f64
|
1261
|
+
locals.push F64(0.0)
|
1262
|
+
else
|
1263
|
+
$stderr.puts "warning: unknown type #{typ.inspect}. default to I32"
|
1264
|
+
locals.push I32(0)
|
1265
|
+
end
|
1266
|
+
end
|
1267
|
+
end
|
1268
|
+
locals
|
1269
|
+
end
|
1270
|
+
|
1311
1271
|
# @rbs override_type: Type?
|
1312
1272
|
# @rbs return: WasmFunction
|
1313
1273
|
def clone(override_type: nil)
|
@@ -1322,23 +1282,32 @@ module Wardite
|
|
1322
1282
|
|
1323
1283
|
# @rbs!
|
1324
1284
|
# type wasmFuncReturn = Object|nil
|
1325
|
-
# type wasmCallable = ^(Store, Array[wasmValue]) -> wasmFuncReturn
|
1326
1285
|
|
1327
1286
|
class ExternalFunction
|
1287
|
+
attr_accessor :target_module #: wasmModule
|
1288
|
+
|
1289
|
+
attr_accessor :name #: Symbol
|
1290
|
+
|
1328
1291
|
attr_accessor :callsig #: Array[Symbol]
|
1329
1292
|
|
1330
1293
|
attr_accessor :retsig #: Array[Symbol]
|
1331
1294
|
|
1332
|
-
attr_accessor :callable #:
|
1295
|
+
#attr_accessor :callable #: _WasmCallable
|
1333
1296
|
|
1334
1297
|
# @rbs callsig: Array[Symbol]
|
1335
1298
|
# @rbs retsig: Array[Symbol]
|
1336
|
-
# @rbs callable:
|
1299
|
+
# @rbs callable: _WasmCallable
|
1337
1300
|
# @rbs return: void
|
1338
|
-
def initialize(callsig, retsig
|
1301
|
+
def initialize(target_module, name, callsig, retsig)
|
1302
|
+
@target_module = target_module
|
1303
|
+
@name = name
|
1339
1304
|
@callsig = callsig
|
1340
1305
|
@retsig = retsig
|
1341
|
-
|
1306
|
+
end
|
1307
|
+
|
1308
|
+
# @rbs return: _WasmCallable
|
1309
|
+
def callable()
|
1310
|
+
target_module.callable(self.name)
|
1342
1311
|
end
|
1343
1312
|
|
1344
1313
|
# @rbs override_type: Type?
|
@@ -1346,9 +1315,9 @@ module Wardite
|
|
1346
1315
|
def clone(override_type: nil)
|
1347
1316
|
if override_type
|
1348
1317
|
# callable is assumed to be frozen, so we can copy its ref
|
1349
|
-
ExternalFunction.new(override_type.callsig, override_type.retsig
|
1318
|
+
ExternalFunction.new(target_module, name, override_type.callsig, override_type.retsig)
|
1350
1319
|
else
|
1351
|
-
ExternalFunction.new(callsig, retsig
|
1320
|
+
ExternalFunction.new(target_module, name, callsig, retsig)
|
1352
1321
|
end
|
1353
1322
|
end
|
1354
1323
|
end
|