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 +4 -4
- data/Rakefile +15 -0
- data/lib/wardite/alu_i32.generated.rb +77 -0
- data/lib/wardite/instruction.rb +48 -30
- data/lib/wardite/leb128.rb +1 -1
- data/lib/wardite/value.rb +82 -0
- data/lib/wardite/version.rb +1 -1
- data/lib/wardite/wasi.rb +5 -3
- data/lib/wardite.rb +117 -90
- data/scripts/gen_alu.rb +124 -0
- data/scripts/templates/alu_module.rb.tmpl +18 -0
- data/sig/generated/wardite/alu_i32.generated.rbs +11 -0
- data/sig/generated/wardite/instruction.rbs +9 -6
- data/sig/generated/wardite/leb128.rbs +1 -1
- data/sig/generated/wardite/value.rbs +58 -0
- data/sig/generated/wardite/wasi.rbs +4 -2
- data/sig/generated/wardite.rbs +18 -12
- metadata +8 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8e33fd39e5cc58e9ec6071c4a74d5cbe872d68355657dd1adfdf375d74cf03b9
|
4
|
+
data.tar.gz: cee2e80f2dda3a2366450cf9b2d6656b172faa41b69eba39c03610b8a3c8d38b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
data/lib/wardite/instruction.rb
CHANGED
@@ -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
|
-
|
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[
|
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
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
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
|
-
|
62
|
+
[:default, code]
|
45
63
|
end
|
46
64
|
end
|
47
65
|
|
data/lib/wardite/leb128.rb
CHANGED
@@ -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
|
data/lib/wardite/version.rb
CHANGED
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[
|
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?(
|
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::
|
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[
|
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
|
-
|
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.
|
712
|
-
|
713
|
-
|
714
|
-
|
715
|
-
|
716
|
-
|
717
|
-
|
718
|
-
|
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
|
-
|
765
|
-
|
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
|
768
|
-
locals.push
|
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:
|
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?(
|
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
|
-
|
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
|
-
|
911
|
-
|
912
|
-
|
913
|
-
|
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[
|
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[
|
1064
|
+
attr_accessor :locals #: Array[I32|I64|F32|F64]
|
1038
1065
|
|
1039
1066
|
# @rbs pc: Integer
|
1040
1067
|
# @rbs sp: Integer
|
data/scripts/gen_alu.rb
ADDED
@@ -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
|
-
|
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[
|
12
|
-
def initialize: (Symbol code, Array[
|
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]
|
@@ -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[
|
13
|
+
# @rbs args: Array[I32|I64|F32|F64]
|
12
14
|
# @rbs return: Object
|
13
|
-
def fd_write: (Store store, Array[
|
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]
|
data/sig/generated/wardite.rbs
CHANGED
@@ -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::
|
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
|
-
|
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:
|
240
|
-
def invoke_external: (ExternalFunction external_function) -> (
|
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[
|
263
|
-
def drained_stack: (Integer finish) -> Array[
|
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[
|
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.
|
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-
|
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
|