wardite 0.2.2 → 0.4.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/Rakefile +6 -0
- data/examples/break.wat +13 -0
- data/examples/call_indirect.wat +15 -0
- data/examples/loop.wat +20 -0
- data/examples/memory_init.wat +18 -0
- data/examples/saturate.wat +8 -0
- data/examples/saturate_u.wat +9 -0
- data/examples/start.wat +12 -0
- data/lib/wardite/const.rb +13 -12
- data/lib/wardite/convert.generated.rb +104 -0
- data/lib/wardite/instruction.rb +67 -8
- data/lib/wardite/load.rb +216 -28
- data/lib/wardite/value.rb +247 -70
- data/lib/wardite/version.rb +1 -1
- data/lib/wardite/wasi.rb +2 -2
- data/lib/wardite.rb +471 -17
- data/scripts/gen_conv.rb +12 -2
- data/sig/generated/wardite/const.rbs +2 -0
- data/sig/generated/wardite/instruction.rbs +15 -3
- data/sig/generated/wardite/load.rbs +63 -7
- data/sig/generated/wardite/value.rbs +142 -82
- data/sig/generated/wardite/wasi.rbs +4 -4
- data/sig/generated/wardite.rbs +103 -17
- data/sig/wardite.rbs +1 -3
- metadata +9 -2
data/lib/wardite.rb
CHANGED
@@ -31,13 +31,15 @@ module Wardite
|
|
31
31
|
|
32
32
|
attr_accessor :runtime #: Runtime
|
33
33
|
|
34
|
+
attr_accessor :types #: Array[Type]
|
35
|
+
|
34
36
|
attr_accessor :store #: Store
|
35
37
|
|
36
38
|
attr_accessor :exports #: Exports
|
37
39
|
|
38
|
-
attr_reader :import_object #: Hash[Symbol, Hash[Symbol,
|
40
|
+
attr_reader :import_object #: Hash[Symbol, Hash[Symbol, wasmCallable]]
|
39
41
|
|
40
|
-
# @rbs import_object: Hash[Symbol, Hash[Symbol,
|
42
|
+
# @rbs import_object: Hash[Symbol, Hash[Symbol, wasmCallable]]
|
41
43
|
# @rbs &blk: (Instance) -> void
|
42
44
|
def initialize(import_object, &blk)
|
43
45
|
blk.call(self)
|
@@ -46,6 +48,31 @@ module Wardite
|
|
46
48
|
@store = Store.new(self)
|
47
49
|
@exports = Exports.new(self.export_section, store)
|
48
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
|
60
|
+
|
61
|
+
check_data_count
|
62
|
+
end
|
63
|
+
|
64
|
+
# @rbs return: void
|
65
|
+
def check_data_count
|
66
|
+
data_count = self.data_count_section&.count
|
67
|
+
if data_count
|
68
|
+
actual_count = self.data_section&.segments&.size
|
69
|
+
if !actual_count
|
70
|
+
raise LoadError, "invalid data segment count"
|
71
|
+
end
|
72
|
+
if (data_count != actual_count)
|
73
|
+
raise LoadError, "invalid data segment count"
|
74
|
+
end
|
75
|
+
end
|
49
76
|
end
|
50
77
|
|
51
78
|
# @rbs return: ImportSection
|
@@ -82,6 +109,18 @@ module Wardite
|
|
82
109
|
sec
|
83
110
|
end
|
84
111
|
|
112
|
+
# @rbs return: StartSection|nil
|
113
|
+
def start_section
|
114
|
+
sec = @sections.find{|s| s.code == Const::SectionStart }
|
115
|
+
if !sec
|
116
|
+
return nil
|
117
|
+
end
|
118
|
+
if !sec.is_a?(StartSection)
|
119
|
+
raise(GenericError, "[BUG] found invalid start section")
|
120
|
+
end
|
121
|
+
sec
|
122
|
+
end
|
123
|
+
|
85
124
|
# @rbs return: GlobalSection|nil
|
86
125
|
def global_section
|
87
126
|
sec = @sections.find{|s| s.code == Const::SectionGlobal }
|
@@ -106,6 +145,18 @@ module Wardite
|
|
106
145
|
sec
|
107
146
|
end
|
108
147
|
|
148
|
+
# @rbs return: DataCountSection|nil
|
149
|
+
def data_count_section
|
150
|
+
sec = @sections.find{|s| s.code == Const::SectionDataCount }
|
151
|
+
if !sec
|
152
|
+
return nil
|
153
|
+
end
|
154
|
+
if !sec.is_a?(DataCountSection)
|
155
|
+
raise(GenericError, "[BUG] found invalid data section")
|
156
|
+
end
|
157
|
+
sec
|
158
|
+
end
|
159
|
+
|
109
160
|
# @rbs return: FunctionSection|nil
|
110
161
|
def function_section
|
111
162
|
sec = @sections.find{|s| s.code == Const::SectionFunction }
|
@@ -118,6 +169,30 @@ module Wardite
|
|
118
169
|
sec
|
119
170
|
end
|
120
171
|
|
172
|
+
# @rbs return: TableSection?
|
173
|
+
def table_section
|
174
|
+
sec = @sections.find{|s| s.code == Const::SectionTable }
|
175
|
+
if !sec
|
176
|
+
return nil
|
177
|
+
end
|
178
|
+
if !sec.is_a?(TableSection)
|
179
|
+
raise(GenericError, "instance doesn't have required section")
|
180
|
+
end
|
181
|
+
sec
|
182
|
+
end
|
183
|
+
|
184
|
+
# @rbs return: ElemSection?
|
185
|
+
def elem_section
|
186
|
+
sec = @sections.find{|s| s.code == Const::SectionElement }
|
187
|
+
if !sec
|
188
|
+
return nil
|
189
|
+
end
|
190
|
+
if !sec.is_a?(ElemSection)
|
191
|
+
raise(GenericError, "instance doesn't have required section")
|
192
|
+
end
|
193
|
+
sec
|
194
|
+
end
|
195
|
+
|
121
196
|
# @rbs return: CodeSection|nil
|
122
197
|
def code_section
|
123
198
|
sec = @sections.find{|s| s.code == Const::SectionCode }
|
@@ -147,7 +222,7 @@ module Wardite
|
|
147
222
|
include ValueHelper
|
148
223
|
|
149
224
|
# TODO: add types of class that the stack accomodates
|
150
|
-
attr_accessor :stack #: Array[
|
225
|
+
attr_accessor :stack #: Array[wasmValue]
|
151
226
|
|
152
227
|
attr_accessor :call_stack #: Array[Frame]
|
153
228
|
|
@@ -158,6 +233,16 @@ module Wardite
|
|
158
233
|
@stack = []
|
159
234
|
@call_stack = []
|
160
235
|
@instance = inst
|
236
|
+
|
237
|
+
invoke_start_section
|
238
|
+
end
|
239
|
+
|
240
|
+
# @rbs return: void
|
241
|
+
def invoke_start_section
|
242
|
+
start_section = instance.start_section
|
243
|
+
if start_section
|
244
|
+
call_by_index(start_section.func_index)
|
245
|
+
end
|
161
246
|
end
|
162
247
|
|
163
248
|
# @rbs name: String|Symbol
|
@@ -200,6 +285,21 @@ module Wardite
|
|
200
285
|
end
|
201
286
|
end
|
202
287
|
|
288
|
+
# @rbs idx: Integer
|
289
|
+
# @rbs return: void
|
290
|
+
def call_by_index(idx)
|
291
|
+
fn = @instance.store.funcs[idx]
|
292
|
+
|
293
|
+
case fn
|
294
|
+
when WasmFunction
|
295
|
+
invoke_internal(fn)
|
296
|
+
when ExternalFunction
|
297
|
+
invoke_external(fn)
|
298
|
+
else
|
299
|
+
raise GenericError, "registered pointer is not to a function"
|
300
|
+
end
|
301
|
+
end
|
302
|
+
|
203
303
|
# @rbs wasm_function: WasmFunction
|
204
304
|
# @rbs return: void
|
205
305
|
def push_frame(wasm_function)
|
@@ -249,7 +349,7 @@ module Wardite
|
|
249
349
|
end
|
250
350
|
|
251
351
|
# @rbs external_function: ExternalFunction
|
252
|
-
# @rbs return:
|
352
|
+
# @rbs return: wasmValue|nil
|
253
353
|
def invoke_external(external_function)
|
254
354
|
local_start = stack.size - external_function.callsig.size
|
255
355
|
args = stack[local_start..]
|
@@ -326,19 +426,80 @@ module Wardite
|
|
326
426
|
when :nop
|
327
427
|
return
|
328
428
|
|
429
|
+
when :br
|
430
|
+
level = insn.operand[0]
|
431
|
+
raise EvalError, "br op without level" if !level.is_a?(Integer)
|
432
|
+
pc = do_branch(frame.labels, stack, level)
|
433
|
+
frame.pc = pc
|
434
|
+
|
435
|
+
when :br_if
|
436
|
+
level = insn.operand[0]
|
437
|
+
raise EvalError, "br op without level" if !level.is_a?(Integer)
|
438
|
+
cond = stack.pop
|
439
|
+
raise EvalError, "cond not found" if !cond.is_a?(I32)
|
440
|
+
if cond.value.zero?
|
441
|
+
return
|
442
|
+
end
|
443
|
+
pc = do_branch(frame.labels, stack, level)
|
444
|
+
frame.pc = pc
|
445
|
+
|
446
|
+
when :br_table
|
447
|
+
level_vec = insn.operand[0]
|
448
|
+
raise EvalError, "no level vector" if !level_vec.is_a?(Array)
|
449
|
+
default = insn.operand[1]
|
450
|
+
raise EvalError, "no default specified" if !default.is_a?(Integer)
|
451
|
+
idx = stack.pop
|
452
|
+
raise EvalError, "idx not found" if !idx.is_a?(I32)
|
453
|
+
level = if idx.value_s < 0 || idx.value_s >= level_vec.size
|
454
|
+
default
|
455
|
+
else
|
456
|
+
level_vec[idx.value_s]
|
457
|
+
end
|
458
|
+
pc = do_branch(frame.labels, stack, level)
|
459
|
+
frame.pc = pc
|
460
|
+
|
461
|
+
when :block
|
462
|
+
block = insn.operand[0]
|
463
|
+
raise EvalError, "block op without block" if !block.is_a?(Block)
|
464
|
+
next_pc = fetch_ops_while_end(frame.body, frame.pc)
|
465
|
+
label = Label.new(:block, next_pc, stack.size, block.result_size)
|
466
|
+
frame.labels.push(label)
|
467
|
+
|
468
|
+
when :loop
|
469
|
+
block = insn.operand[0]
|
470
|
+
raise EvalError, "loop op without block" if !block.is_a?(Block)
|
471
|
+
start = frame.pc
|
472
|
+
end_pc = fetch_ops_while_end(frame.body, frame.pc)
|
473
|
+
label = Label.new(:loop, end_pc, stack.size, block.result_size, start)
|
474
|
+
frame.labels.push(label)
|
475
|
+
|
329
476
|
when :if
|
330
477
|
block = insn.operand[0]
|
331
478
|
raise EvalError, "if op without block" if !block.is_a?(Block)
|
332
479
|
cond = stack.pop
|
333
480
|
raise EvalError, "cond not found" if !cond.is_a?(I32)
|
334
481
|
next_pc = fetch_ops_while_end(frame.body, frame.pc)
|
482
|
+
|
335
483
|
if cond.value.zero?
|
336
|
-
frame.pc =
|
484
|
+
frame.pc = fetch_ops_while_else_or_end(frame.body, frame.pc)
|
485
|
+
end
|
486
|
+
|
487
|
+
if frame.pc == next_pc
|
488
|
+
# This means if block has no else instr.
|
489
|
+
return
|
337
490
|
end
|
338
491
|
|
339
492
|
label = Label.new(:if, next_pc, stack.size, block.result_size)
|
340
493
|
frame.labels.push(label)
|
341
494
|
|
495
|
+
when :else
|
496
|
+
if old_label = frame.labels.pop
|
497
|
+
frame.pc = old_label.pc
|
498
|
+
stack_unwind(old_label.sp, old_label.arity)
|
499
|
+
else
|
500
|
+
raise EvalError, "else should be in if block"
|
501
|
+
end
|
502
|
+
|
342
503
|
when :call
|
343
504
|
idx = insn.operand[0]
|
344
505
|
raise EvalError, "[BUG] local operand not found" if !idx.is_a?(Integer)
|
@@ -353,6 +514,45 @@ module Wardite
|
|
353
514
|
raise GenericError, "got a non-function pointer"
|
354
515
|
end
|
355
516
|
|
517
|
+
when :call_indirect
|
518
|
+
table = self.instance.store.tables[0]
|
519
|
+
raise EvalError, "table required but not found" if !table
|
520
|
+
type_idx = insn.operand[0]
|
521
|
+
raise EvalError, "[BUG] index operand invalid" if !type_idx.is_a?(Integer)
|
522
|
+
nullbyte = insn.operand[1]
|
523
|
+
raise EvalError, "[BUG] invalid bytearray of call_indirect" if nullbyte != 0x0
|
524
|
+
table_idx = stack.pop
|
525
|
+
raise EvalError, "[BUG] index stack invalid" if !table_idx.is_a?(I32)
|
526
|
+
fntype = self.instance.types[type_idx]
|
527
|
+
if !fntype
|
528
|
+
raise EvalError, "undefined type index: idx=#{type_idx}"
|
529
|
+
end
|
530
|
+
refs = self.instance.store.tables[0]&.refs
|
531
|
+
if !refs
|
532
|
+
raise EvalError, "uninitialized element idx:#{table_idx}"
|
533
|
+
end
|
534
|
+
|
535
|
+
fn = refs[table_idx.value]
|
536
|
+
case fn
|
537
|
+
when WasmFunction
|
538
|
+
if table.type != :funcref
|
539
|
+
raise EvalError, "invalid type of elem; expected: #{table.type}"
|
540
|
+
end
|
541
|
+
fn = fn.clone(override_type: fntype)
|
542
|
+
push_frame(fn)
|
543
|
+
when ExternalFunction
|
544
|
+
if table.type != :externref
|
545
|
+
raise EvalError, "invalid type of elem; expected: #{table.type}"
|
546
|
+
end
|
547
|
+
fn = fn.clone(override_type: fntype)
|
548
|
+
ret = invoke_external(fn)
|
549
|
+
self.stack.push ret if ret
|
550
|
+
when nil
|
551
|
+
raise EvalError, "uninitialized element idx:#{table_idx.value}"
|
552
|
+
else
|
553
|
+
raise EvalError, "[BUG] unknwon function type #{fn}"
|
554
|
+
end
|
555
|
+
|
356
556
|
when :return
|
357
557
|
old_frame = call_stack.pop
|
358
558
|
if !old_frame
|
@@ -408,6 +608,18 @@ module Wardite
|
|
408
608
|
end
|
409
609
|
frame.locals[idx] = value
|
410
610
|
|
611
|
+
when :local_tee
|
612
|
+
idx = insn.operand[0]
|
613
|
+
if !idx.is_a?(Integer)
|
614
|
+
raise EvalError, "[BUG] invalid type of operand"
|
615
|
+
end
|
616
|
+
value = stack.pop
|
617
|
+
if !value
|
618
|
+
raise EvalError, "value should be pushed"
|
619
|
+
end
|
620
|
+
frame.locals[idx] = value
|
621
|
+
stack.push value
|
622
|
+
|
411
623
|
when :global_get
|
412
624
|
idx = insn.operand[0]
|
413
625
|
if !idx.is_a?(Integer)
|
@@ -450,17 +662,126 @@ module Wardite
|
|
450
662
|
memory = instance.store.memories[0] || raise("[BUG] no memory")
|
451
663
|
stack.push(I32(memory.grow(delta.value)))
|
452
664
|
|
665
|
+
when :memory_init
|
666
|
+
idx = insn.operand[0]
|
667
|
+
if !idx.is_a?(Integer)
|
668
|
+
raise EvalError, "[BUG] invalid type of operand"
|
669
|
+
end
|
670
|
+
if insn.operand[1] != 0x0
|
671
|
+
$stderr.puts "warning: :memory_init is not ending with 0x00"
|
672
|
+
end
|
673
|
+
data_sec = instance.data_section
|
674
|
+
if !data_sec
|
675
|
+
raise EvalError, "data segment out of range"
|
676
|
+
end
|
677
|
+
data_seg = data_sec.segments[idx]
|
678
|
+
if !data_seg
|
679
|
+
raise EvalError, "data segment out of range"
|
680
|
+
end
|
681
|
+
|
682
|
+
memory = instance.store.memories[0] || raise("[BUG] no memory")
|
683
|
+
length, src_offset, dest_offset = stack.pop, stack.pop, stack.pop
|
684
|
+
if !length.is_a?(I32) || !src_offset.is_a?(I32) || !dest_offset.is_a?(I32)
|
685
|
+
raise EvalError, "invalid stack values"
|
686
|
+
end
|
687
|
+
source = data_seg.data[src_offset.value...(src_offset.value+length.value)]
|
688
|
+
raise EvalError, "invalid source range" if !source
|
689
|
+
memory.data[dest_offset.value...(dest_offset.value+length.value)] = source
|
690
|
+
|
691
|
+
when :memory_copy
|
692
|
+
if insn.operand[0] != 0x0 || insn.operand[1] != 0x0
|
693
|
+
$stderr.puts "warning: :memory_copy is not ending with 0x00"
|
694
|
+
end
|
695
|
+
length, src_offset, dest_offset = stack.pop, stack.pop, stack.pop
|
696
|
+
if !length.is_a?(I32) || !src_offset.is_a?(I32) || !dest_offset.is_a?(I32)
|
697
|
+
raise EvalError, "invalid stack values"
|
698
|
+
end
|
699
|
+
memory = instance.store.memories[0] || raise("[BUG] no memory")
|
700
|
+
source = memory.data[src_offset.value...(src_offset.value+length.value)]
|
701
|
+
raise EvalError, "invalid source range" if !source
|
702
|
+
memory.data[dest_offset.value...(dest_offset.value+length.value)] = source
|
703
|
+
|
704
|
+
when :memory_fill
|
705
|
+
if insn.operand[0] != 0x0
|
706
|
+
$stderr.puts "warning: :memory_fill is not ending with 0x00"
|
707
|
+
end
|
708
|
+
length, byte, dest_offset = stack.pop, stack.pop, stack.pop
|
709
|
+
if !length.is_a?(I32) || !byte.is_a?(I32) || !dest_offset.is_a?(I32)
|
710
|
+
raise EvalError, "invalid stack values"
|
711
|
+
end
|
712
|
+
memory = instance.store.memories[0] || raise("[BUG] no memory")
|
713
|
+
source = byte.value.chr * length.value
|
714
|
+
memory.data[dest_offset.value...(dest_offset.value+length.value)] = source
|
715
|
+
|
453
716
|
else
|
454
717
|
raise "TODO! unsupported #{insn.inspect}"
|
455
718
|
end
|
456
719
|
|
457
720
|
rescue => e
|
458
721
|
require "pp"
|
722
|
+
$stderr.puts "instance:::\n#{self.instance.pretty_inspect}"
|
459
723
|
$stderr.puts "frame:::\n#{frame.pretty_inspect}"
|
460
724
|
$stderr.puts "stack:::\n#{stack.pretty_inspect}"
|
461
725
|
raise e
|
462
726
|
end
|
463
727
|
|
728
|
+
# @rbs ops: Array[Op]
|
729
|
+
# @rbs pc_start: Integer
|
730
|
+
# @rbs return: Integer
|
731
|
+
def fetch_ops_while_else_or_end(ops, pc_start)
|
732
|
+
cursor = pc_start
|
733
|
+
depth = 0
|
734
|
+
loop {
|
735
|
+
cursor += 1
|
736
|
+
inst = ops[cursor]
|
737
|
+
case inst&.code
|
738
|
+
when nil
|
739
|
+
raise EvalError, "end op not found"
|
740
|
+
when :if
|
741
|
+
depth += 1
|
742
|
+
when :else
|
743
|
+
if depth == 0
|
744
|
+
return cursor
|
745
|
+
end
|
746
|
+
# do not touch depth
|
747
|
+
when :end
|
748
|
+
if depth == 0
|
749
|
+
return cursor
|
750
|
+
else
|
751
|
+
depth -= 1
|
752
|
+
end
|
753
|
+
else
|
754
|
+
# nop
|
755
|
+
end
|
756
|
+
}
|
757
|
+
raise "[BUG] unreachable"
|
758
|
+
end
|
759
|
+
|
760
|
+
# @rbs labels: Array[Label]
|
761
|
+
# @rbs stack: Array[wasmValue]
|
762
|
+
# @rbs level: Integer
|
763
|
+
# @rbs return: Integer
|
764
|
+
def do_branch(labels, stack, level)
|
765
|
+
idx = labels.size - 1 - level
|
766
|
+
label = labels[idx]
|
767
|
+
pc = if label.kind == :loop
|
768
|
+
# keep the top of labels for loop again...
|
769
|
+
while labels.size > idx + 1
|
770
|
+
labels.pop
|
771
|
+
end
|
772
|
+
stack_unwind(label.sp, 0)
|
773
|
+
label.start || raise(EvalError, "loop withour start")
|
774
|
+
else
|
775
|
+
while labels.size > idx
|
776
|
+
labels.pop
|
777
|
+
end
|
778
|
+
stack_unwind(label.sp, label.arity)
|
779
|
+
label.pc
|
780
|
+
end
|
781
|
+
|
782
|
+
pc
|
783
|
+
end
|
784
|
+
|
464
785
|
# @rbs ops: Array[Op]
|
465
786
|
# @rbs pc_start: Integer
|
466
787
|
# @rbs return: Integer
|
@@ -473,7 +794,7 @@ module Wardite
|
|
473
794
|
case inst&.code
|
474
795
|
when nil
|
475
796
|
raise EvalError, "end op not found"
|
476
|
-
when :
|
797
|
+
when :if, :block, :loop
|
477
798
|
depth += 1
|
478
799
|
when :end
|
479
800
|
if depth == 0
|
@@ -509,7 +830,7 @@ module Wardite
|
|
509
830
|
end
|
510
831
|
|
511
832
|
# @rbs finish: Integer
|
512
|
-
# @rbs return: Array[
|
833
|
+
# @rbs return: Array[wasmValue]
|
513
834
|
def drained_stack(finish)
|
514
835
|
drained = stack[0...finish]
|
515
836
|
if ! drained
|
@@ -537,6 +858,20 @@ module Wardite
|
|
537
858
|
end
|
538
859
|
end
|
539
860
|
|
861
|
+
class Type
|
862
|
+
attr_accessor :callsig #: Array[Symbol]
|
863
|
+
|
864
|
+
attr_accessor :retsig #: Array[Symbol]
|
865
|
+
|
866
|
+
# @rbs callsig: Array[Symbol]
|
867
|
+
# @rbs retsig: Array[Symbol]
|
868
|
+
# @rbs returb: void
|
869
|
+
def initialize(callsig, retsig)
|
870
|
+
@callsig = callsig
|
871
|
+
@retsig = retsig
|
872
|
+
end
|
873
|
+
end
|
874
|
+
|
540
875
|
class Frame
|
541
876
|
attr_accessor :pc #: Integer
|
542
877
|
attr_accessor :sp #: Integer
|
@@ -547,13 +882,13 @@ module Wardite
|
|
547
882
|
|
548
883
|
attr_accessor :labels #: Array[Label]
|
549
884
|
|
550
|
-
attr_accessor :locals #: Array[
|
885
|
+
attr_accessor :locals #: Array[wasmValue]
|
551
886
|
|
552
887
|
# @rbs pc: Integer
|
553
888
|
# @rbs sp: Integer
|
554
889
|
# @rbs body: Array[Op]
|
555
890
|
# @rbs arity: Integer
|
556
|
-
# @rbs locals: Array[
|
891
|
+
# @rbs locals: Array[wasmValue]
|
557
892
|
# @rbs returb: void
|
558
893
|
def initialize(pc, sp, body, arity, locals)
|
559
894
|
@pc = pc
|
@@ -573,16 +908,20 @@ module Wardite
|
|
573
908
|
|
574
909
|
attr_accessor :arity #: Integer
|
575
910
|
|
911
|
+
attr_accessor :start #: Integer|nil
|
912
|
+
|
576
913
|
# @rbs kind: (:if|:loop|:block)
|
577
914
|
# @rbs pc: Integer
|
578
915
|
# @rbs sp: Integer
|
579
916
|
# @rbs arity: Integer
|
580
|
-
# @rbs
|
581
|
-
|
917
|
+
# @rbs start: Integer|nil
|
918
|
+
# @rbs return: void
|
919
|
+
def initialize(kind, pc, sp, arity, start=nil)
|
582
920
|
@kind = kind
|
583
921
|
@pc = pc
|
584
922
|
@sp = sp
|
585
923
|
@arity = arity
|
924
|
+
@start = start
|
586
925
|
end
|
587
926
|
end
|
588
927
|
|
@@ -595,6 +934,10 @@ module Wardite
|
|
595
934
|
|
596
935
|
attr_accessor :globals #: Array[Global]
|
597
936
|
|
937
|
+
attr_accessor :tables #: Array[Table]
|
938
|
+
|
939
|
+
attr_accessor :elements #: Array[[Symbol, Integer, Array[Integer]]]
|
940
|
+
|
598
941
|
# @rbs inst: Instance
|
599
942
|
# @rbs return: void
|
600
943
|
def initialize(inst)
|
@@ -641,9 +984,12 @@ module Wardite
|
|
641
984
|
data_section = inst.data_section
|
642
985
|
if data_section
|
643
986
|
data_section.segments.each do |segment|
|
644
|
-
|
987
|
+
if segment.mode != :active
|
988
|
+
next
|
989
|
+
end
|
990
|
+
memory = self.memories[segment.mem_index]
|
645
991
|
if !memory
|
646
|
-
raise GenericError, "invalid memory index: #{segment.
|
992
|
+
raise GenericError, "invalid memory index: #{segment.mem_index}"
|
647
993
|
end
|
648
994
|
|
649
995
|
data_start = segment.offset
|
@@ -669,6 +1015,56 @@ module Wardite
|
|
669
1015
|
end
|
670
1016
|
end
|
671
1017
|
end
|
1018
|
+
|
1019
|
+
@tables = []
|
1020
|
+
@elements = []
|
1021
|
+
table_section = inst.table_section
|
1022
|
+
if table_section
|
1023
|
+
table_section.table_types.each_with_index do |typ, idx|
|
1024
|
+
init, max = *table_section.table_limits[idx]
|
1025
|
+
if !init
|
1026
|
+
raise LoadError, "empty limits"
|
1027
|
+
end
|
1028
|
+
table = Table.new(typ, init, max)
|
1029
|
+
@tables << table
|
1030
|
+
end
|
1031
|
+
end
|
1032
|
+
|
1033
|
+
elem_section = inst.elem_section
|
1034
|
+
if elem_section
|
1035
|
+
elem_section.table_indices.each_with_index do |tidx, idx|
|
1036
|
+
table = @tables[tidx]
|
1037
|
+
if !table
|
1038
|
+
raise LoadError, "invalid table index #{tidx}"
|
1039
|
+
end
|
1040
|
+
typ = table.type
|
1041
|
+
offset = elem_section.table_offsets[idx]
|
1042
|
+
if !offset
|
1043
|
+
raise LoadError, "invalid element index #{idx}"
|
1044
|
+
end
|
1045
|
+
indices = elem_section.element_indices[idx]
|
1046
|
+
if !indices
|
1047
|
+
raise LoadError, "invalid element index #{idx}"
|
1048
|
+
end
|
1049
|
+
elms = [typ, offset, indices] #: [Symbol, Integer, Array[Integer]]
|
1050
|
+
@elements << elms
|
1051
|
+
end
|
1052
|
+
end
|
1053
|
+
|
1054
|
+
@elements.each_with_index do |(typ, offset, indices), idx|
|
1055
|
+
table = @tables[idx]
|
1056
|
+
if !table
|
1057
|
+
raise LoadError, "invalid table index #{idx}"
|
1058
|
+
end
|
1059
|
+
indices.each_with_index do |eidx, tidx|
|
1060
|
+
case typ
|
1061
|
+
when :funcref
|
1062
|
+
table.set(offset + tidx, @funcs[eidx])
|
1063
|
+
when :externref
|
1064
|
+
raise NotImplementedError, "no support :externref"
|
1065
|
+
end
|
1066
|
+
end
|
1067
|
+
end
|
672
1068
|
end
|
673
1069
|
|
674
1070
|
# @rbs idx: Integer
|
@@ -711,6 +1107,38 @@ module Wardite
|
|
711
1107
|
end
|
712
1108
|
end
|
713
1109
|
|
1110
|
+
class Table
|
1111
|
+
attr_accessor :type #: Symbol
|
1112
|
+
|
1113
|
+
attr_accessor :current #: Integer
|
1114
|
+
|
1115
|
+
attr_accessor :max #: Integer|nil
|
1116
|
+
|
1117
|
+
attr_accessor :refs #: Array[WasmFunction|ExternalFunction|nil]
|
1118
|
+
|
1119
|
+
# @rbs type: Symbol
|
1120
|
+
# @rbs init: Integer
|
1121
|
+
# @rbs max: Integer|nil
|
1122
|
+
# @rbs return: void
|
1123
|
+
def initialize(type, init, max)
|
1124
|
+
@type = type
|
1125
|
+
@current = init
|
1126
|
+
@max = max
|
1127
|
+
|
1128
|
+
@refs = Array.new(3, nil)
|
1129
|
+
end
|
1130
|
+
|
1131
|
+
# @rbs idx: Integer
|
1132
|
+
# @rbs elem: WasmFunction|ExternalFunction|nil
|
1133
|
+
# @rbs return: void
|
1134
|
+
def set(idx, elem)
|
1135
|
+
if idx >= @current
|
1136
|
+
raise GenericError, "idx too large for table"
|
1137
|
+
end
|
1138
|
+
@refs[idx] = elem
|
1139
|
+
end
|
1140
|
+
end
|
1141
|
+
|
714
1142
|
class Global
|
715
1143
|
attr_accessor :type #: Symbol
|
716
1144
|
|
@@ -719,7 +1147,7 @@ module Wardite
|
|
719
1147
|
# TODO: unused in wasm 1.0 spec?
|
720
1148
|
attr_accessor :shared #: bool
|
721
1149
|
|
722
|
-
attr_accessor :value #:
|
1150
|
+
attr_accessor :value #: wasmValue
|
723
1151
|
|
724
1152
|
# @rbs &blk: (Global) -> void
|
725
1153
|
# @rbs return: void
|
@@ -829,25 +1257,51 @@ module Wardite
|
|
829
1257
|
# @rbs return: Array[Integer]
|
830
1258
|
def locals_count
|
831
1259
|
code_body.locals_count
|
832
|
-
end
|
1260
|
+
end
|
1261
|
+
|
1262
|
+
# @rbs override_type: Type?
|
1263
|
+
# @rbs return: WasmFunction
|
1264
|
+
def clone(override_type: nil)
|
1265
|
+
if override_type
|
1266
|
+
# code_body is assumed to be frozen, so we can copy its ref
|
1267
|
+
WasmFunction.new(override_type.callsig, override_type.retsig, code_body)
|
1268
|
+
else
|
1269
|
+
WasmFunction.new(callsig, retsig, code_body)
|
1270
|
+
end
|
1271
|
+
end
|
833
1272
|
end
|
834
1273
|
|
1274
|
+
# @rbs!
|
1275
|
+
# type wasmFuncReturn = Object|nil
|
1276
|
+
# type wasmCallable = ^(Store, Array[wasmValue]) -> wasmFuncReturn
|
1277
|
+
|
835
1278
|
class ExternalFunction
|
836
1279
|
attr_accessor :callsig #: Array[Symbol]
|
837
1280
|
|
838
1281
|
attr_accessor :retsig #: Array[Symbol]
|
839
1282
|
|
840
|
-
attr_accessor :callable #:
|
1283
|
+
attr_accessor :callable #: wasmCallable
|
841
1284
|
|
842
1285
|
# @rbs callsig: Array[Symbol]
|
843
1286
|
# @rbs retsig: Array[Symbol]
|
844
|
-
# @rbs callable:
|
1287
|
+
# @rbs callable: wasmCallable
|
845
1288
|
# @rbs return: void
|
846
1289
|
def initialize(callsig, retsig, callable)
|
847
1290
|
@callsig = callsig
|
848
1291
|
@retsig = retsig
|
849
1292
|
@callable = callable
|
850
1293
|
end
|
1294
|
+
|
1295
|
+
# @rbs override_type: Type?
|
1296
|
+
# @rbs return: ExternalFunction
|
1297
|
+
def clone(override_type: nil)
|
1298
|
+
if override_type
|
1299
|
+
# callable is assumed to be frozen, so we can copy its ref
|
1300
|
+
ExternalFunction.new(override_type.callsig, override_type.retsig, callable)
|
1301
|
+
else
|
1302
|
+
ExternalFunction.new(callsig, retsig, callable)
|
1303
|
+
end
|
1304
|
+
end
|
851
1305
|
end
|
852
1306
|
|
853
1307
|
class GenericError < StandardError; end
|