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