wardite 0.5.0 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|