wardite 0.1.2 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d27a05a105bd446883460d42c05cbec8502360dc686098368d59b1ae5e6e3e91
4
- data.tar.gz: d17f48eade8ac57845bf250583db7eb33dd9a418c315ba1083a7e0f598505298
3
+ metadata.gz: 8e33fd39e5cc58e9ec6071c4a74d5cbe872d68355657dd1adfdf375d74cf03b9
4
+ data.tar.gz: cee2e80f2dda3a2366450cf9b2d6656b172faa41b69eba39c03610b8a3c8d38b
5
5
  SHA512:
6
- metadata.gz: 21de2c67fd7aaaf04d55f028d304588a4f5c7f92b21ab4b7cb40dd7882103067db85401f41efc53b491996a82f109a9b11c05b0efa62e9622ad3971f6e254342
7
- data.tar.gz: 90542ce81cf6bf537eac6ddab087abab10842bfb24f153ba88865a7d2b5a0417c3e3fbab116e5ad2bedabc3d665810f34c0c8568a2baa2adbbdda89c681df076
6
+ metadata.gz: bfabd5ef113b7ebdc5e7aa5059eed7984e5f38a8490e120b4ab4230972f503e62aff24d0bfa5cdcef49bc8dcd082c69ade651f95e5cd0101780acdd389378fda
7
+ data.tar.gz: eac7e0374494969be1ea08e8fb7344e163a2c122ff3d6b958d47851bc3815104329216c9107612930209ecf0551ff677a5d9f3744792d82746b410b32fe329d4
data/Rakefile CHANGED
@@ -15,5 +15,20 @@ task :check do
15
15
  sh "bundle exec steep check"
16
16
  end
17
17
 
18
+ desc "Generate codes"
19
+ task :generate do
20
+ require_relative "scripts/gen_alu"
21
+ libdir = File.expand_path("../lib", __FILE__)
22
+
23
+ GenAlu.execute(libdir + "/wardite/alu_i32.generated.rb", prefix: "i32", defined_ops: [
24
+ :lts,
25
+ :leu,
26
+ :add,
27
+ :sub,
28
+ :const,
29
+ :store,
30
+ ])
31
+ end
32
+
18
33
  task default: %i[test check]
19
34
 
@@ -0,0 +1,77 @@
1
+ # rbs_inline: enabled
2
+ require_relative "value"
3
+
4
+ module Wardite
5
+ module Evaluator
6
+ # @rbs runtime: Runtime
7
+ # @rbs frame: Frame
8
+ # @rbs insn: Op
9
+ # @rbs return: void
10
+ def self.i32_eval_insn(runtime, frame, insn)
11
+ case insn.code
12
+
13
+ when :i32_lts
14
+ right, left = runtime.stack.pop, runtime.stack.pop
15
+ if !right.is_a?(I32) || !left.is_a?(I32)
16
+ raise EvalError, "maybe empty or invalid stack"
17
+ end
18
+ value = (left.value < right.value) ? 1 : 0
19
+ runtime.stack.push(I32(value))
20
+
21
+
22
+ when :i32_leu
23
+ right, left = runtime.stack.pop, runtime.stack.pop
24
+ if !right.is_a?(I32) || !left.is_a?(I32)
25
+ raise EvalError, "maybe empty or invalid stack"
26
+ end
27
+ value = (left.value >= right.value) ? 1 : 0
28
+ runtime.stack.push(I32(value))
29
+
30
+
31
+ when :i32_add
32
+ right, left = runtime.stack.pop, runtime.stack.pop
33
+ if !right.is_a?(I32) || !left.is_a?(I32)
34
+ raise EvalError, "maybe empty or invalid stack"
35
+ end
36
+ runtime.stack.push(I32(left.value + right.value))
37
+
38
+
39
+ when :i32_sub
40
+ right, left = runtime.stack.pop, runtime.stack.pop
41
+ if !right.is_a?(I32) || !left.is_a?(I32)
42
+ raise EvalError, "maybe empty or invalid stack"
43
+ end
44
+ runtime.stack.push(I32(left.value - right.value))
45
+
46
+
47
+ when :i32_const
48
+ const = insn.operand[0]
49
+ if !const.is_a?(Integer)
50
+ raise EvalError, "invalid type of operand"
51
+ end
52
+ runtime.stack.push(I32(const))
53
+
54
+
55
+ when :i32_store
56
+ _align = insn.operand[0] # TODO: alignment support?
57
+ offset = insn.operand[1]
58
+ raise EvalError, "[BUG] invalid type of operand" if !offset.is_a?(Integer)
59
+
60
+ value = runtime.stack.pop
61
+ addr = runtime.stack.pop
62
+ if !value.is_a?(I32) || !addr.is_a?(I32)
63
+ raise EvalError, "maybe stack too short"
64
+ end
65
+
66
+ at = addr.value + offset
67
+ data_end = at + value.packed.size
68
+ memory = runtime.instance.store.memories[0] || raise("[BUG] no memory")
69
+ memory.data[at...data_end] = value.packed
70
+
71
+
72
+ else
73
+ raise "Unknown opcode for namespace #{insn.namespace}: #{insn.code}"
74
+ end
75
+ end
76
+ end
77
+ end
@@ -1,47 +1,65 @@
1
1
  # rbs_inline: enabled
2
+
2
3
  module Wardite
3
4
  class Op
5
+ attr_accessor :namespace #: Symbol
6
+
4
7
  attr_accessor :code #: Symbol
5
8
 
6
- attr_accessor :operand #: Array[Object]
9
+ # TODO: add types of potential operands
10
+ attr_accessor :operand #: Array[Integer|Float|Block]
7
11
 
12
+ # @rbs namespace: Symbol
8
13
  # @rbs code: Symbol
9
- # @rbs operand: Array[Object]
10
- def initialize(code, operand)
14
+ # @rbs operand: Array[Integer|Float|Block]
15
+ def initialize(namespace, code, operand)
16
+ @namespace = namespace
11
17
  @code = code
12
18
  @operand = operand
13
19
  end
14
20
 
15
21
  # @rbs chr: String
16
- # @rbs return: Symbol
22
+ # @rbs return: [Symbol, Symbol]
17
23
  def self.to_sym(chr)
18
- case chr
19
- when "\u0004"
20
- :if
21
- when "\u000b"
22
- :end
23
- when "\u000f"
24
- :return
25
- when "\u0010"
26
- :call
27
- when "\u0020"
28
- :local_get
29
- when "\u0021"
30
- :local_set
31
- when "\u0036"
32
- :i32_store
33
- when "\u0041"
34
- :i32_const
35
- when "\u0048"
36
- :i32_lts
37
- when "\u004d"
38
- :i32_leu
39
- when "\u006a"
40
- :i32_add
41
- when "\u006b"
42
- :i32_sub
24
+ code = case chr
25
+ when "\u0004"
26
+ :if
27
+ when "\u000b"
28
+ :end
29
+ when "\u000f"
30
+ :return
31
+ when "\u0010"
32
+ :call
33
+ when "\u0020"
34
+ :local_get
35
+ when "\u0021"
36
+ :local_set
37
+ when "\u0036"
38
+ :i32_store
39
+ when "\u0041"
40
+ :i32_const
41
+ when "\u0048"
42
+ :i32_lts
43
+ when "\u004d"
44
+ :i32_leu
45
+ when "\u006a"
46
+ :i32_add
47
+ when "\u006b"
48
+ :i32_sub
49
+ else
50
+ raise NotImplementedError, "unimplemented: #{"%04x" % chr.ord}"
51
+ end
52
+ # opcodes equal to or larger than are "convert" ops
53
+ if chr.ord >= 0xa7
54
+ return [:convert, code]
55
+ end
56
+
57
+ prefix = code.to_s.split("_")[0]
58
+ case prefix
59
+ when "i32", "i64", "f32", "f64"
60
+ [prefix.to_sym, code]
43
61
  else
44
- raise NotImplementedError, "unimplemented: #{"%04x" % chr.ord}"
62
+ [:default, code]
45
63
  end
46
64
  end
47
65
 
@@ -1,6 +1,6 @@
1
1
  # rbs_inline: enabled
2
2
  module Wardite
3
- module Leb128Helpers
3
+ module Leb128Helper
4
4
  # @rbs buf: File|StringIO
5
5
  # @rbs return: Integer
6
6
  def fetch_uleb128(buf)
@@ -0,0 +1,82 @@
1
+ # rbs_inline: enabled
2
+
3
+ module Wardite
4
+ class I32
5
+ attr_accessor :value #: Integer
6
+
7
+ # TODO: eliminate use of pack, to support mruby - in this file!
8
+ # @rbs return: String
9
+ def packed
10
+ [self.value].pack("I")
11
+ end
12
+
13
+ def inspect
14
+ "I32(#{@value})"
15
+ end
16
+ end
17
+
18
+ class I64
19
+ attr_accessor :value #: Integer
20
+
21
+ # @rbs return: String
22
+ def packed
23
+ [self.value].pack("L")
24
+ end
25
+
26
+ def inspect
27
+ "I64(#{@value})"
28
+ end
29
+ end
30
+
31
+ class F32
32
+ attr_accessor :value #: Float
33
+
34
+ # @rbs return: String
35
+ def packed
36
+ [self.value].pack("f")
37
+ end
38
+
39
+ def inspect
40
+ "F32(#{@value})"
41
+ end
42
+ end
43
+
44
+ class F64
45
+ attr_accessor :value #: Float
46
+
47
+ # @rbs return: String
48
+ def packed
49
+ [self.value].pack("d")
50
+ end
51
+
52
+ def inspect
53
+ "F64(#{@value})"
54
+ end
55
+ end
56
+
57
+ module ValueHelper
58
+ # @rbs value: Integer
59
+ # @rbs return: I32
60
+ def I32(value)
61
+ I32.new.tap{|i| i.value = value }
62
+ end
63
+
64
+ # @rbs value: Integer
65
+ # @rbs return: I64
66
+ def I64(value)
67
+ I64.new.tap{|i| i.value = value }
68
+ end
69
+
70
+ # @rbs value: Float
71
+ # @rbs return: F32
72
+ def F32(value)
73
+ F32.new.tap{|i| i.value = value }
74
+ end
75
+
76
+ # @rbs value: Float
77
+ # @rbs return: F64
78
+ def F64(value)
79
+ F64.new.tap{|i| i.value = value }
80
+ end
81
+ end
82
+ end
@@ -2,5 +2,5 @@
2
2
  # rbs_inline: enabled
3
3
 
4
4
  module Wardite
5
- VERSION = "0.1.2" #: String
5
+ VERSION = "0.2.0" #: String
6
6
  end
data/lib/wardite/wasi.rb CHANGED
@@ -1,6 +1,8 @@
1
1
  # rbs_inline: enabled
2
2
  module Wardite
3
3
  class WasiSnapshotPreview1
4
+ include ValueHelper
5
+
4
6
  attr_accessor :fd_table #: Array[IO]
5
7
 
6
8
  def initialize
@@ -12,12 +14,12 @@ module Wardite
12
14
  end
13
15
 
14
16
  # @rbs store: Store
15
- # @rbs args: Array[Object]
17
+ # @rbs args: Array[I32|I64|F32|F64]
16
18
  # @rbs return: Object
17
19
  def fd_write(store, args)
18
20
  iargs = args.map do |elm|
19
- if elm.is_a?(Integer)
20
- elm
21
+ if elm.is_a?(I32)
22
+ elm.value
21
23
  else
22
24
  raise Wardite::ArgumentError, "invalid type of args: #{args.inspect}"
23
25
  end
data/lib/wardite.rb CHANGED
@@ -5,6 +5,15 @@ require_relative "wardite/version"
5
5
  require_relative "wardite/leb128"
6
6
  require_relative "wardite/const"
7
7
  require_relative "wardite/instruction"
8
+ require_relative "wardite/value"
9
+
10
+ module Wardite
11
+ module Evaluator
12
+ extend Wardite::ValueHelper
13
+ end
14
+ end
15
+ require_relative "wardite/alu_i32.generated"
16
+
8
17
  require_relative "wardite/wasi"
9
18
 
10
19
  require "stringio"
@@ -164,7 +173,8 @@ module Wardite
164
173
  end
165
174
 
166
175
  module BinaryLoader
167
- extend Wardite::Leb128Helpers
176
+ extend Wardite::Leb128Helper
177
+ extend Wardite::ValueHelper
168
178
 
169
179
  # @rbs buf: File|StringIO
170
180
  # @rbs import_object: Hash[Symbol, Hash[Symbol, Proc]]
@@ -417,9 +427,9 @@ module Wardite
417
427
  def self.code_body(buf)
418
428
  dest = []
419
429
  while c = buf.read(1)
420
- code = Op.to_sym(c)
430
+ namespace, code = Op.to_sym(c)
421
431
  operand_types = Op.operand_of(code)
422
- operand = [] #: Array[Object]
432
+ operand = [] #: Array[Integer|Float|Block]
423
433
  operand_types.each do |typ|
424
434
  case typ
425
435
  when :u32
@@ -442,7 +452,7 @@ module Wardite
442
452
  end
443
453
  end
444
454
 
445
- dest << Op.new(code, operand)
455
+ dest << Op.new(namespace, code, operand)
446
456
  end
447
457
 
448
458
  dest
@@ -675,7 +685,10 @@ module Wardite
675
685
  end
676
686
 
677
687
  class Runtime
678
- attr_accessor :stack #: Array[Object]
688
+ include ValueHelper
689
+
690
+ # TODO: add types of class that the stack accomodates
691
+ attr_accessor :stack #: Array[I32|I64|F32|F64|Block]
679
692
 
680
693
  attr_accessor :call_stack #: Array[Frame]
681
694
 
@@ -708,34 +721,14 @@ module Wardite
708
721
  if fn.callsig.size != args.size
709
722
  raise ArgumentError, "unmatch arg size"
710
723
  end
711
- args.each do |arg|
712
- stack.push arg
713
- end
714
-
715
- case fn
716
- when WasmFunction
717
- invoke_internal(fn)
718
- when ExternalFunction
719
- invoke_external(fn)
720
- else
721
- raise GenericError, "registered pointer is not to a function"
722
- end
723
- end
724
-
725
- # @rbs idx: Integer
726
- # @rbs args: Array[Object]
727
- # @rbs return: Object|nil
728
- def call_index(idx, args)
729
- fn = self.instance.store[idx]
730
- if !fn
731
- # TODO: own error NoFunctionError
732
- raise ::NoMethodError, "func #{idx} not found"
733
- end
734
- if fn.callsig.size != args.size
735
- raise ArgumentError, "unmatch arg size"
736
- end
737
- args.each do |arg|
738
- stack.push arg
724
+ args.each_with_index do |arg, idx|
725
+ case fn.callsig[idx]
726
+ when :i32
727
+ raise "type mismatch: i32(#{arg})" unless arg.is_a?(Integer)
728
+ stack.push I32(arg)
729
+ else
730
+ raise "TODO: add me"
731
+ end
739
732
  end
740
733
 
741
734
  case fn
@@ -761,11 +754,12 @@ module Wardite
761
754
  wasm_function.locals_type.each_with_index do |typ, i|
762
755
  case typ
763
756
  when :i32, :u32
764
- # locals.push Local::I32(typ, 0)...
765
- locals.push 0
757
+ locals.push I32(0)
758
+ when :i64, :u64
759
+ locals.push I64(0)
766
760
  else
767
- $stderr.puts "warning: unknown type #{typ.inspect}. default to Object"
768
- locals.push Object.new
761
+ $stderr.puts "warning: unknown type #{typ.inspect}. default to I32"
762
+ locals.push I32(0)
769
763
  end
770
764
  end
771
765
 
@@ -796,7 +790,7 @@ module Wardite
796
790
  end
797
791
 
798
792
  # @rbs external_function: ExternalFunction
799
- # @rbs return: Object|nil
793
+ # @rbs return: I32|I64|F32|F64|nil
800
794
  def invoke_external(external_function)
801
795
  local_start = stack.size - external_function.callsig.size
802
796
  args = stack[local_start..]
@@ -806,7 +800,31 @@ module Wardite
806
800
  self.stack = drained_stack(local_start)
807
801
 
808
802
  proc = external_function.callable
809
- proc[self.instance.store, args]
803
+ val = proc[self.instance.store, args]
804
+ if !val
805
+ return
806
+ end
807
+
808
+ case val
809
+ when I32, I64, F32, F64
810
+ return val
811
+ when Integer
812
+ case external_function.retsig[0]
813
+ when :i32
814
+ return I32(val)
815
+ when :i64
816
+ return I64(val)
817
+ end
818
+ when Float
819
+ case external_function.retsig[0]
820
+ when :f32
821
+ return F32(val)
822
+ when :f64
823
+ return F64(val)
824
+ end
825
+ end
826
+
827
+ raise "invalid type of value returned in proc. val: #{val.inspect}"
810
828
  end
811
829
 
812
830
  # @rbs return: void
@@ -829,14 +847,20 @@ module Wardite
829
847
  # @rbs insn: Op
830
848
  # @rbs return: void
831
849
  def eval_insn(frame, insn)
850
+ case insn.namespace
851
+ when :i32
852
+ return Evaluator.i32_eval_insn(self, frame, insn)
853
+ end
854
+
855
+ # unmached namespace...
832
856
  case insn.code
833
857
  when :if
834
858
  block = insn.operand[0]
835
859
  raise EvalError, "if op without block" if !block.is_a?(Block)
836
860
  cond = stack.pop
837
- raise EvalError, "cond not found" if !cond.is_a?(Integer)
861
+ raise EvalError, "cond not found" if !cond.is_a?(I32)
838
862
  next_pc = fetch_ops_while_end(frame.body, frame.pc)
839
- if cond.zero?
863
+ if cond.value.zero?
840
864
  frame.pc = next_pc
841
865
  end
842
866
 
@@ -862,55 +886,58 @@ module Wardite
862
886
  if !value
863
887
  raise EvalError, "value should be pushed"
864
888
  end
865
- frame.locals[idx] = value
866
-
867
- when :i32_lts
868
- right, left = stack.pop, stack.pop
869
- if !right.is_a?(Integer) || !left.is_a?(Integer)
870
- raise EvalError, "maybe empty stack"
871
- end
872
- value = (left < right) ? 1 : 0
873
- stack.push(value)
874
- when :i32_leu
875
- right, left = stack.pop, stack.pop
876
- if !right.is_a?(Integer) || !left.is_a?(Integer)
877
- raise EvalError, "maybe empty stack"
878
- end
879
- value = (left >= right) ? 1 : 0
880
- stack.push(value)
881
- when :i32_add
882
- right, left = stack.pop, stack.pop
883
- if !right.is_a?(Integer) || !left.is_a?(Integer)
884
- raise EvalError, "maybe empty stack"
885
- end
886
- stack.push(left + right)
887
- when :i32_sub
888
- right, left = stack.pop, stack.pop
889
- if !right.is_a?(Integer) || !left.is_a?(Integer)
890
- raise EvalError, "maybe empty stack"
891
- end
892
- stack.push(left - right)
893
- when :i32_const
894
- const = insn.operand[0]
895
- if !const.is_a?(Integer)
896
- raise EvalError, "[BUG] invalid type of operand"
897
- end
898
- stack.push(const)
899
- when :i32_store
900
- _align = insn.operand[0] # TODO: alignment support?
901
- offset = insn.operand[1]
902
- raise EvalError, "[BUG] invalid type of operand" if !offset.is_a?(Integer)
903
-
904
- value = stack.pop
905
- addr = stack.pop
906
- if !value.is_a?(Integer) || !addr.is_a?(Integer)
907
- raise EvalError, "maybe stack too short"
889
+ if value.is_a?(Block)
890
+ raise EvalError, "block value detected"
908
891
  end
892
+ frame.locals[idx] = value
909
893
 
910
- at = addr + offset
911
- data_end = at + 4 # sizeof(i32)
912
- memory = self.instance.store.memories[0] || raise("[BUG] no memory")
913
- memory.data[at...data_end] = [value].pack("I")
894
+ # when :i32_lts
895
+ # right, left = stack.pop, stack.pop
896
+ # if !right.is_a?(Integer) || !left.is_a?(Integer)
897
+ # raise EvalError, "maybe empty stack"
898
+ # end
899
+ # value = (left < right) ? 1 : 0
900
+ # stack.push(value)
901
+ # when :i32_leu
902
+ # right, left = stack.pop, stack.pop
903
+ # if !right.is_a?(Integer) || !left.is_a?(Integer)
904
+ # raise EvalError, "maybe empty stack"
905
+ # end
906
+ # value = (left >= right) ? 1 : 0
907
+ # stack.push(value)
908
+ # when :i32_add
909
+ # right, left = stack.pop, stack.pop
910
+ # if !right.is_a?(Integer) || !left.is_a?(Integer)
911
+ # raise EvalError, "maybe empty stack"
912
+ # end
913
+ # stack.push(left + right)
914
+ # when :i32_sub
915
+ # right, left = stack.pop, stack.pop
916
+ # if !right.is_a?(Integer) || !left.is_a?(Integer)
917
+ # raise EvalError, "maybe empty stack"
918
+ # end
919
+ # stack.push(left - right)
920
+ # when :i32_const
921
+ # const = insn.operand[0]
922
+ # if !const.is_a?(Integer)
923
+ # raise EvalError, "[BUG] invalid type of operand"
924
+ # end
925
+ # stack.push(const)
926
+ # when :i32_store
927
+ # _align = insn.operand[0] # TODO: alignment support?
928
+ # offset = insn.operand[1]
929
+ # raise EvalError, "[BUG] invalid type of operand" if !offset.is_a?(Integer)
930
+
931
+ # value = stack.pop
932
+ # addr = stack.pop
933
+ # if !value.is_a?(Integer) || !addr.is_a?(Integer)
934
+ # raise EvalError, "maybe stack too short"
935
+ # end
936
+
937
+ # at = addr + offset
938
+ # data_end = at + 4 # sizeof(i32)
939
+ # memory = self.instance.store.memories[0] || raise("[BUG] no memory")
940
+ # memory.data[at...data_end] = [value].pack("I")
914
941
 
915
942
  when :call
916
943
  idx = insn.operand[0]
@@ -996,7 +1023,7 @@ module Wardite
996
1023
  end
997
1024
 
998
1025
  # @rbs finish: Integer
999
- # @rbs return: Array[Object]
1026
+ # @rbs return: Array[I32|I64|F32|F64|Block]
1000
1027
  def drained_stack(finish)
1001
1028
  drained = stack[0...finish]
1002
1029
  if ! drained
@@ -1034,7 +1061,7 @@ module Wardite
1034
1061
 
1035
1062
  attr_accessor :labels #: Array[Label]
1036
1063
 
1037
- attr_accessor :locals #: Array[Object]
1064
+ attr_accessor :locals #: Array[I32|I64|F32|F64]
1038
1065
 
1039
1066
  # @rbs pc: Integer
1040
1067
  # @rbs sp: Integer
@@ -0,0 +1,124 @@
1
+ require "stringio"
2
+
3
+ module GenAlu
4
+ def self.execute(path, prefix: "i32", defined_ops: [])
5
+ parent_dir = File.dirname(path)
6
+ system "mkdir -p #{parent_dir}"
7
+
8
+ basic_module = File.read(
9
+ File.expand_path("../templates/alu_module.rb.tmpl", __FILE__)
10
+ )
11
+ basic_module.gsub!(/\$\{PREFIX\}/, prefix)
12
+ ope_defs = generate_ops(prefix: prefix, defined_ops: defined_ops)
13
+ basic_module.gsub!(/\$\{DEFS\}/, ope_defs)
14
+
15
+ dest = File.open(path, "w")
16
+ dest.puts basic_module
17
+
18
+ $stderr.puts "generated: #{path}"
19
+ end
20
+
21
+ def self.generate_ops(prefix:, defined_ops:)
22
+ result = StringIO.new("")
23
+ defined_ops.each do |op|
24
+ code = DEFS[op.to_sym]
25
+ if ! code
26
+ raise "unsupported code specified!"
27
+ end
28
+ code.gsub!(/\$\{PREFIX\}/, prefix)
29
+ code.gsub!(/\$\{CLASS\}/, to_class(prefix.to_sym))
30
+ result << "\n"
31
+ code.each_line do |ln|
32
+ result << " " * 6 << ln
33
+ end
34
+ result << "\n"
35
+ end
36
+ result.string
37
+ end
38
+
39
+ def self.to_class(prefix)
40
+ {
41
+ i32: "I32",
42
+ i64: "I64",
43
+ f32: "F32",
44
+ f64: "F64",
45
+ }[prefix]
46
+ end
47
+
48
+ # ope_templates
49
+ DEFS = { #: Hash[Symbol, String]
50
+ lts: <<~RUBY,
51
+ when :${PREFIX}_lts
52
+ right, left = runtime.stack.pop, runtime.stack.pop
53
+ if !right.is_a?(${CLASS}) || !left.is_a?(${CLASS})
54
+ raise EvalError, "maybe empty or invalid stack"
55
+ end
56
+ value = (left.value < right.value) ? 1 : 0
57
+ runtime.stack.push(I32(value))
58
+ RUBY
59
+
60
+ leu: <<~RUBY,
61
+ when :${PREFIX}_leu
62
+ right, left = runtime.stack.pop, runtime.stack.pop
63
+ if !right.is_a?(${CLASS}) || !left.is_a?(${CLASS})
64
+ raise EvalError, "maybe empty or invalid stack"
65
+ end
66
+ value = (left.value >= right.value) ? 1 : 0
67
+ runtime.stack.push(I32(value))
68
+ RUBY
69
+
70
+ add: <<~RUBY,
71
+ when :${PREFIX}_add
72
+ right, left = runtime.stack.pop, runtime.stack.pop
73
+ if !right.is_a?(${CLASS}) || !left.is_a?(${CLASS})
74
+ raise EvalError, "maybe empty or invalid stack"
75
+ end
76
+ runtime.stack.push(${CLASS}(left.value + right.value))
77
+ RUBY
78
+
79
+ sub: <<~RUBY,
80
+ when :${PREFIX}_sub
81
+ right, left = runtime.stack.pop, runtime.stack.pop
82
+ if !right.is_a?(${CLASS}) || !left.is_a?(${CLASS})
83
+ raise EvalError, "maybe empty or invalid stack"
84
+ end
85
+ runtime.stack.push(${CLASS}(left.value - right.value))
86
+ RUBY
87
+
88
+ const: <<~RUBY,
89
+ when :${PREFIX}_const
90
+ const = insn.operand[0]
91
+ if !const.is_a?(Integer)
92
+ raise EvalError, "invalid type of operand"
93
+ end
94
+ runtime.stack.push(${CLASS}(const))
95
+ RUBY
96
+
97
+ const__f: <<~RUBY,
98
+ when :${PREFIX}_const
99
+ const = insn.operand[0]
100
+ if !const.is_a?(Float)
101
+ raise EvalError, "invalid type of operand"
102
+ end
103
+ runtime.stack.push(${CLASS}(const))
104
+ RUBY
105
+
106
+ store: <<~RUBY,
107
+ when :${PREFIX}_store
108
+ _align = insn.operand[0] # TODO: alignment support?
109
+ offset = insn.operand[1]
110
+ raise EvalError, "[BUG] invalid type of operand" if !offset.is_a?(Integer)
111
+
112
+ value = runtime.stack.pop
113
+ addr = runtime.stack.pop
114
+ if !value.is_a?(${CLASS}) || !addr.is_a?(I32)
115
+ raise EvalError, "maybe stack too short"
116
+ end
117
+
118
+ at = addr.value + offset
119
+ data_end = at + value.packed.size
120
+ memory = runtime.instance.store.memories[0] || raise("[BUG] no memory")
121
+ memory.data[at...data_end] = value.packed
122
+ RUBY
123
+ }
124
+ end
@@ -0,0 +1,18 @@
1
+ # rbs_inline: enabled
2
+ require_relative "value"
3
+
4
+ module Wardite
5
+ module Evaluator
6
+ # @rbs runtime: Runtime
7
+ # @rbs frame: Frame
8
+ # @rbs insn: Op
9
+ # @rbs return: void
10
+ def self.${PREFIX}_eval_insn(runtime, frame, insn)
11
+ case insn.code
12
+ ${DEFS}
13
+ else
14
+ raise "Unknown opcode for namespace #{insn.namespace}: #{insn.code}"
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,11 @@
1
+ # Generated from lib/wardite/alu_i32.generated.rb with RBS::Inline
2
+
3
+ module Wardite
4
+ module Evaluator
5
+ # @rbs runtime: Runtime
6
+ # @rbs frame: Frame
7
+ # @rbs insn: Op
8
+ # @rbs return: void
9
+ def self.i32_eval_insn: (Runtime runtime, Frame frame, Op insn) -> void
10
+ end
11
+ end
@@ -1,19 +1,22 @@
1
1
  # Generated from lib/wardite/instruction.rb with RBS::Inline
2
2
 
3
- # rbs_inline: enabled
4
3
  module Wardite
5
4
  class Op
5
+ attr_accessor namespace: Symbol
6
+
6
7
  attr_accessor code: Symbol
7
8
 
8
- attr_accessor operand: Array[Object]
9
+ # TODO: add types of potential operands
10
+ attr_accessor operand: Array[Integer | Float | Block]
9
11
 
12
+ # @rbs namespace: Symbol
10
13
  # @rbs code: Symbol
11
- # @rbs operand: Array[Object]
12
- def initialize: (Symbol code, Array[Object] operand) -> untyped
14
+ # @rbs operand: Array[Integer|Float|Block]
15
+ def initialize: (Symbol namespace, Symbol code, Array[Integer | Float | Block] operand) -> untyped
13
16
 
14
17
  # @rbs chr: String
15
- # @rbs return: Symbol
16
- def self.to_sym: (String chr) -> Symbol
18
+ # @rbs return: [Symbol, Symbol]
19
+ def self.to_sym: (String chr) -> [ Symbol, Symbol ]
17
20
 
18
21
  # @rbs chr: Symbol
19
22
  # @rbs return: Array[Symbol]
@@ -2,7 +2,7 @@
2
2
 
3
3
  # rbs_inline: enabled
4
4
  module Wardite
5
- module Leb128Helpers
5
+ module Leb128Helper
6
6
  # @rbs buf: File|StringIO
7
7
  # @rbs return: Integer
8
8
  def fetch_uleb128: (File | StringIO buf) -> Integer
@@ -0,0 +1,58 @@
1
+ # Generated from lib/wardite/value.rb with RBS::Inline
2
+
3
+ module Wardite
4
+ class I32
5
+ attr_accessor value: Integer
6
+
7
+ # TODO: eliminate use of pack, to support mruby - in this file!
8
+ # @rbs return: String
9
+ def packed: () -> String
10
+
11
+ def inspect: () -> untyped
12
+ end
13
+
14
+ class I64
15
+ attr_accessor value: Integer
16
+
17
+ # @rbs return: String
18
+ def packed: () -> String
19
+
20
+ def inspect: () -> untyped
21
+ end
22
+
23
+ class F32
24
+ attr_accessor value: Float
25
+
26
+ # @rbs return: String
27
+ def packed: () -> String
28
+
29
+ def inspect: () -> untyped
30
+ end
31
+
32
+ class F64
33
+ attr_accessor value: Float
34
+
35
+ # @rbs return: String
36
+ def packed: () -> String
37
+
38
+ def inspect: () -> untyped
39
+ end
40
+
41
+ module ValueHelper
42
+ # @rbs value: Integer
43
+ # @rbs return: I32
44
+ def I32: (Integer value) -> I32
45
+
46
+ # @rbs value: Integer
47
+ # @rbs return: I64
48
+ def I64: (Integer value) -> I64
49
+
50
+ # @rbs value: Float
51
+ # @rbs return: F32
52
+ def F32: (Float value) -> F32
53
+
54
+ # @rbs value: Float
55
+ # @rbs return: F64
56
+ def F64: (Float value) -> F64
57
+ end
58
+ end
@@ -3,14 +3,16 @@
3
3
  # rbs_inline: enabled
4
4
  module Wardite
5
5
  class WasiSnapshotPreview1
6
+ include ValueHelper
7
+
6
8
  attr_accessor fd_table: Array[IO]
7
9
 
8
10
  def initialize: () -> untyped
9
11
 
10
12
  # @rbs store: Store
11
- # @rbs args: Array[Object]
13
+ # @rbs args: Array[I32|I64|F32|F64]
12
14
  # @rbs return: Object
13
- def fd_write: (Store store, Array[Object] args) -> Object
15
+ def fd_write: (Store store, Array[I32 | I64 | F32 | F64] args) -> Object
14
16
 
15
17
  # @rbs return: Hash[Symbol, Proc]
16
18
  def to_module: () -> Hash[Symbol, Proc]
@@ -1,5 +1,11 @@
1
1
  # Generated from lib/wardite.rb with RBS::Inline
2
2
 
3
+ module Wardite
4
+ module Evaluator
5
+ extend Wardite::ValueHelper
6
+ end
7
+ end
8
+
3
9
  module Wardite
4
10
  class Section
5
11
  attr_accessor name: String
@@ -107,7 +113,9 @@ module Wardite
107
113
  end
108
114
 
109
115
  module BinaryLoader
110
- extend Wardite::Leb128Helpers
116
+ extend Wardite::Leb128Helper
117
+
118
+ extend Wardite::ValueHelper
111
119
 
112
120
  # @rbs buf: File|StringIO
113
121
  # @rbs import_object: Hash[Symbol, Hash[Symbol, Proc]]
@@ -204,7 +212,10 @@ module Wardite
204
212
  end
205
213
 
206
214
  class Runtime
207
- attr_accessor stack: Array[Object]
215
+ include ValueHelper
216
+
217
+ # TODO: add types of class that the stack accomodates
218
+ attr_accessor stack: Array[I32 | I64 | F32 | F64 | Block]
208
219
 
209
220
  attr_accessor call_stack: Array[Frame]
210
221
 
@@ -222,11 +233,6 @@ module Wardite
222
233
  # @rbs return: Object|nil
223
234
  def call: (String | Symbol name, Array[Object] args) -> (Object | nil)
224
235
 
225
- # @rbs idx: Integer
226
- # @rbs args: Array[Object]
227
- # @rbs return: Object|nil
228
- def call_index: (Integer idx, Array[Object] args) -> (Object | nil)
229
-
230
236
  # @rbs wasm_function: WasmFunction
231
237
  # @rbs return: void
232
238
  def push_frame: (WasmFunction wasm_function) -> void
@@ -236,8 +242,8 @@ module Wardite
236
242
  def invoke_internal: (WasmFunction wasm_function) -> (Object | nil)
237
243
 
238
244
  # @rbs external_function: ExternalFunction
239
- # @rbs return: Object|nil
240
- def invoke_external: (ExternalFunction external_function) -> (Object | nil)
245
+ # @rbs return: I32|I64|F32|F64|nil
246
+ def invoke_external: (ExternalFunction external_function) -> (I32 | I64 | F32 | F64 | nil)
241
247
 
242
248
  # @rbs return: void
243
249
  def execute!: () -> void
@@ -259,8 +265,8 @@ module Wardite
259
265
  def stack_unwind: (Integer sp, Integer arity) -> void
260
266
 
261
267
  # @rbs finish: Integer
262
- # @rbs return: Array[Object]
263
- def drained_stack: (Integer finish) -> Array[Object]
268
+ # @rbs return: Array[I32|I64|F32|F64|Block]
269
+ def drained_stack: (Integer finish) -> Array[I32 | I64 | F32 | F64 | Block]
264
270
 
265
271
  # @rbs name: Symbol
266
272
  # @rbs args: Array[Object]
@@ -283,7 +289,7 @@ module Wardite
283
289
 
284
290
  attr_accessor labels: Array[Label]
285
291
 
286
- attr_accessor locals: Array[Object]
292
+ attr_accessor locals: Array[I32 | I64 | F32 | F64]
287
293
 
288
294
  # @rbs pc: Integer
289
295
  # @rbs sp: Integer
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: wardite
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Uchio Kondo
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-10-28 00:00:00.000000000 Z
11
+ date: 2024-11-02 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: A pure-ruby webassembly runtime
14
14
  email:
@@ -34,15 +34,21 @@ files:
34
34
  - examples/memory.wat
35
35
  - exe/wardite
36
36
  - lib/wardite.rb
37
+ - lib/wardite/alu_i32.generated.rb
37
38
  - lib/wardite/const.rb
38
39
  - lib/wardite/instruction.rb
39
40
  - lib/wardite/leb128.rb
41
+ - lib/wardite/value.rb
40
42
  - lib/wardite/version.rb
41
43
  - lib/wardite/wasi.rb
44
+ - scripts/gen_alu.rb
45
+ - scripts/templates/alu_module.rb.tmpl
42
46
  - sig/generated/wardite.rbs
47
+ - sig/generated/wardite/alu_i32.generated.rbs
43
48
  - sig/generated/wardite/const.rbs
44
49
  - sig/generated/wardite/instruction.rbs
45
50
  - sig/generated/wardite/leb128.rbs
51
+ - sig/generated/wardite/value.rbs
46
52
  - sig/generated/wardite/version.rbs
47
53
  - sig/generated/wardite/wasi.rbs
48
54
  - sig/wardite.rbs