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 +4 -4
- data/README.md +15 -0
- data/Rakefile +6 -0
- data/examples/memory_init.wat +18 -0
- data/examples/saturate.wat +8 -0
- data/examples/saturate_u.wat +9 -0
- data/lib/wardite/const.rb +13 -12
- data/lib/wardite/convert.generated.rb +104 -0
- data/lib/wardite/instruction.rb +56 -3
- data/lib/wardite/leb128.rb +5 -4
- data/lib/wardite/load.rb +94 -21
- data/lib/wardite/value.rb +202 -28
- data/lib/wardite/version.rb +1 -1
- data/lib/wardite.rb +85 -3
- data/scripts/gen_conv.rb +12 -2
- data/sig/generated/wardite/const.rbs +2 -0
- data/sig/generated/wardite/instruction.rbs +9 -0
- data/sig/generated/wardite/leb128.rbs +3 -2
- data/sig/generated/wardite/load.rbs +19 -1
- data/sig/generated/wardite/value.rbs +64 -6
- data/sig/generated/wardite.rbs +6 -0
- metadata +4 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '02079b17ada50d21f00ea34c1830452eea21ff12a2fb6e9c5903d07cdca53d3a'
|
4
|
+
data.tar.gz: 9ab24caf2cc630593ce32ab652c8044a621f67ddce1cb70f75a1cd9e767b13e2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
+
)
|
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
|
7
|
-
SectionType
|
8
|
-
SectionImport
|
9
|
-
SectionFunction
|
10
|
-
SectionTable
|
11
|
-
SectionMemory
|
12
|
-
SectionGlobal
|
13
|
-
SectionExport
|
14
|
-
SectionStart
|
15
|
-
SectionElement
|
16
|
-
SectionCode
|
17
|
-
SectionData
|
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)
|
data/lib/wardite/instruction.rb
CHANGED
@@ -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
|
-
@@
|
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, :
|
150
|
+
[:u32, :u32]
|
98
151
|
when :br_table
|
99
152
|
[:u32_vec, :u32]
|
100
153
|
when :i32_const
|
data/lib/wardite/leb128.rb
CHANGED
@@ -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 >
|
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 >
|
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 :
|
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 =
|
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
|
-
|
665
|
-
|
666
|
-
|
667
|
-
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
|
678
|
-
|
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
|
-
|
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
|
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
|
-
|
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
|
-
|
408
|
-
if
|
409
|
-
|
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
|
-
|
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
|
-
|
418
|
-
if
|
419
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
551
|
-
if
|
552
|
-
|
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
|
-
|
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
|
-
|
561
|
-
if
|
562
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
data/lib/wardite/version.rb
CHANGED
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
|
-
|
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.
|
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
|
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
|
@@ -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
|
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:
|
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:
|
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
|
data/sig/generated/wardite.rbs
CHANGED
@@ -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.
|
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
|