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