wardite 0.2.1 → 0.3.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/examples/break.wat +13 -0
- data/examples/call_indirect.wat +15 -0
- data/examples/global.wat +13 -0
- data/examples/loop.wat +20 -0
- data/examples/start.wat +12 -0
- data/lib/wardite/instruction.rb +12 -6
- data/lib/wardite/load.rb +800 -0
- data/lib/wardite/value.rb +45 -42
- data/lib/wardite/version.rb +1 -1
- data/lib/wardite/wasi.rb +2 -2
- data/lib/wardite.rb +465 -605
- data/sig/generated/wardite/instruction.rbs +8 -5
- data/sig/generated/wardite/load.rbs +236 -0
- data/sig/generated/wardite/value.rbs +82 -80
- data/sig/generated/wardite/wasi.rbs +4 -4
- data/sig/generated/wardite.rbs +120 -181
- data/sig/wardite.rbs +1 -3
- metadata +9 -2
data/lib/wardite.rb
CHANGED
@@ -6,6 +6,7 @@ require_relative "wardite/leb128"
|
|
6
6
|
require_relative "wardite/const"
|
7
7
|
require_relative "wardite/instruction"
|
8
8
|
require_relative "wardite/value"
|
9
|
+
require_relative "wardite/load"
|
9
10
|
|
10
11
|
module Wardite
|
11
12
|
module Evaluator
|
@@ -23,596 +24,6 @@ require_relative "wardite/wasi"
|
|
23
24
|
require "stringio"
|
24
25
|
|
25
26
|
module Wardite
|
26
|
-
class Section
|
27
|
-
attr_accessor :name #: String
|
28
|
-
|
29
|
-
attr_accessor :code #: Integer
|
30
|
-
|
31
|
-
attr_accessor :size #: Integer
|
32
|
-
end
|
33
|
-
|
34
|
-
class TypeSection < Section
|
35
|
-
attr_accessor :defined_types #: Array[Array[Symbol]]
|
36
|
-
|
37
|
-
attr_accessor :defined_results #: Array[Array[Symbol]]
|
38
|
-
|
39
|
-
# @rbs return: void
|
40
|
-
def initialize
|
41
|
-
self.name = "Type"
|
42
|
-
self.code = 0x1
|
43
|
-
|
44
|
-
@defined_types = []
|
45
|
-
@defined_results = []
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
class FunctionSection < Section
|
50
|
-
attr_accessor :func_indices #: Array[Integer]
|
51
|
-
|
52
|
-
# @rbs return: void
|
53
|
-
def initialize
|
54
|
-
self.name = "Function"
|
55
|
-
self.code = 0x3
|
56
|
-
|
57
|
-
@func_indices = []
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
class MemorySection < Section
|
62
|
-
attr_accessor :limits #: Array[[Integer, Integer|nil]]
|
63
|
-
|
64
|
-
# @rbs return: void
|
65
|
-
def initialize
|
66
|
-
self.name = "Memory"
|
67
|
-
self.code = 0x5
|
68
|
-
|
69
|
-
@limits = []
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
class CodeSection < Section
|
74
|
-
class CodeBody
|
75
|
-
attr_accessor :locals_count #: Array[Integer]
|
76
|
-
|
77
|
-
attr_accessor :locals_type #: Array[Symbol]
|
78
|
-
|
79
|
-
attr_accessor :body #: Array[Op]
|
80
|
-
|
81
|
-
# @rbs &blk: (CodeBody) -> void
|
82
|
-
# @rbs return: void
|
83
|
-
def initialize(&blk)
|
84
|
-
blk.call(self)
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
attr_accessor :func_codes #:Array[CodeBody]
|
89
|
-
|
90
|
-
# @rbs return: void
|
91
|
-
def initialize
|
92
|
-
self.name = "Code"
|
93
|
-
self.code = 0xa
|
94
|
-
|
95
|
-
@func_codes = []
|
96
|
-
end
|
97
|
-
end
|
98
|
-
|
99
|
-
class DataSection < Section
|
100
|
-
class Segment
|
101
|
-
attr_accessor :flags #: Integer
|
102
|
-
|
103
|
-
attr_accessor :offset #: Integer
|
104
|
-
|
105
|
-
attr_accessor :data #: String
|
106
|
-
|
107
|
-
# @rbs &blk: (Segment) -> void
|
108
|
-
# @rbs return: void
|
109
|
-
def initialize(&blk)
|
110
|
-
blk.call(self)
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
|
-
attr_accessor :segments #: Array[Segment]
|
115
|
-
|
116
|
-
# @rbs return: void
|
117
|
-
def initialize
|
118
|
-
self.name = "Data"
|
119
|
-
self.code = 0xb
|
120
|
-
|
121
|
-
@segments = []
|
122
|
-
end
|
123
|
-
end
|
124
|
-
|
125
|
-
class ExportSection < Section
|
126
|
-
class ExportDesc
|
127
|
-
attr_accessor :name #: String
|
128
|
-
|
129
|
-
attr_accessor :kind #: Integer
|
130
|
-
|
131
|
-
attr_accessor :func_index #: Integer
|
132
|
-
end
|
133
|
-
|
134
|
-
attr_accessor :exports #: Hash[String, ExportDesc]
|
135
|
-
|
136
|
-
def initialize #: void
|
137
|
-
self.name = "Export"
|
138
|
-
self.code = 0x7
|
139
|
-
|
140
|
-
@exports = {}
|
141
|
-
end
|
142
|
-
|
143
|
-
# @rbs &blk: (ExportDesc) -> void
|
144
|
-
def add_desc(&blk)
|
145
|
-
desc = ExportDesc.new
|
146
|
-
blk.call(desc)
|
147
|
-
self.exports[desc.name] = desc
|
148
|
-
end
|
149
|
-
end
|
150
|
-
|
151
|
-
class ImportSection < Section
|
152
|
-
class ImportDesc
|
153
|
-
attr_accessor :module_name #: String
|
154
|
-
|
155
|
-
attr_accessor :name #: String
|
156
|
-
|
157
|
-
attr_accessor :kind #: Integer
|
158
|
-
|
159
|
-
attr_accessor :sig_index #: Integer
|
160
|
-
end
|
161
|
-
|
162
|
-
attr_accessor :imports #: Array[ImportDesc]
|
163
|
-
|
164
|
-
def initialize #: void
|
165
|
-
self.name = "Import"
|
166
|
-
self.code = 0x2
|
167
|
-
|
168
|
-
@imports = []
|
169
|
-
end
|
170
|
-
|
171
|
-
# @rbs &blk: (ImportDesc) -> void
|
172
|
-
def add_desc(&blk)
|
173
|
-
desc = ImportDesc.new
|
174
|
-
blk.call(desc) if blk
|
175
|
-
self.imports << desc
|
176
|
-
end
|
177
|
-
end
|
178
|
-
|
179
|
-
module BinaryLoader
|
180
|
-
extend Wardite::Leb128Helper
|
181
|
-
extend Wardite::ValueHelper
|
182
|
-
|
183
|
-
# @rbs buf: File|StringIO
|
184
|
-
# @rbs import_object: Hash[Symbol, Hash[Symbol, Proc]]
|
185
|
-
# @rbs enable_wasi: boolish
|
186
|
-
# @rbs return: Instance
|
187
|
-
def self.load_from_buffer(buf, import_object: {}, enable_wasi: true)
|
188
|
-
@buf = buf
|
189
|
-
|
190
|
-
version = preamble
|
191
|
-
sections_ = sections
|
192
|
-
|
193
|
-
if enable_wasi
|
194
|
-
wasi_env = Wardite::WasiSnapshotPreview1.new
|
195
|
-
import_object[:wasi_snapshot_preview1] = wasi_env.to_module
|
196
|
-
end
|
197
|
-
|
198
|
-
return Instance.new(import_object) do |i|
|
199
|
-
i.version = version
|
200
|
-
i.sections = sections_
|
201
|
-
end
|
202
|
-
end
|
203
|
-
|
204
|
-
# @rbs return: Integer
|
205
|
-
def self.preamble
|
206
|
-
asm = @buf.read 4
|
207
|
-
if !asm
|
208
|
-
raise LoadError, "buffer too short"
|
209
|
-
end
|
210
|
-
if asm != "\u0000asm"
|
211
|
-
raise LoadError, "invalid preamble"
|
212
|
-
end
|
213
|
-
|
214
|
-
vstr = @buf.read(4)
|
215
|
-
if !vstr
|
216
|
-
raise LoadError, "buffer too short"
|
217
|
-
end
|
218
|
-
version = vstr.to_enum(:chars)
|
219
|
-
.with_index
|
220
|
-
.inject(0) {|dest, (c, i)| dest | (c.ord << i*8) }
|
221
|
-
if version != 1
|
222
|
-
raise LoadError, "unsupported version: #{version}"
|
223
|
-
end
|
224
|
-
version
|
225
|
-
end
|
226
|
-
|
227
|
-
# @rbs return: Array[Section]
|
228
|
-
def self.sections
|
229
|
-
sections = [] #: Array[Section]
|
230
|
-
|
231
|
-
loop do
|
232
|
-
byte = @buf.read(1)
|
233
|
-
if !byte
|
234
|
-
break
|
235
|
-
end
|
236
|
-
code = byte.ord
|
237
|
-
|
238
|
-
section = case code
|
239
|
-
when Wardite::SectionType
|
240
|
-
type_section
|
241
|
-
when Wardite::SectionImport
|
242
|
-
import_section
|
243
|
-
when Wardite::SectionFunction
|
244
|
-
function_section
|
245
|
-
when Wardite::SectionTable
|
246
|
-
unimplemented_skip_section(code)
|
247
|
-
when Wardite::SectionMemory
|
248
|
-
memory_section
|
249
|
-
when Wardite::SectionGlobal
|
250
|
-
unimplemented_skip_section(code)
|
251
|
-
when Wardite::SectionExport
|
252
|
-
export_section
|
253
|
-
when Wardite::SectionStart
|
254
|
-
unimplemented_skip_section(code)
|
255
|
-
when Wardite::SectionElement
|
256
|
-
unimplemented_skip_section(code)
|
257
|
-
when Wardite::SectionCode
|
258
|
-
code_section
|
259
|
-
when Wardite::SectionData
|
260
|
-
data_section
|
261
|
-
when Wardite::SectionCustom
|
262
|
-
unimplemented_skip_section(code)
|
263
|
-
else
|
264
|
-
raise LoadError, "unknown code: #{code}(\"#{code.to_s 16}\")"
|
265
|
-
end
|
266
|
-
|
267
|
-
if section
|
268
|
-
sections << section
|
269
|
-
end
|
270
|
-
end
|
271
|
-
sections
|
272
|
-
end
|
273
|
-
|
274
|
-
# @rbs return: TypeSection
|
275
|
-
def self.type_section
|
276
|
-
dest = TypeSection.new
|
277
|
-
|
278
|
-
size = fetch_uleb128(@buf)
|
279
|
-
dest.size = size
|
280
|
-
sbuf = StringIO.new(@buf.read(size) || raise("buffer too short"))
|
281
|
-
|
282
|
-
len = fetch_uleb128(sbuf)
|
283
|
-
len.times do |i|
|
284
|
-
fncode = assert_read(sbuf, 1)
|
285
|
-
if fncode != "\x60"
|
286
|
-
raise LoadError, "not a function definition"
|
287
|
-
end
|
288
|
-
|
289
|
-
arglen = fetch_uleb128(sbuf)
|
290
|
-
arg = []
|
291
|
-
arglen.times do
|
292
|
-
case ty = assert_read(sbuf, 1)&.ord
|
293
|
-
when 0x7f
|
294
|
-
arg << :i32
|
295
|
-
when 0x7e
|
296
|
-
arg << :i64
|
297
|
-
when 0x7d
|
298
|
-
arg << :f32
|
299
|
-
when 0x7c
|
300
|
-
arg << :f64
|
301
|
-
else
|
302
|
-
raise NotImplementedError, "unsupported for now: #{ty.inspect}"
|
303
|
-
end
|
304
|
-
end
|
305
|
-
dest.defined_types << arg
|
306
|
-
|
307
|
-
retlen = fetch_uleb128(sbuf)
|
308
|
-
ret = []
|
309
|
-
retlen.times do
|
310
|
-
case ty = assert_read(sbuf, 1)&.ord
|
311
|
-
when 0x7f
|
312
|
-
ret << :i32
|
313
|
-
when 0x7e
|
314
|
-
ret << :i64
|
315
|
-
when 0x7d
|
316
|
-
ret << :f32
|
317
|
-
when 0x7c
|
318
|
-
ret << :f64
|
319
|
-
else
|
320
|
-
raise NotImplementedError, "unsupported for now: #{ty.inspect}"
|
321
|
-
end
|
322
|
-
end
|
323
|
-
dest.defined_results << ret
|
324
|
-
end
|
325
|
-
|
326
|
-
dest
|
327
|
-
end
|
328
|
-
|
329
|
-
# @rbs return: ImportSection
|
330
|
-
def self.import_section
|
331
|
-
dest = ImportSection.new
|
332
|
-
size = fetch_uleb128(@buf)
|
333
|
-
dest.size = size
|
334
|
-
sbuf = StringIO.new(@buf.read(size) || raise("buffer too short"))
|
335
|
-
|
336
|
-
len = fetch_uleb128(sbuf)
|
337
|
-
len.times do |i|
|
338
|
-
mlen = fetch_uleb128(sbuf)
|
339
|
-
module_name = assert_read(sbuf, mlen)
|
340
|
-
nlen = fetch_uleb128(sbuf)
|
341
|
-
name = assert_read(sbuf, nlen)
|
342
|
-
kind_ = assert_read(sbuf, 1)
|
343
|
-
kind = kind_[0]&.ord
|
344
|
-
if !kind
|
345
|
-
raise "[BUG] empty unpacked string" # guard rbs
|
346
|
-
end
|
347
|
-
|
348
|
-
index = fetch_uleb128(sbuf)
|
349
|
-
dest.add_desc do |desc|
|
350
|
-
desc.module_name = module_name
|
351
|
-
desc.name = name
|
352
|
-
desc.kind = kind
|
353
|
-
desc.sig_index = index
|
354
|
-
end
|
355
|
-
end
|
356
|
-
|
357
|
-
dest
|
358
|
-
end
|
359
|
-
|
360
|
-
# @rbs return: MemorySection
|
361
|
-
def self.memory_section
|
362
|
-
dest = MemorySection.new
|
363
|
-
size = fetch_uleb128(@buf)
|
364
|
-
dest.size = size
|
365
|
-
sbuf = StringIO.new(@buf.read(size) || raise("buffer too short"))
|
366
|
-
|
367
|
-
len = fetch_uleb128(sbuf)
|
368
|
-
if len != 1
|
369
|
-
raise LoadError, "memory section has invalid size: #{len}"
|
370
|
-
end
|
371
|
-
len.times do |i|
|
372
|
-
flags = fetch_uleb128(sbuf)
|
373
|
-
min = fetch_uleb128(sbuf)
|
374
|
-
|
375
|
-
max = nil
|
376
|
-
if flags != 0
|
377
|
-
max = fetch_uleb128(sbuf)
|
378
|
-
end
|
379
|
-
dest.limits << [min, max]
|
380
|
-
end
|
381
|
-
dest
|
382
|
-
end
|
383
|
-
|
384
|
-
# @rbs return: FunctionSection
|
385
|
-
def self.function_section
|
386
|
-
dest = FunctionSection.new
|
387
|
-
size = fetch_uleb128(@buf)
|
388
|
-
dest.size = size
|
389
|
-
sbuf = StringIO.new(@buf.read(size) || raise("buffer too short"))
|
390
|
-
|
391
|
-
len = fetch_uleb128(sbuf)
|
392
|
-
len.times do |i|
|
393
|
-
index = fetch_uleb128(sbuf)
|
394
|
-
dest.func_indices << index
|
395
|
-
end
|
396
|
-
dest
|
397
|
-
end
|
398
|
-
|
399
|
-
# @rbs return: CodeSection
|
400
|
-
def self.code_section
|
401
|
-
dest = CodeSection.new
|
402
|
-
size = fetch_uleb128(@buf)
|
403
|
-
dest.size = size
|
404
|
-
sbuf = StringIO.new(@buf.read(size) || raise("buffer too short"))
|
405
|
-
|
406
|
-
len = fetch_uleb128(sbuf)
|
407
|
-
len.times do |i|
|
408
|
-
ilen = fetch_uleb128(sbuf)
|
409
|
-
code = assert_read(sbuf, ilen)
|
410
|
-
last_code = code[-1]
|
411
|
-
if ! last_code
|
412
|
-
raise "[BUG] empty code fetched" # guard for steep check
|
413
|
-
end
|
414
|
-
if last_code.ord != 0x0b
|
415
|
-
$stderr.puts "warning: instruction not ended with inst end(0x0b): 0x0#{last_code.ord}"
|
416
|
-
end
|
417
|
-
cbuf = StringIO.new(code)
|
418
|
-
locals_count = []
|
419
|
-
locals_type = []
|
420
|
-
locals_len = fetch_uleb128(cbuf)
|
421
|
-
locals_len.times do
|
422
|
-
type_count = fetch_uleb128(cbuf)
|
423
|
-
locals_count << type_count
|
424
|
-
value_type = assert_read(cbuf, 1)&.ord
|
425
|
-
locals_type << Op.i2type(value_type || -1)
|
426
|
-
end
|
427
|
-
body = code_body(cbuf)
|
428
|
-
dest.func_codes << CodeSection::CodeBody.new do |b|
|
429
|
-
b.locals_count = locals_count
|
430
|
-
b.locals_type = locals_type
|
431
|
-
b.body = body
|
432
|
-
end
|
433
|
-
end
|
434
|
-
dest
|
435
|
-
end
|
436
|
-
|
437
|
-
# @rbs buf: StringIO
|
438
|
-
# @rbs return: Array[::Wardite::Op]
|
439
|
-
def self.code_body(buf)
|
440
|
-
dest = []
|
441
|
-
while c = buf.read(1)
|
442
|
-
namespace, code = Op.to_sym(c)
|
443
|
-
operand_types = Op.operand_of(code)
|
444
|
-
operand = [] #: Array[Integer|Float|Block]
|
445
|
-
operand_types.each do |typ|
|
446
|
-
case typ
|
447
|
-
when :u8
|
448
|
-
ope = buf.read 1
|
449
|
-
if ! ope
|
450
|
-
raise LoadError, "buffer too short"
|
451
|
-
end
|
452
|
-
operand << ope.ord
|
453
|
-
when :u32
|
454
|
-
operand << fetch_uleb128(buf)
|
455
|
-
when :i32
|
456
|
-
operand << fetch_sleb128(buf)
|
457
|
-
when :i64
|
458
|
-
operand << fetch_sleb128(buf)
|
459
|
-
when :f32
|
460
|
-
data = buf.read 4
|
461
|
-
if !data || data.size != 4
|
462
|
-
raise LoadError, "buffer too short"
|
463
|
-
end
|
464
|
-
v = data.unpack("e")[0]
|
465
|
-
raise "String#unpack is broken" if !v.is_a?(Float)
|
466
|
-
operand << v
|
467
|
-
when :f64
|
468
|
-
data = buf.read 8
|
469
|
-
if !data || data.size != 8
|
470
|
-
raise LoadError, "buffer too short"
|
471
|
-
end
|
472
|
-
v = data.unpack("E")[0]
|
473
|
-
raise "String#unpack is broken" if !v.is_a?(Float)
|
474
|
-
operand << v
|
475
|
-
when :u8_if_block # :if specific
|
476
|
-
block_ope = buf.read 1
|
477
|
-
if ! block_ope
|
478
|
-
raise LoadError, "buffer too short for if"
|
479
|
-
end
|
480
|
-
if block_ope.ord == 0x40
|
481
|
-
operand << Block.void
|
482
|
-
else
|
483
|
-
operand << Block.new([block_ope.ord])
|
484
|
-
end
|
485
|
-
else
|
486
|
-
$stderr.puts "warning: unknown type #{typ.inspect}. defaulting to u32"
|
487
|
-
operand << fetch_uleb128(buf)
|
488
|
-
end
|
489
|
-
end
|
490
|
-
|
491
|
-
dest << Op.new(namespace, code, operand)
|
492
|
-
end
|
493
|
-
|
494
|
-
dest
|
495
|
-
end
|
496
|
-
|
497
|
-
# @rbs return: DataSection
|
498
|
-
def self.data_section
|
499
|
-
dest = DataSection.new
|
500
|
-
size = fetch_uleb128(@buf)
|
501
|
-
dest.size = size
|
502
|
-
sbuf = StringIO.new(@buf.read(size) || raise("buffer too short"))
|
503
|
-
|
504
|
-
len = fetch_uleb128(sbuf)
|
505
|
-
len.times do |i|
|
506
|
-
mem_index = fetch_uleb128(sbuf)
|
507
|
-
code = fetch_insn_while_end(sbuf)
|
508
|
-
ops = code_body(StringIO.new(code))
|
509
|
-
offset = decode_expr(ops)
|
510
|
-
|
511
|
-
len = fetch_uleb128(sbuf)
|
512
|
-
data = sbuf.read len
|
513
|
-
if !data
|
514
|
-
raise LoadError, "buffer too short"
|
515
|
-
end
|
516
|
-
|
517
|
-
segment = DataSection::Segment.new do |seg|
|
518
|
-
seg.flags = mem_index
|
519
|
-
seg.offset = offset
|
520
|
-
seg.data = data
|
521
|
-
end
|
522
|
-
dest.segments << segment
|
523
|
-
end
|
524
|
-
dest
|
525
|
-
end
|
526
|
-
|
527
|
-
# @rbs sbuf: StringIO
|
528
|
-
# @rbs return: String
|
529
|
-
def self.fetch_insn_while_end(sbuf)
|
530
|
-
code = String.new("")
|
531
|
-
loop {
|
532
|
-
c = sbuf.read 1
|
533
|
-
if !c
|
534
|
-
break
|
535
|
-
end
|
536
|
-
code << c
|
537
|
-
if c == "\u000b" # :end
|
538
|
-
break
|
539
|
-
end
|
540
|
-
}
|
541
|
-
code
|
542
|
-
end
|
543
|
-
|
544
|
-
# @rbs ops: Array[Op]
|
545
|
-
# @rbs return: Integer
|
546
|
-
def self.decode_expr(ops)
|
547
|
-
# sees first opcode
|
548
|
-
op = ops.first
|
549
|
-
if !op
|
550
|
-
raise LoadError, "empty opcodes"
|
551
|
-
end
|
552
|
-
case op.code
|
553
|
-
when :i32_const
|
554
|
-
arg = op.operand[0]
|
555
|
-
if !arg.is_a?(Integer)
|
556
|
-
raise "Invalid definition of operand"
|
557
|
-
end
|
558
|
-
return arg
|
559
|
-
else
|
560
|
-
raise "Unimplemented offset op: #{op.code.inspect}"
|
561
|
-
end
|
562
|
-
end
|
563
|
-
|
564
|
-
# @rbs return: ExportSection
|
565
|
-
def self.export_section
|
566
|
-
dest = ExportSection.new
|
567
|
-
size = fetch_uleb128(@buf)
|
568
|
-
dest.size = size
|
569
|
-
sbuf = StringIO.new(@buf.read(size) || raise("buffer too short"))
|
570
|
-
|
571
|
-
len = fetch_uleb128(sbuf)
|
572
|
-
len.times do |i|
|
573
|
-
nlen = fetch_uleb128(sbuf)
|
574
|
-
name = assert_read(sbuf, nlen)
|
575
|
-
kind_ = assert_read(sbuf, 1)
|
576
|
-
kind = kind_[0]&.ord
|
577
|
-
if !kind
|
578
|
-
raise "[BUG] empty unpacked string" # guard rbs
|
579
|
-
end
|
580
|
-
|
581
|
-
index = fetch_uleb128(sbuf)
|
582
|
-
dest.add_desc do |desc|
|
583
|
-
desc.name = name
|
584
|
-
desc.kind = kind
|
585
|
-
desc.func_index = index
|
586
|
-
end
|
587
|
-
end
|
588
|
-
|
589
|
-
dest
|
590
|
-
end
|
591
|
-
|
592
|
-
# @rbs code: Integer
|
593
|
-
# @rbs return: nil
|
594
|
-
def self.unimplemented_skip_section(code)
|
595
|
-
$stderr.puts "warning: unimplemented section: 0x0#{code}"
|
596
|
-
size = @buf.read(1)&.ord
|
597
|
-
@buf.read(size)
|
598
|
-
nil
|
599
|
-
end
|
600
|
-
|
601
|
-
# @rbs sbuf: StringIO
|
602
|
-
# @rbs n: Integer
|
603
|
-
# @rbs return: String
|
604
|
-
def self.assert_read(sbuf, n)
|
605
|
-
ret = sbuf.read n
|
606
|
-
if !ret
|
607
|
-
raise LoadError, "too short section size"
|
608
|
-
end
|
609
|
-
if ret.size != n
|
610
|
-
raise LoadError, "too short section size"
|
611
|
-
end
|
612
|
-
ret
|
613
|
-
end
|
614
|
-
end
|
615
|
-
|
616
27
|
class Instance
|
617
28
|
attr_accessor :version #: Integer
|
618
29
|
|
@@ -620,13 +31,15 @@ module Wardite
|
|
620
31
|
|
621
32
|
attr_accessor :runtime #: Runtime
|
622
33
|
|
34
|
+
attr_accessor :types #: Array[Type]
|
35
|
+
|
623
36
|
attr_accessor :store #: Store
|
624
37
|
|
625
38
|
attr_accessor :exports #: Exports
|
626
39
|
|
627
|
-
attr_reader :import_object #: Hash[Symbol, Hash[Symbol,
|
40
|
+
attr_reader :import_object #: Hash[Symbol, Hash[Symbol, wasmCallable]]
|
628
41
|
|
629
|
-
# @rbs import_object: Hash[Symbol, Hash[Symbol,
|
42
|
+
# @rbs import_object: Hash[Symbol, Hash[Symbol, wasmCallable]]
|
630
43
|
# @rbs &blk: (Instance) -> void
|
631
44
|
def initialize(import_object, &blk)
|
632
45
|
blk.call(self)
|
@@ -635,6 +48,15 @@ module Wardite
|
|
635
48
|
@store = Store.new(self)
|
636
49
|
@exports = Exports.new(self.export_section, store)
|
637
50
|
@runtime = Runtime.new(self)
|
51
|
+
|
52
|
+
@types = []
|
53
|
+
type_section = self.type_section
|
54
|
+
if type_section
|
55
|
+
type_section.defined_types.each_with_index do |calltype, idx|
|
56
|
+
rettype = type_section.defined_results[idx]
|
57
|
+
@types << Type.new(calltype, rettype)
|
58
|
+
end
|
59
|
+
end
|
638
60
|
end
|
639
61
|
|
640
62
|
# @rbs return: ImportSection
|
@@ -671,6 +93,30 @@ module Wardite
|
|
671
93
|
sec
|
672
94
|
end
|
673
95
|
|
96
|
+
# @rbs return: StartSection|nil
|
97
|
+
def start_section
|
98
|
+
sec = @sections.find{|s| s.code == Const::SectionStart }
|
99
|
+
if !sec
|
100
|
+
return nil
|
101
|
+
end
|
102
|
+
if !sec.is_a?(StartSection)
|
103
|
+
raise(GenericError, "[BUG] found invalid start section")
|
104
|
+
end
|
105
|
+
sec
|
106
|
+
end
|
107
|
+
|
108
|
+
# @rbs return: GlobalSection|nil
|
109
|
+
def global_section
|
110
|
+
sec = @sections.find{|s| s.code == Const::SectionGlobal }
|
111
|
+
if !sec
|
112
|
+
return nil
|
113
|
+
end
|
114
|
+
if !sec.is_a?(GlobalSection)
|
115
|
+
raise(GenericError, "instance doesn't have required section")
|
116
|
+
end
|
117
|
+
sec
|
118
|
+
end
|
119
|
+
|
674
120
|
# @rbs return: DataSection|nil
|
675
121
|
def data_section
|
676
122
|
sec = @sections.find{|s| s.code == Const::SectionData }
|
@@ -695,6 +141,30 @@ module Wardite
|
|
695
141
|
sec
|
696
142
|
end
|
697
143
|
|
144
|
+
# @rbs return: TableSection?
|
145
|
+
def table_section
|
146
|
+
sec = @sections.find{|s| s.code == Const::SectionTable }
|
147
|
+
if !sec
|
148
|
+
return nil
|
149
|
+
end
|
150
|
+
if !sec.is_a?(TableSection)
|
151
|
+
raise(GenericError, "instance doesn't have required section")
|
152
|
+
end
|
153
|
+
sec
|
154
|
+
end
|
155
|
+
|
156
|
+
# @rbs return: ElemSection?
|
157
|
+
def elem_section
|
158
|
+
sec = @sections.find{|s| s.code == Const::SectionElement }
|
159
|
+
if !sec
|
160
|
+
return nil
|
161
|
+
end
|
162
|
+
if !sec.is_a?(ElemSection)
|
163
|
+
raise(GenericError, "instance doesn't have required section")
|
164
|
+
end
|
165
|
+
sec
|
166
|
+
end
|
167
|
+
|
698
168
|
# @rbs return: CodeSection|nil
|
699
169
|
def code_section
|
700
170
|
sec = @sections.find{|s| s.code == Const::SectionCode }
|
@@ -724,7 +194,7 @@ module Wardite
|
|
724
194
|
include ValueHelper
|
725
195
|
|
726
196
|
# TODO: add types of class that the stack accomodates
|
727
|
-
attr_accessor :stack #: Array[
|
197
|
+
attr_accessor :stack #: Array[wasmValue]
|
728
198
|
|
729
199
|
attr_accessor :call_stack #: Array[Frame]
|
730
200
|
|
@@ -735,8 +205,18 @@ module Wardite
|
|
735
205
|
@stack = []
|
736
206
|
@call_stack = []
|
737
207
|
@instance = inst
|
208
|
+
|
209
|
+
invoke_start_section
|
738
210
|
end
|
739
211
|
|
212
|
+
# @rbs return: void
|
213
|
+
def invoke_start_section
|
214
|
+
start_section = instance.start_section
|
215
|
+
if start_section
|
216
|
+
call_by_index(start_section.func_index)
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
740
220
|
# @rbs name: String|Symbol
|
741
221
|
# @rbs return: bool
|
742
222
|
def callable?(name)
|
@@ -777,6 +257,21 @@ module Wardite
|
|
777
257
|
end
|
778
258
|
end
|
779
259
|
|
260
|
+
# @rbs idx: Integer
|
261
|
+
# @rbs return: void
|
262
|
+
def call_by_index(idx)
|
263
|
+
fn = @instance.store.funcs[idx]
|
264
|
+
|
265
|
+
case fn
|
266
|
+
when WasmFunction
|
267
|
+
invoke_internal(fn)
|
268
|
+
when ExternalFunction
|
269
|
+
invoke_external(fn)
|
270
|
+
else
|
271
|
+
raise GenericError, "registered pointer is not to a function"
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
780
275
|
# @rbs wasm_function: WasmFunction
|
781
276
|
# @rbs return: void
|
782
277
|
def push_frame(wasm_function)
|
@@ -826,7 +321,7 @@ module Wardite
|
|
826
321
|
end
|
827
322
|
|
828
323
|
# @rbs external_function: ExternalFunction
|
829
|
-
# @rbs return:
|
324
|
+
# @rbs return: wasmValue|nil
|
830
325
|
def invoke_external(external_function)
|
831
326
|
local_start = stack.size - external_function.callsig.size
|
832
327
|
args = stack[local_start..]
|
@@ -903,19 +398,80 @@ module Wardite
|
|
903
398
|
when :nop
|
904
399
|
return
|
905
400
|
|
401
|
+
when :br
|
402
|
+
level = insn.operand[0]
|
403
|
+
raise EvalError, "br op without level" if !level.is_a?(Integer)
|
404
|
+
pc = do_branch(frame.labels, stack, level)
|
405
|
+
frame.pc = pc
|
406
|
+
|
407
|
+
when :br_if
|
408
|
+
level = insn.operand[0]
|
409
|
+
raise EvalError, "br op without level" if !level.is_a?(Integer)
|
410
|
+
cond = stack.pop
|
411
|
+
raise EvalError, "cond not found" if !cond.is_a?(I32)
|
412
|
+
if cond.value.zero?
|
413
|
+
return
|
414
|
+
end
|
415
|
+
pc = do_branch(frame.labels, stack, level)
|
416
|
+
frame.pc = pc
|
417
|
+
|
418
|
+
when :br_table
|
419
|
+
level_vec = insn.operand[0]
|
420
|
+
raise EvalError, "no level vector" if !level_vec.is_a?(Array)
|
421
|
+
default = insn.operand[1]
|
422
|
+
raise EvalError, "no default specified" if !default.is_a?(Integer)
|
423
|
+
idx = stack.pop
|
424
|
+
raise EvalError, "idx not found" if !idx.is_a?(I32)
|
425
|
+
level = if idx.value_s < 0 || idx.value_s >= level_vec.size
|
426
|
+
default
|
427
|
+
else
|
428
|
+
level_vec[idx.value_s]
|
429
|
+
end
|
430
|
+
pc = do_branch(frame.labels, stack, level)
|
431
|
+
frame.pc = pc
|
432
|
+
|
433
|
+
when :block
|
434
|
+
block = insn.operand[0]
|
435
|
+
raise EvalError, "block op without block" if !block.is_a?(Block)
|
436
|
+
next_pc = fetch_ops_while_end(frame.body, frame.pc)
|
437
|
+
label = Label.new(:block, next_pc, stack.size, block.result_size)
|
438
|
+
frame.labels.push(label)
|
439
|
+
|
440
|
+
when :loop
|
441
|
+
block = insn.operand[0]
|
442
|
+
raise EvalError, "loop op without block" if !block.is_a?(Block)
|
443
|
+
start = frame.pc
|
444
|
+
end_pc = fetch_ops_while_end(frame.body, frame.pc)
|
445
|
+
label = Label.new(:loop, end_pc, stack.size, block.result_size, start)
|
446
|
+
frame.labels.push(label)
|
447
|
+
|
906
448
|
when :if
|
907
449
|
block = insn.operand[0]
|
908
450
|
raise EvalError, "if op without block" if !block.is_a?(Block)
|
909
451
|
cond = stack.pop
|
910
452
|
raise EvalError, "cond not found" if !cond.is_a?(I32)
|
911
453
|
next_pc = fetch_ops_while_end(frame.body, frame.pc)
|
454
|
+
|
912
455
|
if cond.value.zero?
|
913
|
-
frame.pc =
|
456
|
+
frame.pc = fetch_ops_while_else_or_end(frame.body, frame.pc)
|
457
|
+
end
|
458
|
+
|
459
|
+
if frame.pc == next_pc
|
460
|
+
# This means if block has no else instr.
|
461
|
+
return
|
914
462
|
end
|
915
463
|
|
916
464
|
label = Label.new(:if, next_pc, stack.size, block.result_size)
|
917
465
|
frame.labels.push(label)
|
918
466
|
|
467
|
+
when :else
|
468
|
+
if old_label = frame.labels.pop
|
469
|
+
frame.pc = old_label.pc
|
470
|
+
stack_unwind(old_label.sp, old_label.arity)
|
471
|
+
else
|
472
|
+
raise EvalError, "else should be in if block"
|
473
|
+
end
|
474
|
+
|
919
475
|
when :call
|
920
476
|
idx = insn.operand[0]
|
921
477
|
raise EvalError, "[BUG] local operand not found" if !idx.is_a?(Integer)
|
@@ -930,6 +486,45 @@ module Wardite
|
|
930
486
|
raise GenericError, "got a non-function pointer"
|
931
487
|
end
|
932
488
|
|
489
|
+
when :call_indirect
|
490
|
+
table = self.instance.store.tables[0]
|
491
|
+
raise EvalError, "table required but not found" if !table
|
492
|
+
type_idx = insn.operand[0]
|
493
|
+
raise EvalError, "[BUG] index operand invalid" if !type_idx.is_a?(Integer)
|
494
|
+
nullbyte = insn.operand[1]
|
495
|
+
raise EvalError, "[BUG] invalid bytearray of call_indirect" if nullbyte != 0x0
|
496
|
+
table_idx = stack.pop
|
497
|
+
raise EvalError, "[BUG] index stack invalid" if !table_idx.is_a?(I32)
|
498
|
+
fntype = self.instance.types[type_idx]
|
499
|
+
if !fntype
|
500
|
+
raise EvalError, "undefined type index: idx=#{type_idx}"
|
501
|
+
end
|
502
|
+
refs = self.instance.store.tables[0]&.refs
|
503
|
+
if !refs
|
504
|
+
raise EvalError, "uninitialized element idx:#{table_idx}"
|
505
|
+
end
|
506
|
+
|
507
|
+
fn = refs[table_idx.value]
|
508
|
+
case fn
|
509
|
+
when WasmFunction
|
510
|
+
if table.type != :funcref
|
511
|
+
raise EvalError, "invalid type of elem; expected: #{table.type}"
|
512
|
+
end
|
513
|
+
fn = fn.clone(override_type: fntype)
|
514
|
+
push_frame(fn)
|
515
|
+
when ExternalFunction
|
516
|
+
if table.type != :externref
|
517
|
+
raise EvalError, "invalid type of elem; expected: #{table.type}"
|
518
|
+
end
|
519
|
+
fn = fn.clone(override_type: fntype)
|
520
|
+
ret = invoke_external(fn)
|
521
|
+
self.stack.push ret if ret
|
522
|
+
when nil
|
523
|
+
raise EvalError, "uninitialized element idx:#{table_idx.value}"
|
524
|
+
else
|
525
|
+
raise EvalError, "[BUG] unknwon function type #{fn}"
|
526
|
+
end
|
527
|
+
|
933
528
|
when :return
|
934
529
|
old_frame = call_stack.pop
|
935
530
|
if !old_frame
|
@@ -985,6 +580,48 @@ module Wardite
|
|
985
580
|
end
|
986
581
|
frame.locals[idx] = value
|
987
582
|
|
583
|
+
when :local_tee
|
584
|
+
idx = insn.operand[0]
|
585
|
+
if !idx.is_a?(Integer)
|
586
|
+
raise EvalError, "[BUG] invalid type of operand"
|
587
|
+
end
|
588
|
+
value = stack.pop
|
589
|
+
if !value
|
590
|
+
raise EvalError, "value should be pushed"
|
591
|
+
end
|
592
|
+
frame.locals[idx] = value
|
593
|
+
stack.push value
|
594
|
+
|
595
|
+
when :global_get
|
596
|
+
idx = insn.operand[0]
|
597
|
+
if !idx.is_a?(Integer)
|
598
|
+
raise EvalError, "[BUG] invalid type of operand"
|
599
|
+
end
|
600
|
+
global = instance.store.globals[idx]
|
601
|
+
if !global
|
602
|
+
raise EvalError, "global not found"
|
603
|
+
end
|
604
|
+
stack.push(global.value)
|
605
|
+
|
606
|
+
when :global_set
|
607
|
+
idx = insn.operand[0]
|
608
|
+
if !idx.is_a?(Integer)
|
609
|
+
raise EvalError, "[BUG] invalid type of operand"
|
610
|
+
end
|
611
|
+
current_global = instance.store.globals[idx]
|
612
|
+
if !current_global
|
613
|
+
raise EvalError, "global index not valid"
|
614
|
+
end
|
615
|
+
if !current_global.mutable?
|
616
|
+
raise EvalError, "global not mutable"
|
617
|
+
end
|
618
|
+
value = stack.pop
|
619
|
+
if !value
|
620
|
+
raise EvalError, "value should be pushed"
|
621
|
+
end
|
622
|
+
current_global.value = value
|
623
|
+
instance.store.globals[idx] = current_global
|
624
|
+
|
988
625
|
when :memory_size
|
989
626
|
memory = instance.store.memories[0] || raise("[BUG] no memory")
|
990
627
|
stack.push(I32(memory.current))
|
@@ -1003,11 +640,69 @@ module Wardite
|
|
1003
640
|
|
1004
641
|
rescue => e
|
1005
642
|
require "pp"
|
643
|
+
$stderr.puts "instance:::\n#{self.instance.pretty_inspect}"
|
1006
644
|
$stderr.puts "frame:::\n#{frame.pretty_inspect}"
|
1007
645
|
$stderr.puts "stack:::\n#{stack.pretty_inspect}"
|
1008
646
|
raise e
|
1009
647
|
end
|
1010
648
|
|
649
|
+
# @rbs ops: Array[Op]
|
650
|
+
# @rbs pc_start: Integer
|
651
|
+
# @rbs return: Integer
|
652
|
+
def fetch_ops_while_else_or_end(ops, pc_start)
|
653
|
+
cursor = pc_start
|
654
|
+
depth = 0
|
655
|
+
loop {
|
656
|
+
cursor += 1
|
657
|
+
inst = ops[cursor]
|
658
|
+
case inst&.code
|
659
|
+
when nil
|
660
|
+
raise EvalError, "end op not found"
|
661
|
+
when :if
|
662
|
+
depth += 1
|
663
|
+
when :else
|
664
|
+
if depth == 0
|
665
|
+
return cursor
|
666
|
+
end
|
667
|
+
# do not touch depth
|
668
|
+
when :end
|
669
|
+
if depth == 0
|
670
|
+
return cursor
|
671
|
+
else
|
672
|
+
depth -= 1
|
673
|
+
end
|
674
|
+
else
|
675
|
+
# nop
|
676
|
+
end
|
677
|
+
}
|
678
|
+
raise "[BUG] unreachable"
|
679
|
+
end
|
680
|
+
|
681
|
+
# @rbs labels: Array[Label]
|
682
|
+
# @rbs stack: Array[wasmValue]
|
683
|
+
# @rbs level: Integer
|
684
|
+
# @rbs return: Integer
|
685
|
+
def do_branch(labels, stack, level)
|
686
|
+
idx = labels.size - 1 - level
|
687
|
+
label = labels[idx]
|
688
|
+
pc = if label.kind == :loop
|
689
|
+
# keep the top of labels for loop again...
|
690
|
+
while labels.size > idx + 1
|
691
|
+
labels.pop
|
692
|
+
end
|
693
|
+
stack_unwind(label.sp, 0)
|
694
|
+
label.start || raise(EvalError, "loop withour start")
|
695
|
+
else
|
696
|
+
while labels.size > idx
|
697
|
+
labels.pop
|
698
|
+
end
|
699
|
+
stack_unwind(label.sp, label.arity)
|
700
|
+
label.pc
|
701
|
+
end
|
702
|
+
|
703
|
+
pc
|
704
|
+
end
|
705
|
+
|
1011
706
|
# @rbs ops: Array[Op]
|
1012
707
|
# @rbs pc_start: Integer
|
1013
708
|
# @rbs return: Integer
|
@@ -1020,7 +715,7 @@ module Wardite
|
|
1020
715
|
case inst&.code
|
1021
716
|
when nil
|
1022
717
|
raise EvalError, "end op not found"
|
1023
|
-
when :
|
718
|
+
when :if, :block, :loop
|
1024
719
|
depth += 1
|
1025
720
|
when :end
|
1026
721
|
if depth == 0
|
@@ -1056,7 +751,7 @@ module Wardite
|
|
1056
751
|
end
|
1057
752
|
|
1058
753
|
# @rbs finish: Integer
|
1059
|
-
# @rbs return: Array[
|
754
|
+
# @rbs return: Array[wasmValue]
|
1060
755
|
def drained_stack(finish)
|
1061
756
|
drained = stack[0...finish]
|
1062
757
|
if ! drained
|
@@ -1084,6 +779,20 @@ module Wardite
|
|
1084
779
|
end
|
1085
780
|
end
|
1086
781
|
|
782
|
+
class Type
|
783
|
+
attr_accessor :callsig #: Array[Symbol]
|
784
|
+
|
785
|
+
attr_accessor :retsig #: Array[Symbol]
|
786
|
+
|
787
|
+
# @rbs callsig: Array[Symbol]
|
788
|
+
# @rbs retsig: Array[Symbol]
|
789
|
+
# @rbs returb: void
|
790
|
+
def initialize(callsig, retsig)
|
791
|
+
@callsig = callsig
|
792
|
+
@retsig = retsig
|
793
|
+
end
|
794
|
+
end
|
795
|
+
|
1087
796
|
class Frame
|
1088
797
|
attr_accessor :pc #: Integer
|
1089
798
|
attr_accessor :sp #: Integer
|
@@ -1094,13 +803,13 @@ module Wardite
|
|
1094
803
|
|
1095
804
|
attr_accessor :labels #: Array[Label]
|
1096
805
|
|
1097
|
-
attr_accessor :locals #: Array[
|
806
|
+
attr_accessor :locals #: Array[wasmValue]
|
1098
807
|
|
1099
808
|
# @rbs pc: Integer
|
1100
809
|
# @rbs sp: Integer
|
1101
810
|
# @rbs body: Array[Op]
|
1102
811
|
# @rbs arity: Integer
|
1103
|
-
# @rbs locals: Array[
|
812
|
+
# @rbs locals: Array[wasmValue]
|
1104
813
|
# @rbs returb: void
|
1105
814
|
def initialize(pc, sp, body, arity, locals)
|
1106
815
|
@pc = pc
|
@@ -1120,16 +829,20 @@ module Wardite
|
|
1120
829
|
|
1121
830
|
attr_accessor :arity #: Integer
|
1122
831
|
|
832
|
+
attr_accessor :start #: Integer|nil
|
833
|
+
|
1123
834
|
# @rbs kind: (:if|:loop|:block)
|
1124
835
|
# @rbs pc: Integer
|
1125
836
|
# @rbs sp: Integer
|
1126
837
|
# @rbs arity: Integer
|
1127
|
-
# @rbs
|
1128
|
-
|
838
|
+
# @rbs start: Integer|nil
|
839
|
+
# @rbs return: void
|
840
|
+
def initialize(kind, pc, sp, arity, start=nil)
|
1129
841
|
@kind = kind
|
1130
842
|
@pc = pc
|
1131
843
|
@sp = sp
|
1132
844
|
@arity = arity
|
845
|
+
@start = start
|
1133
846
|
end
|
1134
847
|
end
|
1135
848
|
|
@@ -1137,9 +850,15 @@ module Wardite
|
|
1137
850
|
attr_accessor :funcs #: Array[WasmFunction|ExternalFunction]
|
1138
851
|
|
1139
852
|
# FIXME: attr_accessor :modules
|
1140
|
-
|
853
|
+
|
1141
854
|
attr_accessor :memories #: Array[Memory]
|
1142
855
|
|
856
|
+
attr_accessor :globals #: Array[Global]
|
857
|
+
|
858
|
+
attr_accessor :tables #: Array[Table]
|
859
|
+
|
860
|
+
attr_accessor :elements #: Array[[Symbol, Integer, Array[Integer]]]
|
861
|
+
|
1143
862
|
# @rbs inst: Instance
|
1144
863
|
# @rbs return: void
|
1145
864
|
def initialize(inst)
|
@@ -1201,6 +920,69 @@ module Wardite
|
|
1201
920
|
end
|
1202
921
|
end
|
1203
922
|
end
|
923
|
+
|
924
|
+
@globals = []
|
925
|
+
global_section = inst.global_section
|
926
|
+
if global_section
|
927
|
+
global_section.globals.each do |g|
|
928
|
+
@globals << Global.new do |g2|
|
929
|
+
g2.type = g.type
|
930
|
+
g2.mutable = g.mutable
|
931
|
+
g2.shared = g.shared
|
932
|
+
g2.value = g.value
|
933
|
+
end
|
934
|
+
end
|
935
|
+
end
|
936
|
+
|
937
|
+
@tables = []
|
938
|
+
@elements = []
|
939
|
+
table_section = inst.table_section
|
940
|
+
if table_section
|
941
|
+
table_section.table_types.each_with_index do |typ, idx|
|
942
|
+
init, max = *table_section.table_limits[idx]
|
943
|
+
if !init
|
944
|
+
raise LoadError, "empty limits"
|
945
|
+
end
|
946
|
+
table = Table.new(typ, init, max)
|
947
|
+
@tables << table
|
948
|
+
end
|
949
|
+
end
|
950
|
+
|
951
|
+
elem_section = inst.elem_section
|
952
|
+
if elem_section
|
953
|
+
elem_section.table_indices.each_with_index do |tidx, idx|
|
954
|
+
table = @tables[tidx]
|
955
|
+
if !table
|
956
|
+
raise LoadError, "invalid table index #{tidx}"
|
957
|
+
end
|
958
|
+
typ = table.type
|
959
|
+
offset = elem_section.table_offsets[idx]
|
960
|
+
if !offset
|
961
|
+
raise LoadError, "invalid element index #{idx}"
|
962
|
+
end
|
963
|
+
indices = elem_section.element_indices[idx]
|
964
|
+
if !indices
|
965
|
+
raise LoadError, "invalid element index #{idx}"
|
966
|
+
end
|
967
|
+
elms = [typ, offset, indices] #: [Symbol, Integer, Array[Integer]]
|
968
|
+
@elements << elms
|
969
|
+
end
|
970
|
+
end
|
971
|
+
|
972
|
+
@elements.each_with_index do |(typ, offset, indices), idx|
|
973
|
+
table = @tables[idx]
|
974
|
+
if !table
|
975
|
+
raise LoadError, "invalid table index #{idx}"
|
976
|
+
end
|
977
|
+
indices.each_with_index do |eidx, tidx|
|
978
|
+
case typ
|
979
|
+
when :funcref
|
980
|
+
table.set(offset + tidx, @funcs[eidx])
|
981
|
+
when :externref
|
982
|
+
raise NotImplementedError, "no support :externref"
|
983
|
+
end
|
984
|
+
end
|
985
|
+
end
|
1204
986
|
end
|
1205
987
|
|
1206
988
|
# @rbs idx: Integer
|
@@ -1243,6 +1025,58 @@ module Wardite
|
|
1243
1025
|
end
|
1244
1026
|
end
|
1245
1027
|
|
1028
|
+
class Table
|
1029
|
+
attr_accessor :type #: Symbol
|
1030
|
+
|
1031
|
+
attr_accessor :current #: Integer
|
1032
|
+
|
1033
|
+
attr_accessor :max #: Integer|nil
|
1034
|
+
|
1035
|
+
attr_accessor :refs #: Array[WasmFunction|ExternalFunction|nil]
|
1036
|
+
|
1037
|
+
# @rbs type: Symbol
|
1038
|
+
# @rbs init: Integer
|
1039
|
+
# @rbs max: Integer|nil
|
1040
|
+
# @rbs return: void
|
1041
|
+
def initialize(type, init, max)
|
1042
|
+
@type = type
|
1043
|
+
@current = init
|
1044
|
+
@max = max
|
1045
|
+
|
1046
|
+
@refs = Array.new(3, nil)
|
1047
|
+
end
|
1048
|
+
|
1049
|
+
# @rbs idx: Integer
|
1050
|
+
# @rbs elem: WasmFunction|ExternalFunction|nil
|
1051
|
+
# @rbs return: void
|
1052
|
+
def set(idx, elem)
|
1053
|
+
if idx >= @current
|
1054
|
+
raise GenericError, "idx too large for table"
|
1055
|
+
end
|
1056
|
+
@refs[idx] = elem
|
1057
|
+
end
|
1058
|
+
end
|
1059
|
+
|
1060
|
+
class Global
|
1061
|
+
attr_accessor :type #: Symbol
|
1062
|
+
|
1063
|
+
attr_accessor :mutable #: bool
|
1064
|
+
|
1065
|
+
# TODO: unused in wasm 1.0 spec?
|
1066
|
+
attr_accessor :shared #: bool
|
1067
|
+
|
1068
|
+
attr_accessor :value #: wasmValue
|
1069
|
+
|
1070
|
+
# @rbs &blk: (Global) -> void
|
1071
|
+
# @rbs return: void
|
1072
|
+
def initialize(&blk)
|
1073
|
+
blk.call(self)
|
1074
|
+
end
|
1075
|
+
|
1076
|
+
alias mutable? mutable
|
1077
|
+
alias shared? shared
|
1078
|
+
end
|
1079
|
+
|
1246
1080
|
class WasmData
|
1247
1081
|
attr_accessor :memory_index #: Integer
|
1248
1082
|
|
@@ -1341,25 +1175,51 @@ module Wardite
|
|
1341
1175
|
# @rbs return: Array[Integer]
|
1342
1176
|
def locals_count
|
1343
1177
|
code_body.locals_count
|
1344
|
-
end
|
1178
|
+
end
|
1179
|
+
|
1180
|
+
# @rbs override_type: Type?
|
1181
|
+
# @rbs return: WasmFunction
|
1182
|
+
def clone(override_type: nil)
|
1183
|
+
if override_type
|
1184
|
+
# code_body is assumed to be frozen, so we can copy its ref
|
1185
|
+
WasmFunction.new(override_type.callsig, override_type.retsig, code_body)
|
1186
|
+
else
|
1187
|
+
WasmFunction.new(callsig, retsig, code_body)
|
1188
|
+
end
|
1189
|
+
end
|
1345
1190
|
end
|
1346
1191
|
|
1192
|
+
# @rbs!
|
1193
|
+
# type wasmFuncReturn = Object|nil
|
1194
|
+
# type wasmCallable = ^(Store, Array[wasmValue]) -> wasmFuncReturn
|
1195
|
+
|
1347
1196
|
class ExternalFunction
|
1348
1197
|
attr_accessor :callsig #: Array[Symbol]
|
1349
1198
|
|
1350
1199
|
attr_accessor :retsig #: Array[Symbol]
|
1351
1200
|
|
1352
|
-
attr_accessor :callable #:
|
1201
|
+
attr_accessor :callable #: wasmCallable
|
1353
1202
|
|
1354
1203
|
# @rbs callsig: Array[Symbol]
|
1355
1204
|
# @rbs retsig: Array[Symbol]
|
1356
|
-
# @rbs callable:
|
1205
|
+
# @rbs callable: wasmCallable
|
1357
1206
|
# @rbs return: void
|
1358
1207
|
def initialize(callsig, retsig, callable)
|
1359
1208
|
@callsig = callsig
|
1360
1209
|
@retsig = retsig
|
1361
1210
|
@callable = callable
|
1362
1211
|
end
|
1212
|
+
|
1213
|
+
# @rbs override_type: Type?
|
1214
|
+
# @rbs return: ExternalFunction
|
1215
|
+
def clone(override_type: nil)
|
1216
|
+
if override_type
|
1217
|
+
# callable is assumed to be frozen, so we can copy its ref
|
1218
|
+
ExternalFunction.new(override_type.callsig, override_type.retsig, callable)
|
1219
|
+
else
|
1220
|
+
ExternalFunction.new(callsig, retsig, callable)
|
1221
|
+
end
|
1222
|
+
end
|
1363
1223
|
end
|
1364
1224
|
|
1365
1225
|
class GenericError < StandardError; end
|