wardite 0.1.1 → 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a5f1ce687265ea33d718ed38618cdba69873acabbd241515ef941f7a226672d0
4
- data.tar.gz: a8a2cef102636f2fdfb9dc530bd268a6e8eb754bc2da9af882acd0b60e4c47f8
3
+ metadata.gz: 8e33fd39e5cc58e9ec6071c4a74d5cbe872d68355657dd1adfdf375d74cf03b9
4
+ data.tar.gz: cee2e80f2dda3a2366450cf9b2d6656b172faa41b69eba39c03610b8a3c8d38b
5
5
  SHA512:
6
- metadata.gz: b0e1f8005b1b96f7f2f34d32b1ddf97dde71577791a91d5a3309c9c83bf46e25e0d41f25d5859a94d4fec8714f4b7a42700756f8d6fae87c7e32b5d97e265e87
7
- data.tar.gz: c6e9f7333baf51b2a08f0944beae0095a430c32a151c317e17d0becccf337724b86a0f214697e203cfbfbc251ee974230a211cc130ff2ff8cf95eabf09a47de6
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
 
data/exe/wardite CHANGED
@@ -11,6 +11,13 @@ instance = Wardite::BinaryLoader::load_from_buffer(f);
11
11
  if !method && instance.runtime.respond_to?(:_start)
12
12
  instance.runtime._start
13
13
  else
14
+ args = args.map do|a|
15
+ if a.include? "."
16
+ a.to_f
17
+ else
18
+ a.to_i
19
+ end
20
+ end
14
21
  ret = instance.runtime.call(method, args)
15
22
  $stderr.puts "return value: #{ret.inspect}"
16
23
  end
@@ -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.1" #: 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.1
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