wardite 0.3.0 → 0.4.1

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: f92001daa1c57ae535fd1556fabee90a61dbe741e4e5b9f313c26e5d75d68b3e
4
- data.tar.gz: 237df98e70875e1b6e69fbf0019cc298c3df26fa69cd4e62df8a04eaeff37522
3
+ metadata.gz: '02079b17ada50d21f00ea34c1830452eea21ff12a2fb6e9c5903d07cdca53d3a'
4
+ data.tar.gz: 9ab24caf2cc630593ce32ab652c8044a621f67ddce1cb70f75a1cd9e767b13e2
5
5
  SHA512:
6
- metadata.gz: 94b5d318cebff3c8d87ea03fa0c5489ece3ef26ca7fcd6e6324febaf55a63f0a9ecb0a76d01b5adf5712737d8daf79ac55f5e2149ff8f85612acbaee1a2ace8c
7
- data.tar.gz: c5991f43b9a62a7df87f23ec71350a77bf9493ccd083c6d0dba596c55976460e0c89625294048389a5fec1e35826bfbddd205718b45e04353b8e1627ccc4bb57
6
+ metadata.gz: 88054ffba3884002ea3ff7c63b21a38ff41a93f2e641ec7b82cf39f47e7df7672c5c6412f4efd1ca9feb6e222aaaadf98e67a40810c8ed213046df348aac8f79
7
+ data.tar.gz: 1c5b8765bff6ae42eb00c696efd8af2c6b892911d52fc68a1124fb3804419f121f886ba416b6b39b3183afa22e1f6aadf730681c004f254796c5e6934ab39da1
data/README.md CHANGED
@@ -7,6 +7,21 @@ A pure-ruby webassembly runtime.
7
7
  - [x] Fully typed by RBS (with the aid of [rbs-inline](https://github.com/soutaro/rbs-inline))
8
8
  - [ ] WASI (p1) support
9
9
 
10
+ ## Supported Instructions
11
+
12
+ ref: https://webassembly.github.io/spec/core/binary/instructions.html
13
+
14
+ - [x] Control Instructions
15
+ - [x] Parametric Instructions
16
+ - [x] Variable Instructions
17
+ - [ ] Table Instructions
18
+ - [x] Memory Instructions (except `data.drop`)
19
+ - [x] Numeric Instructions (`0x41 ... 0xC4`)
20
+ - [x] Numeric Instructions (`0xFC` Operations)
21
+ - [ ] Reference Instructions
22
+ - [ ] Vector Instructions
23
+ - [x] end `0x0B`
24
+
10
25
  ## Installation
11
26
 
12
27
  Install the gem and add to the application's Gemfile by executing:
data/Rakefile CHANGED
@@ -170,6 +170,9 @@ task :generate do
170
170
  trunc_s: [:f32, :f64],
171
171
  trunc_u: [:f32, :f64],
172
172
  reinterpret: [:f32],
173
+ extendN_s: [:i8, :i16],
174
+ trunc_sat_s: [:f32, :f64],
175
+ trunc_sat_u: [:f32, :f64],
173
176
  },
174
177
  i64: {
175
178
  extend_s: [:i32, :i64],
@@ -177,6 +180,9 @@ task :generate do
177
180
  trunc_s: [:f32, :f64],
178
181
  trunc_u: [:f32, :f64],
179
182
  reinterpret: [:f64],
183
+ extendN_s: [:i8, :i16, :i32],
184
+ trunc_sat_s: [:f32, :f64],
185
+ trunc_sat_u: [:f32, :f64],
180
186
  },
181
187
  f32: {
182
188
  convert_s: [:i32, :i64],
@@ -0,0 +1,18 @@
1
+ (module ;;
2
+ (memory 1)
3
+ (data (i32.const 0) "hello") ;; data segment 0, is active so always copied
4
+ (data "goodbye") ;; data segment 1, is passive
5
+
6
+ (func $start (param $test i32) (result i32)
7
+ (if (local.get $test)
8
+ (then (memory.init 1
9
+ (i32.const 16)
10
+ (i32.const 0)
11
+ (i32.const 7))
12
+ (return (i32.const 1))
13
+ )
14
+ )
15
+ (return (i32.const 0))
16
+ )
17
+ (export "test" (func $start))
18
+ )
@@ -0,0 +1,8 @@
1
+ (module
2
+ (global $big (mut f64) (f64.const 50000000000.0))
3
+ (func $main (result i32)
4
+ global.get $big
5
+ i32.trunc_sat_f64_s
6
+ )
7
+ (export "saturate" (func $main))
8
+ )
@@ -0,0 +1,9 @@
1
+ (module
2
+ (global $big (mut f64) (f64.const 50000000000.0))
3
+ (func $main (result i64)
4
+ global.get $big
5
+ i32.trunc_sat_f64_u
6
+ i64.extend_i32_u
7
+ )
8
+ (export "saturate" (func $main))
9
+ )
data/lib/wardite/const.rb CHANGED
@@ -3,18 +3,19 @@ module Wardite
3
3
  module Const
4
4
  # Section Code
5
5
  # @see https://www.w3.org/TR/wasm-core-1/#sections%E2%91%A0
6
- SectionCustom = 0x0 #: Integer
7
- SectionType = 0x1 #: Integer
8
- SectionImport = 0x2 #: Integer
9
- SectionFunction = 0x3 #: Integer
10
- SectionTable = 0x4 #: Integer
11
- SectionMemory = 0x5 #: Integer
12
- SectionGlobal = 0x6 #: Integer
13
- SectionExport = 0x7 #: Integer
14
- SectionStart = 0x8 #: Integer
15
- SectionElement = 0x9 #: Integer
16
- SectionCode = 0xa #: Integer
17
- SectionData = 0xb #: Integer
6
+ SectionCustom = 0x0 #: Integer
7
+ SectionType = 0x1 #: Integer
8
+ SectionImport = 0x2 #: Integer
9
+ SectionFunction = 0x3 #: Integer
10
+ SectionTable = 0x4 #: Integer
11
+ SectionMemory = 0x5 #: Integer
12
+ SectionGlobal = 0x6 #: Integer
13
+ SectionExport = 0x7 #: Integer
14
+ SectionStart = 0x8 #: Integer
15
+ SectionElement = 0x9 #: Integer
16
+ SectionCode = 0xa #: Integer
17
+ SectionData = 0xb #: Integer
18
+ SectionDataCount = 0xc #: Integer
18
19
  end
19
20
  include Const
20
21
  end
@@ -58,6 +58,54 @@ module Wardite
58
58
  runtime.stack.push(to)
59
59
 
60
60
 
61
+ when :i32_extend_8_s
62
+ from = runtime.stack.pop
63
+ raise EvalError, "maybe empty or invalid stack" if !from.is_a?(I32)
64
+ to = from.extendN_s(to: :i32, from: :i8)
65
+ raise EvalError, "failed to convert type" if !to.is_a?(I32)
66
+ runtime.stack.push(to)
67
+
68
+
69
+ when :i32_extend_16_s
70
+ from = runtime.stack.pop
71
+ raise EvalError, "maybe empty or invalid stack" if !from.is_a?(I32)
72
+ to = from.extendN_s(to: :i32, from: :i16)
73
+ raise EvalError, "failed to convert type" if !to.is_a?(I32)
74
+ runtime.stack.push(to)
75
+
76
+
77
+ when :i32_trunc_sat_f32_s
78
+ from = runtime.stack.pop
79
+ raise EvalError, "maybe empty or invalid stack" if !from.is_a?(F32)
80
+ to = from.trunc_sat_s(to: :i32)
81
+ raise EvalError, "failed to convert type" if !to.is_a?(I32)
82
+ runtime.stack.push(to)
83
+
84
+
85
+ when :i32_trunc_sat_f64_s
86
+ from = runtime.stack.pop
87
+ raise EvalError, "maybe empty or invalid stack" if !from.is_a?(F64)
88
+ to = from.trunc_sat_s(to: :i32)
89
+ raise EvalError, "failed to convert type" if !to.is_a?(I32)
90
+ runtime.stack.push(to)
91
+
92
+
93
+ when :i32_trunc_sat_f32_u
94
+ from = runtime.stack.pop
95
+ raise EvalError, "maybe empty or invalid stack" if !from.is_a?(F32)
96
+ to = from.trunc_sat_u(to: :i32)
97
+ raise EvalError, "failed to convert type" if !to.is_a?(I32)
98
+ runtime.stack.push(to)
99
+
100
+
101
+ when :i32_trunc_sat_f64_u
102
+ from = runtime.stack.pop
103
+ raise EvalError, "maybe empty or invalid stack" if !from.is_a?(F64)
104
+ to = from.trunc_sat_u(to: :i32)
105
+ raise EvalError, "failed to convert type" if !to.is_a?(I32)
106
+ runtime.stack.push(to)
107
+
108
+
61
109
  when :i64_extend_i32_s
62
110
  from = runtime.stack.pop
63
111
  raise EvalError, "maybe empty or invalid stack" if !from.is_a?(I32)
@@ -130,6 +178,62 @@ module Wardite
130
178
  runtime.stack.push(to)
131
179
 
132
180
 
181
+ when :i64_extend_8_s
182
+ from = runtime.stack.pop
183
+ raise EvalError, "maybe empty or invalid stack" if !from.is_a?(I32)
184
+ to = from.extendN_s(to: :i64, from: :i8)
185
+ raise EvalError, "failed to convert type" if !to.is_a?(I64)
186
+ runtime.stack.push(to)
187
+
188
+
189
+ when :i64_extend_16_s
190
+ from = runtime.stack.pop
191
+ raise EvalError, "maybe empty or invalid stack" if !from.is_a?(I32)
192
+ to = from.extendN_s(to: :i64, from: :i16)
193
+ raise EvalError, "failed to convert type" if !to.is_a?(I64)
194
+ runtime.stack.push(to)
195
+
196
+
197
+ when :i64_extend_32_s
198
+ from = runtime.stack.pop
199
+ raise EvalError, "maybe empty or invalid stack" if !from.is_a?(I32)
200
+ to = from.extendN_s(to: :i64, from: :i32)
201
+ raise EvalError, "failed to convert type" if !to.is_a?(I64)
202
+ runtime.stack.push(to)
203
+
204
+
205
+ when :i64_trunc_sat_f32_s
206
+ from = runtime.stack.pop
207
+ raise EvalError, "maybe empty or invalid stack" if !from.is_a?(F32)
208
+ to = from.trunc_sat_s(to: :i64)
209
+ raise EvalError, "failed to convert type" if !to.is_a?(I64)
210
+ runtime.stack.push(to)
211
+
212
+
213
+ when :i64_trunc_sat_f64_s
214
+ from = runtime.stack.pop
215
+ raise EvalError, "maybe empty or invalid stack" if !from.is_a?(F64)
216
+ to = from.trunc_sat_s(to: :i64)
217
+ raise EvalError, "failed to convert type" if !to.is_a?(I64)
218
+ runtime.stack.push(to)
219
+
220
+
221
+ when :i64_trunc_sat_f32_u
222
+ from = runtime.stack.pop
223
+ raise EvalError, "maybe empty or invalid stack" if !from.is_a?(F32)
224
+ to = from.trunc_sat_u(to: :i64)
225
+ raise EvalError, "failed to convert type" if !to.is_a?(I64)
226
+ runtime.stack.push(to)
227
+
228
+
229
+ when :i64_trunc_sat_f64_u
230
+ from = runtime.stack.pop
231
+ raise EvalError, "maybe empty or invalid stack" if !from.is_a?(F64)
232
+ to = from.trunc_sat_u(to: :i64)
233
+ raise EvalError, "failed to convert type" if !to.is_a?(I64)
234
+ runtime.stack.push(to)
235
+
236
+
133
237
  when :f32_convert_i32_s
134
238
  from = runtime.stack.pop
135
239
  raise EvalError, "maybe empty or invalid stack" if !from.is_a?(I32)
@@ -31,15 +31,27 @@ module Wardite
31
31
  i32_trunc_f32_s i32_trunc_f32_u i32_trunc_f64_s i32_trunc_f64_u i64_extend_i32_s i64_extend_i32_u i64_trunc_f32_s i64_trunc_f32_u
32
32
  i64_trunc_f64_s i64_trunc_f64_u f32_convert_i32_s f32_convert_i32_u f32_convert_i64_s f32_convert_i64_u f32_demote_f64 f64_convert_i32_s
33
33
  f64_convert_i32_u f64_convert_i64_s f64_convert_i64_u f64_promote_f32 i32_reinterpret_f32 i64_reinterpret_f64 f32_reinterpret_i32 f64_reinterpret_i64
34
+ i32_extend8_s i32_extend16_s i64_extend8_s i64_extend16_s i64_extend32_s
34
35
  __unsuported_from_here_on__
35
36
  ] #: Array[Symbol]
36
37
 
38
+ FC_SYMS = %i[
39
+ i32_trunc_sat_f32_s i32_trunc_sat_f32_u i32_trunc_sat_f64_s i32_trunc_sat_f64_u
40
+ i64_trunc_sat_f32_s i64_trunc_sat_f32_u i64_trunc_sat_f64_s i64_trunc_sat_f64_u
41
+ memory_init data_drop memory_copy memory_fill
42
+ table_init elem_drop table_copy table_grow
43
+ table_size table_fill
44
+ __unsuported_from_here_on__
45
+ ] #: Array[Symbol]
46
+
47
+ # @rbs @@table: Hash[Integer, Symbol] | nil
48
+ @@table = nil
37
49
  # @rbs @@table: Hash[Integer, Symbol] | nil
38
- @@table = nil
50
+ @@fc_table = nil
39
51
 
40
52
  # @rbs return: Hash[Integer, Symbol]
41
53
  def self.table
42
- @@table if @@table != nil
54
+ return @@table if @@table != nil
43
55
  @@table = {}.tap do |ha|
44
56
  SYMS.each_with_index do |sym, i|
45
57
  ha[i] = sym
@@ -48,6 +60,17 @@ module Wardite
48
60
  @@table
49
61
  end
50
62
 
63
+ # @rbs return: Hash[Integer, Symbol]
64
+ def self.fc_table
65
+ return @@fc_table if @@fc_table != nil
66
+ @@fc_table = {}.tap do |ha|
67
+ FC_SYMS.each_with_index do |sym, i|
68
+ ha[i] = sym
69
+ end
70
+ end
71
+ @@fc_table
72
+ end
73
+
51
74
  attr_accessor :namespace #: Symbol
52
75
 
53
76
  attr_accessor :code #: Symbol
@@ -67,6 +90,10 @@ module Wardite
67
90
  # @rbs chr: String
68
91
  # @rbs return: [Symbol, Symbol]
69
92
  def self.to_sym(chr)
93
+ if chr.ord == 0xfc
94
+ return [:fc, :fc]
95
+ end
96
+
70
97
  code = table[chr.ord]
71
98
  if ! code
72
99
  raise "found unknown code 0x#{chr.ord.to_s(16)}"
@@ -85,6 +112,28 @@ module Wardite
85
112
  end
86
113
  end
87
114
 
115
+ # @rbs lower: Integer
116
+ # @rbs return: [Symbol, Symbol]
117
+ def self.resolve_fc_sym(lower)
118
+ if lower == 0xfc
119
+ return [:fc, :fc]
120
+ end
121
+
122
+ code = fc_table[lower]
123
+ if ! code
124
+ raise "found unknown code 0xfc 0x#{lower.to_s(16)}"
125
+ end
126
+
127
+ prefix = code.to_s.split("_")[0]
128
+ case prefix
129
+ when "i32", "i64", "f32", "f64"
130
+ # All FC operations for numeric are "convert"
131
+ [:convert, code]
132
+ else
133
+ [:default, code]
134
+ end
135
+ end
136
+
88
137
  # @rbs code: Symbol
89
138
  # @rbs return: Array[Symbol]
90
139
  def self.operand_of(code)
@@ -93,8 +142,12 @@ module Wardite
93
142
  [:u32, :u32]
94
143
  when :local_get, :local_set, :local_tee, :global_get, :global_set, :call, :br, :br_if
95
144
  [:u32]
145
+ when :memory_init, :memory_copy
146
+ [:u32, :u32]
147
+ when :memory_size, :memory_grow, :memory_fill
148
+ [:u32]
96
149
  when :call_indirect
97
- [:u32, :u8]
150
+ [:u32, :u32]
98
151
  when :br_table
99
152
  [:u32_vec, :u32]
100
153
  when :i32_const
@@ -2,8 +2,9 @@
2
2
  module Wardite
3
3
  module Leb128Helper
4
4
  # @rbs buf: File|StringIO
5
+ # @rbs max_level: Integer
5
6
  # @rbs return: Integer
6
- def fetch_uleb128(buf)
7
+ def fetch_uleb128(buf, max_level: 8)
7
8
  dest = 0
8
9
  level = 0
9
10
  while b = buf.read(1)
@@ -18,7 +19,7 @@ module Wardite
18
19
  return dest
19
20
  end
20
21
 
21
- if level > 6
22
+ if level > max_level
22
23
  break
23
24
  end
24
25
  level += 1
@@ -29,7 +30,7 @@ module Wardite
29
30
 
30
31
  # @rbs buf: File|StringIO
31
32
  # @rbs return: Integer
32
- def fetch_sleb128(buf)
33
+ def fetch_sleb128(buf, max_level: 8)
33
34
  dest = 0
34
35
  level = 0
35
36
  while b = buf.read(1)
@@ -44,7 +45,7 @@ module Wardite
44
45
  break
45
46
  end
46
47
 
47
- if level > 6
48
+ if level > max_level
48
49
  raise "unreachable! debug: dest = #{dest} level = #{level}"
49
50
  end
50
51
  level += 1
data/lib/wardite/load.rb CHANGED
@@ -148,7 +148,9 @@ module Wardite
148
148
 
149
149
  class DataSection < Section
150
150
  class Segment
151
- attr_accessor :flags #: Integer
151
+ attr_accessor :mode #: :active|:passive
152
+
153
+ attr_accessor :mem_index #: Integer
152
154
 
153
155
  attr_accessor :offset #: Integer
154
156
 
@@ -172,6 +174,19 @@ module Wardite
172
174
  end
173
175
  end
174
176
 
177
+ class DataCountSection < Section
178
+ attr_accessor :count #: Integer
179
+
180
+ # @rbs count: Integer
181
+ # @rbs return: void
182
+ def initialize(count)
183
+ self.name = "Data"
184
+ self.code = 0xc
185
+
186
+ @count = count
187
+ end
188
+ end
189
+
175
190
  class ExportSection < Section
176
191
  class ExportDesc
177
192
  attr_accessor :name #: String
@@ -310,6 +325,8 @@ module Wardite
310
325
  code_section
311
326
  when Wardite::SectionData
312
327
  data_section
328
+ when Wardite::Const::SectionDataCount
329
+ data_count_section
313
330
  when Wardite::SectionCustom
314
331
  unimplemented_skip_section(code)
315
332
  else
@@ -590,7 +607,7 @@ module Wardite
590
607
  def self.code_body(buf)
591
608
  dest = []
592
609
  while c = buf.read(1)
593
- namespace, code = Op.to_sym(c)
610
+ namespace, code = resolve_code(c, buf)
594
611
  operand_types = Op.operand_of(code)
595
612
  operand = [] #: Array[operandItem]
596
613
  operand_types.each do |typ|
@@ -613,7 +630,7 @@ module Wardite
613
630
  when :i32
614
631
  operand << fetch_sleb128(buf)
615
632
  when :i64
616
- operand << fetch_sleb128(buf)
633
+ operand << fetch_sleb128(buf, max_level: 16)
617
634
  when :f32
618
635
  data = buf.read 4
619
636
  if !data || data.size != 4
@@ -650,6 +667,24 @@ module Wardite
650
667
  end
651
668
 
652
669
  dest
670
+ rescue => e
671
+ require "pp"
672
+ $stderr.puts "parsed:::"
673
+ $stderr.puts "#{dest.pretty_inspect}"
674
+ $stderr.puts "code = #{code}"
675
+ raise e
676
+ end
677
+
678
+ # @rbs c: String
679
+ # @rbs buf: StringIO
680
+ # @rbs return: [Symbol, Symbol]
681
+ def self.resolve_code(c, buf)
682
+ namespace, code = Op.to_sym(c)
683
+ if namespace == :fc
684
+ lower = fetch_uleb128(buf)
685
+ return Op.resolve_fc_sym(lower) #: [Symbol, Symbol]
686
+ end
687
+ return [namespace, code] #: [Symbol, Symbol]
653
688
  end
654
689
 
655
690
  # @rbs return: DataSection
@@ -661,27 +696,54 @@ module Wardite
661
696
 
662
697
  len = fetch_uleb128(sbuf)
663
698
  len.times do |i|
664
- mem_index = fetch_uleb128(sbuf)
665
- code = fetch_insn_while_end(sbuf)
666
- ops = code_body(StringIO.new(code))
667
- offset = decode_expr(ops)
668
-
669
- len = fetch_uleb128(sbuf)
670
- data = sbuf.read len
671
- if !data
672
- raise LoadError, "buffer too short"
673
- end
674
-
675
- segment = DataSection::Segment.new do |seg|
676
- seg.flags = mem_index
677
- seg.offset = offset
678
- seg.data = data
699
+ data_type = fetch_uleb128(sbuf)
700
+ case data_type
701
+ when 0x0
702
+ # active
703
+ code = fetch_insn_while_end(sbuf)
704
+ ops = code_body(StringIO.new(code))
705
+ offset = decode_expr(ops)
706
+ len = fetch_uleb128(sbuf)
707
+ data = sbuf.read len
708
+ if !data
709
+ raise LoadError, "buffer too short"
710
+ end
711
+ segment = DataSection::Segment.new do |seg|
712
+ seg.mode = :active
713
+ seg.mem_index = 0 # memory index
714
+ seg.offset = offset
715
+ seg.data = data
716
+ end
717
+ dest.segments << segment
718
+ when 0x1
719
+ # passive
720
+ dsize = fetch_uleb128(sbuf)
721
+ data = sbuf.read dsize
722
+ if !data
723
+ raise LoadError, "data too short"
724
+ end
725
+ segment = DataSection::Segment.new do |seg|
726
+ seg.mode = :passive
727
+ seg.mem_index = 0 # unused
728
+ seg.offset = 0 # unused
729
+ seg.data = data
730
+ end
731
+ dest.segments << segment
679
732
  end
680
- dest.segments << segment
681
733
  end
682
734
  dest
683
735
  end
684
736
 
737
+ # @rbs return: DataCountSection
738
+ def self.data_count_section
739
+ size = fetch_uleb128(@buf)
740
+ sbuf = StringIO.new(@buf.read(size) || raise("buffer too short"))
741
+ count = fetch_uleb128(sbuf)
742
+ dest = DataCountSection.new(count)
743
+ dest.size = size
744
+ dest
745
+ end
746
+
685
747
  # @rbs sbuf: StringIO
686
748
  # @rbs return: String
687
749
  def self.fetch_insn_while_end(sbuf)
@@ -740,7 +802,18 @@ module Wardite
740
802
  raise "Invalid definition of operand"
741
803
  end
742
804
  return I64(arg)
743
- # TODO: floats
805
+ when :f32_const
806
+ arg = op.operand[0]
807
+ if !arg.is_a?(Float)
808
+ raise "Invalid definition of operand"
809
+ end
810
+ return F32(arg)
811
+ when :f64_const
812
+ arg = op.operand[0]
813
+ if !arg.is_a?(Float)
814
+ raise "Invalid definition of operand"
815
+ end
816
+ return F64(arg)
744
817
  else
745
818
  raise "Unimplemented offset op: #{op.code.inspect}"
746
819
  end
@@ -778,7 +851,7 @@ module Wardite
778
851
  # @rbs return: nil
779
852
  def self.unimplemented_skip_section(code)
780
853
  $stderr.puts "warning: unimplemented section: 0x0#{code}"
781
- size = @buf.read(1)&.ord
854
+ size = fetch_uleb128(@buf)
782
855
  @buf.read(size)
783
856
  nil
784
857
  end
data/lib/wardite/value.rb CHANGED
@@ -56,7 +56,7 @@ module Wardite
56
56
  class I32
57
57
  include ValueHelper
58
58
 
59
- I32_MAX = (1<<32) - 1
59
+ I32_MAX = (1<<32) - 1 #: Integer
60
60
  # value should be stored as unsigned Integer, even in I32/I64
61
61
  # when we want to access signed value, it'd be done via #value_s
62
62
  attr_accessor :value #: Integer
@@ -190,6 +190,49 @@ module Wardite
190
190
  F32(v)
191
191
  end
192
192
 
193
+ # @rbs from: Symbol
194
+ # @rbs to: Symbol
195
+ # @rbs return: wasmValue
196
+ def extendN_s(from:, to:)
197
+ src_value = case from
198
+ when :i8
199
+ base = value & 0xff
200
+ (base >> 8).zero? ?
201
+ base :
202
+ ((-base) ^ 0xff) + 1
203
+ when :i16
204
+ base = value & 0xffff
205
+ (base >> 15).zero? ?
206
+ base :
207
+ ((-base) ^ 0xffff) + 1
208
+ when :i32
209
+ value_s
210
+ else
211
+ raise EvalError, "unsupported value size"
212
+ end
213
+
214
+ case to
215
+ when :i32
216
+ I32(src_value)
217
+ when :i64
218
+ I64(src_value)
219
+ else
220
+ raise EvalError, "unsupported value size"
221
+ end
222
+ end
223
+
224
+ # @rbs to: Symbol
225
+ # @rbs return: wasmValue
226
+ def trunc_sat_u(to:)
227
+ raise EvalError, "unsupported operation"
228
+ end
229
+
230
+ # @rbs to: Symbol
231
+ # @rbs return: wasmValue
232
+ def trunc_sat_s(to:)
233
+ raise EvalError, "unsupported operation"
234
+ end
235
+
193
236
  # I32#inspect shows signed value for convinience
194
237
  def inspect
195
238
  "I32(#{value_s})"
@@ -199,7 +242,7 @@ module Wardite
199
242
  class I64
200
243
  include ValueHelper
201
244
 
202
- I64_MAX = (1<<64) - 1
245
+ I64_MAX = (1<<64) - 1 #: Integer
203
246
 
204
247
  attr_accessor :value #: Integer
205
248
 
@@ -334,6 +377,25 @@ module Wardite
334
377
  F32(v)
335
378
  end
336
379
 
380
+ # @rbs from: Symbol
381
+ # @rbs to: Symbol
382
+ # @rbs return: wasmValue
383
+ def extendN_s(from:, to:)
384
+ raise EvalError, "unsupported operation"
385
+ end
386
+
387
+ # @rbs to: Symbol
388
+ # @rbs return: wasmValue
389
+ def trunc_sat_u(to:)
390
+ raise EvalError, "unsupported operation"
391
+ end
392
+
393
+ # @rbs to: Symbol
394
+ # @rbs return: wasmValue
395
+ def trunc_sat_s(to:)
396
+ raise EvalError, "unsupported operation"
397
+ end
398
+
337
399
  # I64#inspect shows signed value
338
400
  def inspect
339
401
  "I64(#{@value})"
@@ -395,28 +457,52 @@ module Wardite
395
457
 
396
458
  # @todo need more testcase...
397
459
  # @see https://webassembly.github.io/spec/core/exec/numerics.html#xref-exec-numerics-op-trunc-s-mathrm-trunc-mathsf-s-m-n-z
460
+ # @see copy this impl to F64 when changed
398
461
  # @rbs to: Symbol
462
+ # @rbs saturating: bool
399
463
  # @rbs return: wasmValue
400
- def trunc_s(to:)
464
+ def trunc_s(to:, saturating: false)
401
465
  v = value.to_i
402
466
  case to
403
467
  when :i32
404
468
  if v >= 0
405
- I32(v & (I32::I32_MAX >> 1))
469
+ i32_signed_max = I32::I32_MAX >> 1
470
+ if saturating
471
+ v = i32_signed_max if v > i32_signed_max
472
+ else
473
+ v = v & i32_signed_max
474
+ end
475
+ I32(v & i32_signed_max)
406
476
  else
407
- v = v & I32::I32_MAX
408
- if (v >> 31).zero?
409
- raise EvalError, "[undefined behavior] detected overflow: #{value}"
477
+ i32_signed_min = -(I32::I32_MAX >> 1) - 1
478
+ if saturating
479
+ v = i32_signed_min if v < i32_signed_min
480
+ else
481
+ v = v & I32::I32_MAX
482
+ if (v >> 31).zero?
483
+ raise EvalError, "[undefined behavior] detected overflow: #{value}"
484
+ end
410
485
  end
411
486
  I32(v)
412
487
  end
413
488
  when :i64
414
489
  if v >= 0
415
- I64(v & (I64::I64_MAX >> 1))
490
+ i64_signed_max = I64::I64_MAX >> 1
491
+ if saturating
492
+ v = i64_signed_max if v > i64_signed_max
493
+ else
494
+ v = v & i64_signed_max
495
+ end
496
+ I64(v & i64_signed_max)
416
497
  else
417
- v = v & I64::I64_MAX
418
- if (v >> 31).zero?
419
- raise EvalError, "[undefined behavior] detected overflow: #{value}"
498
+ i64_signed_min = -(I64::I64_MAX >> 1) - 1
499
+ if saturating
500
+ v = i64_signed_min if v < i64_signed_min
501
+ else
502
+ v = v & I64::I64_MAX
503
+ if (v >> 63).zero?
504
+ raise EvalError, "[undefined behavior] detected overflow: #{value}"
505
+ end
420
506
  end
421
507
  I64(v)
422
508
  end
@@ -426,19 +512,33 @@ module Wardite
426
512
  end
427
513
 
428
514
  # @see https://webassembly.github.io/spec/core/exec/numerics.html#xref-exec-numerics-op-trunc-u-mathrm-trunc-mathsf-u-m-n-z
515
+ # @see copy this impl to F64 when changed
429
516
  # @rbs to: Symbol
517
+ # @rbs sturating: bool
430
518
  # @rbs return: wasmValue
431
- def trunc_u(to:)
519
+ def trunc_u(to:, saturating: false)
432
520
  v = value.to_i
433
521
  if v < 0
434
- raise EvalError, "[undefined behavior] unexpected negative value"
522
+ if saturating
523
+ v = 0
524
+ else
525
+ raise EvalError, "[undefined behavior] unexpected negative value"
526
+ end
435
527
  end
436
528
  case to
437
529
  when :i32
438
- v = v & I32::I32_MAX
530
+ if saturating
531
+ v = I32::I32_MAX if v > I32::I32_MAX
532
+ else
533
+ v = v & I32::I32_MAX
534
+ end
439
535
  I32(v)
440
536
  when :i64
441
- v = v & I64::I64_MAX
537
+ if saturating
538
+ v = I64::I64_MAX if v > I64::I64_MAX
539
+ else
540
+ v = v & I64::I64_MAX
541
+ end
442
542
  I64(v)
443
543
  else
444
544
  raise EvalError, "unsupported operation to: #{to}"
@@ -479,6 +579,25 @@ module Wardite
479
579
  I32(v)
480
580
  end
481
581
 
582
+ # @rbs from: Symbol
583
+ # @rbs to: Symbol
584
+ # @rbs return: wasmValue
585
+ def extendN_s(from:, to:)
586
+ raise EvalError, "unsupported operation"
587
+ end
588
+
589
+ # @rbs to: Symbol
590
+ # @rbs return: wasmValue
591
+ def trunc_sat_u(to:)
592
+ trunc_u(to: to, saturating: true)
593
+ end
594
+
595
+ # @rbs to: Symbol
596
+ # @rbs return: wasmValue
597
+ def trunc_sat_s(to:)
598
+ trunc_s(to: to, saturating: true)
599
+ end
600
+
482
601
  def inspect
483
602
  "F32(#{@value})"
484
603
  end
@@ -539,27 +658,50 @@ module Wardite
539
658
 
540
659
  # @see the same as F32
541
660
  # @rbs to: Symbol
661
+ # @rbs saturating: bool
542
662
  # @rbs return: wasmValue
543
- def trunc_s(to:)
663
+ def trunc_s(to:, saturating: false)
544
664
  v = value.to_i
545
665
  case to
546
666
  when :i32
547
667
  if v >= 0
548
- I32(v & (I32::I32_MAX >> 1))
668
+ i32_signed_max = I32::I32_MAX >> 1
669
+ if saturating
670
+ v = i32_signed_max if v > i32_signed_max
671
+ else
672
+ v = v & i32_signed_max
673
+ end
674
+ I32(v & i32_signed_max)
549
675
  else
550
- v = v & I32::I32_MAX
551
- if (v >> 31).zero?
552
- raise EvalError, "[undefined behavior] detected overflow: #{value}"
676
+ i32_signed_min = -(I32::I32_MAX >> 1) - 1
677
+ if saturating
678
+ v = i32_signed_min if v < i32_signed_min
679
+ else
680
+ v = v & I32::I32_MAX
681
+ if (v >> 31).zero?
682
+ raise EvalError, "[undefined behavior] detected overflow: #{value}"
683
+ end
553
684
  end
554
685
  I32(v)
555
686
  end
556
687
  when :i64
557
688
  if v >= 0
558
- I64(v & (I64::I64_MAX >> 1))
689
+ i64_signed_max = I64::I64_MAX >> 1
690
+ if saturating
691
+ v = i64_signed_max if v > i64_signed_max
692
+ else
693
+ v = v & i64_signed_max
694
+ end
695
+ I64(v & i64_signed_max)
559
696
  else
560
- v = v & I64::I64_MAX
561
- if (v >> 31).zero?
562
- raise EvalError, "[undefined behavior] detected overflow: #{value}"
697
+ i64_signed_min = -(I64::I64_MAX >> 1) - 1
698
+ if saturating
699
+ v = i64_signed_min if v < i64_signed_min
700
+ else
701
+ v = v & I64::I64_MAX
702
+ if (v >> 63).zero?
703
+ raise EvalError, "[undefined behavior] detected overflow: #{value}"
704
+ end
563
705
  end
564
706
  I64(v)
565
707
  end
@@ -570,18 +712,31 @@ module Wardite
570
712
 
571
713
  # @see the same as F32
572
714
  # @rbs to: Symbol
715
+ # @rbs saturating: bool
573
716
  # @rbs return: wasmValue
574
- def trunc_u(to:)
717
+ def trunc_u(to:, saturating: false)
575
718
  v = value.to_i
576
719
  if v < 0
577
- raise EvalError, "[undefined behavior] unexpected negative value"
720
+ if saturating
721
+ v = 0
722
+ else
723
+ raise EvalError, "[undefined behavior] unexpected negative value"
724
+ end
578
725
  end
579
726
  case to
580
727
  when :i32
581
- v = v & I32::I32_MAX
728
+ if saturating
729
+ v = I32::I32_MAX if v > I32::I32_MAX
730
+ else
731
+ v = v & I32::I32_MAX
732
+ end
582
733
  I32(v)
583
734
  when :i64
584
- v = v & I64::I64_MAX
735
+ if saturating
736
+ v = I64::I64_MAX if v > I64::I64_MAX
737
+ else
738
+ v = v & I64::I64_MAX
739
+ end
585
740
  I64(v)
586
741
  else
587
742
  raise EvalError, "unsupported operation to: #{to}"
@@ -623,6 +778,25 @@ module Wardite
623
778
  I64(v)
624
779
  end
625
780
 
781
+ # @rbs from: Symbol
782
+ # @rbs to: Symbol
783
+ # @rbs return: wasmValue
784
+ def extendN_s(from:, to:)
785
+ raise EvalError, "unsupported operation"
786
+ end
787
+
788
+ # @rbs to: Symbol
789
+ # @rbs return: wasmValue
790
+ def trunc_sat_u(to:)
791
+ trunc_u(to: to, saturating: true)
792
+ end
793
+
794
+ # @rbs to: Symbol
795
+ # @rbs return: wasmValue
796
+ def trunc_sat_s(to:)
797
+ trunc_s(to: to, saturating: true)
798
+ end
799
+
626
800
  def inspect
627
801
  "F64(#{@value})"
628
802
  end
@@ -2,5 +2,5 @@
2
2
  # rbs_inline: enabled
3
3
 
4
4
  module Wardite
5
- VERSION = "0.3.0" #: String
5
+ VERSION = "0.4.1" #: String
6
6
  end
data/lib/wardite.rb CHANGED
@@ -57,6 +57,22 @@ module Wardite
57
57
  @types << Type.new(calltype, rettype)
58
58
  end
59
59
  end
60
+
61
+ check_data_count
62
+ end
63
+
64
+ # @rbs return: void
65
+ def check_data_count
66
+ data_count = self.data_count_section&.count
67
+ if data_count
68
+ actual_count = self.data_section&.segments&.size
69
+ if !actual_count
70
+ raise LoadError, "invalid data segment count"
71
+ end
72
+ if (data_count != actual_count)
73
+ raise LoadError, "invalid data segment count"
74
+ end
75
+ end
60
76
  end
61
77
 
62
78
  # @rbs return: ImportSection
@@ -129,6 +145,18 @@ module Wardite
129
145
  sec
130
146
  end
131
147
 
148
+ # @rbs return: DataCountSection|nil
149
+ def data_count_section
150
+ sec = @sections.find{|s| s.code == Const::SectionDataCount }
151
+ if !sec
152
+ return nil
153
+ end
154
+ if !sec.is_a?(DataCountSection)
155
+ raise(GenericError, "[BUG] found invalid data section")
156
+ end
157
+ sec
158
+ end
159
+
132
160
  # @rbs return: FunctionSection|nil
133
161
  def function_section
134
162
  sec = @sections.find{|s| s.code == Const::SectionFunction }
@@ -216,7 +244,7 @@ module Wardite
216
244
  call_by_index(start_section.func_index)
217
245
  end
218
246
  end
219
-
247
+
220
248
  # @rbs name: String|Symbol
221
249
  # @rbs return: bool
222
250
  def callable?(name)
@@ -634,6 +662,57 @@ module Wardite
634
662
  memory = instance.store.memories[0] || raise("[BUG] no memory")
635
663
  stack.push(I32(memory.grow(delta.value)))
636
664
 
665
+ when :memory_init
666
+ idx = insn.operand[0]
667
+ if !idx.is_a?(Integer)
668
+ raise EvalError, "[BUG] invalid type of operand"
669
+ end
670
+ if insn.operand[1] != 0x0
671
+ $stderr.puts "warning: :memory_init is not ending with 0x00"
672
+ end
673
+ data_sec = instance.data_section
674
+ if !data_sec
675
+ raise EvalError, "data segment out of range"
676
+ end
677
+ data_seg = data_sec.segments[idx]
678
+ if !data_seg
679
+ raise EvalError, "data segment out of range"
680
+ end
681
+
682
+ memory = instance.store.memories[0] || raise("[BUG] no memory")
683
+ length, src_offset, dest_offset = stack.pop, stack.pop, stack.pop
684
+ if !length.is_a?(I32) || !src_offset.is_a?(I32) || !dest_offset.is_a?(I32)
685
+ raise EvalError, "invalid stack values"
686
+ end
687
+ source = data_seg.data[src_offset.value...(src_offset.value+length.value)]
688
+ raise EvalError, "invalid source range" if !source
689
+ memory.data[dest_offset.value...(dest_offset.value+length.value)] = source
690
+
691
+ when :memory_copy
692
+ if insn.operand[0] != 0x0 || insn.operand[1] != 0x0
693
+ $stderr.puts "warning: :memory_copy is not ending with 0x00"
694
+ end
695
+ length, src_offset, dest_offset = stack.pop, stack.pop, stack.pop
696
+ if !length.is_a?(I32) || !src_offset.is_a?(I32) || !dest_offset.is_a?(I32)
697
+ raise EvalError, "invalid stack values"
698
+ end
699
+ memory = instance.store.memories[0] || raise("[BUG] no memory")
700
+ source = memory.data[src_offset.value...(src_offset.value+length.value)]
701
+ raise EvalError, "invalid source range" if !source
702
+ memory.data[dest_offset.value...(dest_offset.value+length.value)] = source
703
+
704
+ when :memory_fill
705
+ if insn.operand[0] != 0x0
706
+ $stderr.puts "warning: :memory_fill is not ending with 0x00"
707
+ end
708
+ length, byte, dest_offset = stack.pop, stack.pop, stack.pop
709
+ if !length.is_a?(I32) || !byte.is_a?(I32) || !dest_offset.is_a?(I32)
710
+ raise EvalError, "invalid stack values"
711
+ end
712
+ memory = instance.store.memories[0] || raise("[BUG] no memory")
713
+ source = byte.value.chr * length.value
714
+ memory.data[dest_offset.value...(dest_offset.value+length.value)] = source
715
+
637
716
  else
638
717
  raise "TODO! unsupported #{insn.inspect}"
639
718
  end
@@ -905,9 +984,12 @@ module Wardite
905
984
  data_section = inst.data_section
906
985
  if data_section
907
986
  data_section.segments.each do |segment|
908
- memory = self.memories[segment.flags]
987
+ if segment.mode != :active
988
+ next
989
+ end
990
+ memory = self.memories[segment.mem_index]
909
991
  if !memory
910
- raise GenericError, "invalid memory index: #{segment.flags}"
992
+ raise GenericError, "invalid memory index: #{segment.mem_index}"
911
993
  end
912
994
 
913
995
  data_start = segment.offset
data/scripts/gen_conv.rb CHANGED
@@ -39,11 +39,18 @@ module GenConv
39
39
  code = DEF.dup
40
40
  method = op.to_s
41
41
  symbol = "#{to.to_s}_#{method}_#{from.to_sym}"
42
+ extra_kargs = ""
42
43
 
43
44
  if method == "extend"
44
45
  method = "extend_"
46
+ elsif method =~ /^extendN_(u|s)$/
47
+ suffix = $1
48
+ from_size = from.to_s.scan(/\d+/).join
49
+ symbol = "#{to.to_s}_extend_#{from_size}_#{suffix}"
50
+ extra_kargs = ", from: :#{from.to_s}"
45
51
  elsif method.end_with?("_s") or method.end_with?("_u")
46
- core, suffix = *(method.split("_")[0..1])
52
+ core = method.sub(/_(s|u)$/, "")
53
+ suffix = method.scan(/_(s|u)$/).join
47
54
  symbol = "#{to.to_s}_#{core}_#{from.to_sym}_#{suffix}"
48
55
  end
49
56
  # NOTE to is as namespace
@@ -52,11 +59,14 @@ module GenConv
52
59
  code.gsub!(/\$\{TO\}/, to.to_s)
53
60
  code.gsub!(/\$\{TO_CLASS\}/, to_class(to.to_sym))
54
61
  code.gsub!(/\$\{FROM_CLASS\}/, to_class(from.to_sym))
62
+ code.gsub!(/\$\{EXTRA_KARGS\}/, extra_kargs)
55
63
  return code
56
64
  end
57
65
 
58
66
  def self.to_class(typ)
59
67
  {
68
+ i8: "I32",
69
+ i16: "I32",
60
70
  i32: "I32",
61
71
  i64: "I64",
62
72
  f32: "F32",
@@ -69,7 +79,7 @@ module GenConv
69
79
  when :${SYMBOL}
70
80
  from = runtime.stack.pop
71
81
  raise EvalError, "maybe empty or invalid stack" if !from.is_a?(${FROM_CLASS})
72
- to = from.${METHOD}(to: :${TO})
82
+ to = from.${METHOD}(to: :${TO}${EXTRA_KARGS})
73
83
  raise EvalError, "failed to convert type" if !to.is_a?(${TO_CLASS})
74
84
  runtime.stack.push(to)
75
85
  RUBY
@@ -28,6 +28,8 @@ module Wardite
28
28
  SectionCode: Integer
29
29
 
30
30
  SectionData: Integer
31
+
32
+ SectionDataCount: Integer
31
33
  end
32
34
 
33
35
  include Const
@@ -7,9 +7,14 @@ module Wardite
7
7
  # @see https://pengowray.github.io/wasm-ops/
8
8
  SYMS: Array[Symbol]
9
9
 
10
+ FC_SYMS: Array[Symbol]
11
+
10
12
  # @rbs return: Hash[Integer, Symbol]
11
13
  def self.table: () -> Hash[Integer, Symbol]
12
14
 
15
+ # @rbs return: Hash[Integer, Symbol]
16
+ def self.fc_table: () -> Hash[Integer, Symbol]
17
+
13
18
  attr_accessor namespace: Symbol
14
19
 
15
20
  attr_accessor code: Symbol
@@ -26,6 +31,10 @@ module Wardite
26
31
  # @rbs return: [Symbol, Symbol]
27
32
  def self.to_sym: (String chr) -> [ Symbol, Symbol ]
28
33
 
34
+ # @rbs lower: Integer
35
+ # @rbs return: [Symbol, Symbol]
36
+ def self.resolve_fc_sym: (Integer lower) -> [ Symbol, Symbol ]
37
+
29
38
  # @rbs code: Symbol
30
39
  # @rbs return: Array[Symbol]
31
40
  def self.operand_of: (Symbol code) -> Array[Symbol]
@@ -4,11 +4,12 @@
4
4
  module Wardite
5
5
  module Leb128Helper
6
6
  # @rbs buf: File|StringIO
7
+ # @rbs max_level: Integer
7
8
  # @rbs return: Integer
8
- def fetch_uleb128: (File | StringIO buf) -> Integer
9
+ def fetch_uleb128: (File | StringIO buf, ?max_level: Integer) -> Integer
9
10
 
10
11
  # @rbs buf: File|StringIO
11
12
  # @rbs return: Integer
12
- def fetch_sleb128: (File | StringIO buf) -> Integer
13
+ def fetch_sleb128: (File | StringIO buf, ?max_level: untyped) -> Integer
13
14
  end
14
15
  end
@@ -103,7 +103,9 @@ module Wardite
103
103
 
104
104
  class DataSection < Section
105
105
  class Segment
106
- attr_accessor flags: Integer
106
+ attr_accessor mode: :active | :passive
107
+
108
+ attr_accessor mem_index: Integer
107
109
 
108
110
  attr_accessor offset: Integer
109
111
 
@@ -120,6 +122,14 @@ module Wardite
120
122
  def initialize: () -> void
121
123
  end
122
124
 
125
+ class DataCountSection < Section
126
+ attr_accessor count: Integer
127
+
128
+ # @rbs count: Integer
129
+ # @rbs return: void
130
+ def initialize: (Integer count) -> void
131
+ end
132
+
123
133
  class ExportSection < Section
124
134
  class ExportDesc
125
135
  attr_accessor name: String
@@ -206,9 +216,17 @@ module Wardite
206
216
  # @rbs return: Array[::Wardite::Op]
207
217
  def self.code_body: (StringIO buf) -> Array[::Wardite::Op]
208
218
 
219
+ # @rbs c: String
220
+ # @rbs buf: StringIO
221
+ # @rbs return: [Symbol, Symbol]
222
+ def self.resolve_code: (String c, StringIO buf) -> [ Symbol, Symbol ]
223
+
209
224
  # @rbs return: DataSection
210
225
  def self.data_section: () -> DataSection
211
226
 
227
+ # @rbs return: DataCountSection
228
+ def self.data_count_section: () -> DataCountSection
229
+
212
230
  # @rbs sbuf: StringIO
213
231
  # @rbs return: String
214
232
  def self.fetch_insn_while_end: (StringIO sbuf) -> String
@@ -36,7 +36,7 @@ module Wardite
36
36
  class I32
37
37
  include ValueHelper
38
38
 
39
- I32_MAX: untyped
39
+ I32_MAX: Integer
40
40
 
41
41
  # value should be stored as unsigned Integer, even in I32/I64
42
42
  # when we want to access signed value, it'd be done via #value_s
@@ -100,6 +100,19 @@ module Wardite
100
100
  # @rbs return: wasmValue
101
101
  def reinterpret: (to: Symbol) -> wasmValue
102
102
 
103
+ # @rbs from: Symbol
104
+ # @rbs to: Symbol
105
+ # @rbs return: wasmValue
106
+ def extendN_s: (from: Symbol, to: Symbol) -> wasmValue
107
+
108
+ # @rbs to: Symbol
109
+ # @rbs return: wasmValue
110
+ def trunc_sat_u: (to: Symbol) -> wasmValue
111
+
112
+ # @rbs to: Symbol
113
+ # @rbs return: wasmValue
114
+ def trunc_sat_s: (to: Symbol) -> wasmValue
115
+
103
116
  # I32#inspect shows signed value for convinience
104
117
  def inspect: () -> untyped
105
118
  end
@@ -107,7 +120,7 @@ module Wardite
107
120
  class I64
108
121
  include ValueHelper
109
122
 
110
- I64_MAX: untyped
123
+ I64_MAX: Integer
111
124
 
112
125
  attr_accessor value: Integer
113
126
 
@@ -168,6 +181,19 @@ module Wardite
168
181
  # @rbs return: wasmValue
169
182
  def reinterpret: (to: Symbol) -> wasmValue
170
183
 
184
+ # @rbs from: Symbol
185
+ # @rbs to: Symbol
186
+ # @rbs return: wasmValue
187
+ def extendN_s: (from: Symbol, to: Symbol) -> wasmValue
188
+
189
+ # @rbs to: Symbol
190
+ # @rbs return: wasmValue
191
+ def trunc_sat_u: (to: Symbol) -> wasmValue
192
+
193
+ # @rbs to: Symbol
194
+ # @rbs return: wasmValue
195
+ def trunc_sat_s: (to: Symbol) -> wasmValue
196
+
171
197
  # I64#inspect shows signed value
172
198
  def inspect: () -> untyped
173
199
  end
@@ -205,14 +231,18 @@ module Wardite
205
231
 
206
232
  # @todo need more testcase...
207
233
  # @see https://webassembly.github.io/spec/core/exec/numerics.html#xref-exec-numerics-op-trunc-s-mathrm-trunc-mathsf-s-m-n-z
234
+ # @see copy this impl to F64 when changed
208
235
  # @rbs to: Symbol
236
+ # @rbs saturating: bool
209
237
  # @rbs return: wasmValue
210
- def trunc_s: (to: Symbol) -> wasmValue
238
+ def trunc_s: (to: Symbol, ?saturating: bool) -> wasmValue
211
239
 
212
240
  # @see https://webassembly.github.io/spec/core/exec/numerics.html#xref-exec-numerics-op-trunc-u-mathrm-trunc-mathsf-u-m-n-z
241
+ # @see copy this impl to F64 when changed
213
242
  # @rbs to: Symbol
243
+ # @rbs sturating: bool
214
244
  # @rbs return: wasmValue
215
- def trunc_u: (to: Symbol) -> wasmValue
245
+ def trunc_u: (to: Symbol, ?saturating: untyped) -> wasmValue
216
246
 
217
247
  # @rbs to: Symbol
218
248
  # @rbs return: wasmValue
@@ -234,6 +264,19 @@ module Wardite
234
264
  # @rbs return: wasmValue
235
265
  def reinterpret: (to: Symbol) -> wasmValue
236
266
 
267
+ # @rbs from: Symbol
268
+ # @rbs to: Symbol
269
+ # @rbs return: wasmValue
270
+ def extendN_s: (from: Symbol, to: Symbol) -> wasmValue
271
+
272
+ # @rbs to: Symbol
273
+ # @rbs return: wasmValue
274
+ def trunc_sat_u: (to: Symbol) -> wasmValue
275
+
276
+ # @rbs to: Symbol
277
+ # @rbs return: wasmValue
278
+ def trunc_sat_s: (to: Symbol) -> wasmValue
279
+
237
280
  def inspect: () -> untyped
238
281
  end
239
282
 
@@ -270,13 +313,15 @@ module Wardite
270
313
 
271
314
  # @see the same as F32
272
315
  # @rbs to: Symbol
316
+ # @rbs saturating: bool
273
317
  # @rbs return: wasmValue
274
- def trunc_s: (to: Symbol) -> wasmValue
318
+ def trunc_s: (to: Symbol, ?saturating: bool) -> wasmValue
275
319
 
276
320
  # @see the same as F32
277
321
  # @rbs to: Symbol
322
+ # @rbs saturating: bool
278
323
  # @rbs return: wasmValue
279
- def trunc_u: (to: Symbol) -> wasmValue
324
+ def trunc_u: (to: Symbol, ?saturating: bool) -> wasmValue
280
325
 
281
326
  # @rbs to: Symbol
282
327
  # @rbs return: wasmValue
@@ -299,6 +344,19 @@ module Wardite
299
344
  # @rbs return: wasmValue
300
345
  def reinterpret: (to: Symbol) -> wasmValue
301
346
 
347
+ # @rbs from: Symbol
348
+ # @rbs to: Symbol
349
+ # @rbs return: wasmValue
350
+ def extendN_s: (from: Symbol, to: Symbol) -> wasmValue
351
+
352
+ # @rbs to: Symbol
353
+ # @rbs return: wasmValue
354
+ def trunc_sat_u: (to: Symbol) -> wasmValue
355
+
356
+ # @rbs to: Symbol
357
+ # @rbs return: wasmValue
358
+ def trunc_sat_s: (to: Symbol) -> wasmValue
359
+
302
360
  def inspect: () -> untyped
303
361
  end
304
362
  end
@@ -26,6 +26,9 @@ module Wardite
26
26
  # @rbs &blk: (Instance) -> void
27
27
  def initialize: (Hash[Symbol, Hash[Symbol, wasmCallable]] import_object) { (Instance) -> void } -> untyped
28
28
 
29
+ # @rbs return: void
30
+ def check_data_count: () -> void
31
+
29
32
  # @rbs return: ImportSection
30
33
  def import_section: () -> ImportSection
31
34
 
@@ -44,6 +47,9 @@ module Wardite
44
47
  # @rbs return: DataSection|nil
45
48
  def data_section: () -> (DataSection | nil)
46
49
 
50
+ # @rbs return: DataCountSection|nil
51
+ def data_count_section: () -> (DataCountSection | nil)
52
+
47
53
  # @rbs return: FunctionSection|nil
48
54
  def function_section: () -> (FunctionSection | nil)
49
55
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: wardite
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Uchio Kondo
@@ -37,6 +37,9 @@ files:
37
37
  - examples/local_set.wat
38
38
  - examples/loop.wat
39
39
  - examples/memory.wat
40
+ - examples/memory_init.wat
41
+ - examples/saturate.wat
42
+ - examples/saturate_u.wat
40
43
  - examples/start.wat
41
44
  - exe/wardite
42
45
  - lib/wardite.rb