wardite 0.2.2 → 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.
data/lib/wardite/wasi.rb CHANGED
@@ -14,7 +14,7 @@ module Wardite
14
14
  end
15
15
 
16
16
  # @rbs store: Store
17
- # @rbs args: Array[I32|I64|F32|F64]
17
+ # @rbs args: Array[wasmValue]
18
18
  # @rbs return: Object
19
19
  def fd_write(store, args)
20
20
  iargs = args.map do |elm|
@@ -45,7 +45,7 @@ module Wardite
45
45
  0
46
46
  end
47
47
 
48
- # @rbs return: Hash[Symbol, Proc]
48
+ # @rbs return: Hash[Symbol, wasmCallable]
49
49
  def to_module
50
50
  {
51
51
  fd_write: lambda{|store, args| self.fd_write(store, args) },
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, Proc]]
40
+ attr_reader :import_object #: Hash[Symbol, Hash[Symbol, wasmCallable]]
39
41
 
40
- # @rbs import_object: Hash[Symbol, Hash[Symbol, Proc]]
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,15 @@ 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
49
60
  end
50
61
 
51
62
  # @rbs return: ImportSection
@@ -82,6 +93,18 @@ module Wardite
82
93
  sec
83
94
  end
84
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
+
85
108
  # @rbs return: GlobalSection|nil
86
109
  def global_section
87
110
  sec = @sections.find{|s| s.code == Const::SectionGlobal }
@@ -118,6 +141,30 @@ module Wardite
118
141
  sec
119
142
  end
120
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
+
121
168
  # @rbs return: CodeSection|nil
122
169
  def code_section
123
170
  sec = @sections.find{|s| s.code == Const::SectionCode }
@@ -147,7 +194,7 @@ module Wardite
147
194
  include ValueHelper
148
195
 
149
196
  # TODO: add types of class that the stack accomodates
150
- attr_accessor :stack #: Array[I32|I64|F32|F64]
197
+ attr_accessor :stack #: Array[wasmValue]
151
198
 
152
199
  attr_accessor :call_stack #: Array[Frame]
153
200
 
@@ -158,8 +205,18 @@ module Wardite
158
205
  @stack = []
159
206
  @call_stack = []
160
207
  @instance = inst
208
+
209
+ invoke_start_section
161
210
  end
162
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
+
163
220
  # @rbs name: String|Symbol
164
221
  # @rbs return: bool
165
222
  def callable?(name)
@@ -200,6 +257,21 @@ module Wardite
200
257
  end
201
258
  end
202
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
+
203
275
  # @rbs wasm_function: WasmFunction
204
276
  # @rbs return: void
205
277
  def push_frame(wasm_function)
@@ -249,7 +321,7 @@ module Wardite
249
321
  end
250
322
 
251
323
  # @rbs external_function: ExternalFunction
252
- # @rbs return: I32|I64|F32|F64|nil
324
+ # @rbs return: wasmValue|nil
253
325
  def invoke_external(external_function)
254
326
  local_start = stack.size - external_function.callsig.size
255
327
  args = stack[local_start..]
@@ -326,19 +398,80 @@ module Wardite
326
398
  when :nop
327
399
  return
328
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
+
329
448
  when :if
330
449
  block = insn.operand[0]
331
450
  raise EvalError, "if op without block" if !block.is_a?(Block)
332
451
  cond = stack.pop
333
452
  raise EvalError, "cond not found" if !cond.is_a?(I32)
334
453
  next_pc = fetch_ops_while_end(frame.body, frame.pc)
454
+
335
455
  if cond.value.zero?
336
- frame.pc = next_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
337
462
  end
338
463
 
339
464
  label = Label.new(:if, next_pc, stack.size, block.result_size)
340
465
  frame.labels.push(label)
341
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
+
342
475
  when :call
343
476
  idx = insn.operand[0]
344
477
  raise EvalError, "[BUG] local operand not found" if !idx.is_a?(Integer)
@@ -353,6 +486,45 @@ module Wardite
353
486
  raise GenericError, "got a non-function pointer"
354
487
  end
355
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
+
356
528
  when :return
357
529
  old_frame = call_stack.pop
358
530
  if !old_frame
@@ -408,6 +580,18 @@ module Wardite
408
580
  end
409
581
  frame.locals[idx] = value
410
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
+
411
595
  when :global_get
412
596
  idx = insn.operand[0]
413
597
  if !idx.is_a?(Integer)
@@ -456,11 +640,69 @@ module Wardite
456
640
 
457
641
  rescue => e
458
642
  require "pp"
643
+ $stderr.puts "instance:::\n#{self.instance.pretty_inspect}"
459
644
  $stderr.puts "frame:::\n#{frame.pretty_inspect}"
460
645
  $stderr.puts "stack:::\n#{stack.pretty_inspect}"
461
646
  raise e
462
647
  end
463
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
+
464
706
  # @rbs ops: Array[Op]
465
707
  # @rbs pc_start: Integer
466
708
  # @rbs return: Integer
@@ -473,7 +715,7 @@ module Wardite
473
715
  case inst&.code
474
716
  when nil
475
717
  raise EvalError, "end op not found"
476
- when :i
718
+ when :if, :block, :loop
477
719
  depth += 1
478
720
  when :end
479
721
  if depth == 0
@@ -509,7 +751,7 @@ module Wardite
509
751
  end
510
752
 
511
753
  # @rbs finish: Integer
512
- # @rbs return: Array[I32|I64|F32|F64]
754
+ # @rbs return: Array[wasmValue]
513
755
  def drained_stack(finish)
514
756
  drained = stack[0...finish]
515
757
  if ! drained
@@ -537,6 +779,20 @@ module Wardite
537
779
  end
538
780
  end
539
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
+
540
796
  class Frame
541
797
  attr_accessor :pc #: Integer
542
798
  attr_accessor :sp #: Integer
@@ -547,13 +803,13 @@ module Wardite
547
803
 
548
804
  attr_accessor :labels #: Array[Label]
549
805
 
550
- attr_accessor :locals #: Array[I32|I64|F32|F64]
806
+ attr_accessor :locals #: Array[wasmValue]
551
807
 
552
808
  # @rbs pc: Integer
553
809
  # @rbs sp: Integer
554
810
  # @rbs body: Array[Op]
555
811
  # @rbs arity: Integer
556
- # @rbs locals: Array[Object]
812
+ # @rbs locals: Array[wasmValue]
557
813
  # @rbs returb: void
558
814
  def initialize(pc, sp, body, arity, locals)
559
815
  @pc = pc
@@ -573,16 +829,20 @@ module Wardite
573
829
 
574
830
  attr_accessor :arity #: Integer
575
831
 
832
+ attr_accessor :start #: Integer|nil
833
+
576
834
  # @rbs kind: (:if|:loop|:block)
577
835
  # @rbs pc: Integer
578
836
  # @rbs sp: Integer
579
837
  # @rbs arity: Integer
580
- # @rbs returb: void
581
- def initialize(kind, pc, sp, arity)
838
+ # @rbs start: Integer|nil
839
+ # @rbs return: void
840
+ def initialize(kind, pc, sp, arity, start=nil)
582
841
  @kind = kind
583
842
  @pc = pc
584
843
  @sp = sp
585
844
  @arity = arity
845
+ @start = start
586
846
  end
587
847
  end
588
848
 
@@ -595,6 +855,10 @@ module Wardite
595
855
 
596
856
  attr_accessor :globals #: Array[Global]
597
857
 
858
+ attr_accessor :tables #: Array[Table]
859
+
860
+ attr_accessor :elements #: Array[[Symbol, Integer, Array[Integer]]]
861
+
598
862
  # @rbs inst: Instance
599
863
  # @rbs return: void
600
864
  def initialize(inst)
@@ -669,6 +933,56 @@ module Wardite
669
933
  end
670
934
  end
671
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
672
986
  end
673
987
 
674
988
  # @rbs idx: Integer
@@ -711,6 +1025,38 @@ module Wardite
711
1025
  end
712
1026
  end
713
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
+
714
1060
  class Global
715
1061
  attr_accessor :type #: Symbol
716
1062
 
@@ -719,7 +1065,7 @@ module Wardite
719
1065
  # TODO: unused in wasm 1.0 spec?
720
1066
  attr_accessor :shared #: bool
721
1067
 
722
- attr_accessor :value #: I32|I64|F32|F64
1068
+ attr_accessor :value #: wasmValue
723
1069
 
724
1070
  # @rbs &blk: (Global) -> void
725
1071
  # @rbs return: void
@@ -829,25 +1175,51 @@ module Wardite
829
1175
  # @rbs return: Array[Integer]
830
1176
  def locals_count
831
1177
  code_body.locals_count
832
- 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
833
1190
  end
834
1191
 
1192
+ # @rbs!
1193
+ # type wasmFuncReturn = Object|nil
1194
+ # type wasmCallable = ^(Store, Array[wasmValue]) -> wasmFuncReturn
1195
+
835
1196
  class ExternalFunction
836
1197
  attr_accessor :callsig #: Array[Symbol]
837
1198
 
838
1199
  attr_accessor :retsig #: Array[Symbol]
839
1200
 
840
- attr_accessor :callable #: Proc
1201
+ attr_accessor :callable #: wasmCallable
841
1202
 
842
1203
  # @rbs callsig: Array[Symbol]
843
1204
  # @rbs retsig: Array[Symbol]
844
- # @rbs callable: Proc
1205
+ # @rbs callable: wasmCallable
845
1206
  # @rbs return: void
846
1207
  def initialize(callsig, retsig, callable)
847
1208
  @callsig = callsig
848
1209
  @retsig = retsig
849
1210
  @callable = callable
850
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
851
1223
  end
852
1224
 
853
1225
  class GenericError < StandardError; end
@@ -1,6 +1,8 @@
1
1
  # Generated from lib/wardite/instruction.rb with RBS::Inline
2
2
 
3
3
  module Wardite
4
+ type operandItem = Integer | Array[Integer] | Float | Block
5
+
4
6
  class Op
5
7
  # @see https://pengowray.github.io/wasm-ops/
6
8
  SYMS: Array[Symbol]
@@ -13,12 +15,12 @@ module Wardite
13
15
  attr_accessor code: Symbol
14
16
 
15
17
  # TODO: add types of potential operands
16
- attr_accessor operand: Array[Integer | Float | Block]
18
+ attr_accessor operand: Array[operandItem]
17
19
 
18
20
  # @rbs namespace: Symbol
19
21
  # @rbs code: Symbol
20
- # @rbs operand: Array[Integer|Float|Block]
21
- def initialize: (Symbol namespace, Symbol code, Array[Integer | Float | Block] operand) -> untyped
22
+ # @rbs operand: Array[operandItem]
23
+ def initialize: (Symbol namespace, Symbol code, Array[operandItem] operand) -> untyped
22
24
 
23
25
  # @rbs chr: String
24
26
  # @rbs return: [Symbol, Symbol]
@@ -29,6 +31,7 @@ module Wardite
29
31
  def self.operand_of: (Symbol code) -> Array[Symbol]
30
32
 
31
33
  # @see https://www.w3.org/TR/wasm-core-1/#value-types%E2%91%A2
34
+ # We use this for reftype conversion. https://webassembly.github.io/spec/core/binary/types.html#binary-reftype
32
35
  # @rbs code: Integer
33
36
  # @rbs return: Symbol
34
37
  def self.i2type: (Integer code) -> Symbol