wardite 0.1.2 → 0.2.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: d27a05a105bd446883460d42c05cbec8502360dc686098368d59b1ae5e6e3e91
4
- data.tar.gz: d17f48eade8ac57845bf250583db7eb33dd9a418c315ba1083a7e0f598505298
3
+ metadata.gz: cefed459056cdf59c5c8823b1b4ef8ff53c84fd09a9f73883aaa291561ba4e00
4
+ data.tar.gz: b4ac97c31de3cc655aaf68d9c2097d1cb73ff67a184fd0c365d99b36371f1f93
5
5
  SHA512:
6
- metadata.gz: 21de2c67fd7aaaf04d55f028d304588a4f5c7f92b21ab4b7cb40dd7882103067db85401f41efc53b491996a82f109a9b11c05b0efa62e9622ad3971f6e254342
7
- data.tar.gz: 90542ce81cf6bf537eac6ddab087abab10842bfb24f153ba88865a7d2b5a0417c3e3fbab116e5ad2bedabc3d665810f34c0c8568a2baa2adbbdda89c681df076
6
+ metadata.gz: b3987aab13095263b109e7c907bee2640c3b9d2a5777b1b81812f692508de160d7fdd9f28e8c19c25d53445905e3b7b65379e0443f36dd56232e5c61b7d054bc
7
+ data.tar.gz: ca3e1e1b0390869ce69ddc880e574ff3fb6c75c7def7538ad628c121ea5c12e1c860dbadc960cbaba48841f6ab5be3f1eeb117e0822dd9488271eab0eb1745d9
data/Rakefile CHANGED
@@ -15,5 +15,183 @@ task :check do
15
15
  sh "bundle exec steep check"
16
16
  end
17
17
 
18
+ desc "Compile wat"
19
+ task :wasm, [:name] do |t, args|
20
+ Dir.chdir "examples" do
21
+ sh "wat2wasm #{args.name}.wat"
22
+ end
23
+ end
24
+
25
+ desc "Generate codes"
26
+ task :generate do
27
+ require_relative "scripts/gen_alu"
28
+ require_relative "scripts/gen_conv"
29
+ libdir = File.expand_path("../lib", __FILE__)
30
+
31
+ GenAlu.execute(libdir + "/wardite/alu_i32.generated.rb", prefix: "i32", defined_ops: [
32
+ :load,
33
+ :load8_s,
34
+ :load8_u,
35
+ :load16_s,
36
+ :load16_u,
37
+ :store,
38
+ :store8,
39
+ :store16,
40
+ :const,
41
+ :eqz,
42
+ :eq,
43
+ :ne,
44
+ :lts,
45
+ :ltu,
46
+ :gts,
47
+ :gtu,
48
+ :les,
49
+ :leu,
50
+ :ges,
51
+ :geu,
52
+ :clz,
53
+ :ctz,
54
+ :popcnt,
55
+ :add,
56
+ :sub,
57
+ :mul,
58
+ :div_s,
59
+ :div_u,
60
+ :rem_s,
61
+ :rem_u,
62
+ :and,
63
+ :or,
64
+ :xor,
65
+ :shl,
66
+ :shr_s,
67
+ :shr_u,
68
+ :rotl,
69
+ :rotr,
70
+ ])
71
+ GenAlu.execute(libdir + "/wardite/alu_i64.generated.rb", prefix: "i64", defined_ops: [
72
+ :load,
73
+ :load8_s,
74
+ :load8_u,
75
+ :load16_s,
76
+ :load16_u,
77
+ :load32_s,
78
+ :load32_u,
79
+ :store,
80
+ :store8,
81
+ :store16,
82
+ :store32,
83
+ :const,
84
+ :eqz,
85
+ :eq,
86
+ :ne,
87
+ :lts,
88
+ :ltu,
89
+ :gts,
90
+ :gtu,
91
+ :les,
92
+ :leu,
93
+ :ges,
94
+ :geu,
95
+ :clz,
96
+ :ctz,
97
+ :popcnt,
98
+ :add,
99
+ :sub,
100
+ :mul,
101
+ :div_s,
102
+ :div_u,
103
+ :rem_s,
104
+ :rem_u,
105
+ :and,
106
+ :or,
107
+ :xor,
108
+ :shl,
109
+ :shr_s,
110
+ :shr_u,
111
+ :rotl,
112
+ :rotr,
113
+ ])
114
+ GenAlu.execute(libdir + "/wardite/alu_f32.generated.rb", prefix: "f32", defined_ops: [
115
+ :load,
116
+ :store,
117
+ :const__f,
118
+ :eqz,
119
+ :eq,
120
+ :ne,
121
+ :lt,
122
+ :gt,
123
+ :le,
124
+ :ge,
125
+ :abs,
126
+ :neg,
127
+ :ceil,
128
+ :floor,
129
+ :trunc,
130
+ :nearest,
131
+ :sqrt,
132
+ :add,
133
+ :sub,
134
+ :mul,
135
+ :div,
136
+ :min,
137
+ :max,
138
+ :copysign,
139
+ ])
140
+ GenAlu.execute(libdir + "/wardite/alu_f64.generated.rb", prefix: "f64", defined_ops: [
141
+ :load,
142
+ :store,
143
+ :const__f,
144
+ :eqz,
145
+ :eq,
146
+ :ne,
147
+ :lt,
148
+ :gt,
149
+ :le,
150
+ :ge,
151
+ :abs,
152
+ :neg,
153
+ :ceil,
154
+ :floor,
155
+ :trunc,
156
+ :nearest,
157
+ :sqrt,
158
+ :add,
159
+ :sub,
160
+ :mul,
161
+ :div,
162
+ :min,
163
+ :max,
164
+ :copysign,
165
+ ])
166
+
167
+ GenConv.execute(libdir + "/wardite/convert.generated.rb", defined_ops: {
168
+ i32: {
169
+ wrap: [:i64],
170
+ trunc_s: [:f32, :f64],
171
+ trunc_u: [:f32, :f64],
172
+ reinterpret: [:f32],
173
+ },
174
+ i64: {
175
+ extend_s: [:i32, :i64],
176
+ extend_u: [:i32, :i64],
177
+ trunc_s: [:f32, :f64],
178
+ trunc_u: [:f32, :f64],
179
+ reinterpret: [:f64],
180
+ },
181
+ f32: {
182
+ convert_s: [:i32, :i64],
183
+ convert_u: [:i32, :i64],
184
+ demote: [:f64],
185
+ reinterpret: [:i32],
186
+ },
187
+ f64: {
188
+ convert_s: [:i32, :i64],
189
+ convert_u: [:i32, :i64],
190
+ promote: [:f32],
191
+ reinterpret: [:i64],
192
+ },
193
+ })
194
+ end
195
+
18
196
  task default: %i[test check]
19
197
 
data/Steepfile CHANGED
@@ -3,6 +3,7 @@ target :lib do
3
3
  signature "sig"
4
4
  check "lib"
5
5
 
6
+ library "pp"
6
7
  # configure_code_diagnostics(Steep::Diagnostic::Ruby.strict)
7
8
  end
8
9
 
@@ -0,0 +1,12 @@
1
+ (module
2
+ (func $test_const (result f32)
3
+ (i32.const 42)
4
+ (drop)
5
+ (i64.const 42)
6
+ (drop)
7
+ (f64.const 3.14)
8
+ (drop)
9
+ (f32.const 3.14)
10
+ )
11
+ (export "test_const" (func $test_const))
12
+ )
@@ -0,0 +1,250 @@
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.f32_eval_insn(runtime, frame, insn)
11
+ case insn.code
12
+
13
+ when :f32_load
14
+ _align = insn.operand[0] # TODO: alignment support?
15
+ offset = insn.operand[1]
16
+ raise EvalError, "[BUG] invalid type of operand" if !offset.is_a?(Integer)
17
+
18
+ addr = runtime.stack.pop
19
+ if !addr.is_a?(I32)
20
+ raise EvalError, "maybe stack too short"
21
+ end
22
+
23
+ at = addr.value + offset
24
+ data_end = at + F32.new.memsize / 8
25
+ memory = runtime.instance.store.memories[0] || raise("[BUG] no memory")
26
+ buf = memory.data[at...data_end]
27
+ if !buf
28
+ raise EvalError, "invalid memory range"
29
+ end
30
+ runtime.stack.push(F32.from_bytes(buf))
31
+
32
+
33
+ when :f32_store
34
+ _align = insn.operand[0] # TODO: alignment support?
35
+ offset = insn.operand[1]
36
+ raise EvalError, "[BUG] invalid type of operand" if !offset.is_a?(Integer)
37
+
38
+ value = runtime.stack.pop
39
+ addr = runtime.stack.pop
40
+ if !value.is_a?(F32) || !addr.is_a?(I32)
41
+ raise EvalError, "maybe stack too short"
42
+ end
43
+
44
+ at = addr.value + offset
45
+ data_end = at + value.packed.size
46
+ memory = runtime.instance.store.memories[0] || raise("[BUG] no memory")
47
+ memory.data[at...data_end] = value.packed
48
+
49
+
50
+ when :f32_const
51
+ const = insn.operand[0]
52
+ if !const.is_a?(Float)
53
+ raise EvalError, "invalid type of operand"
54
+ end
55
+ runtime.stack.push(F32(const))
56
+
57
+
58
+ when :f32_eqz
59
+ target = runtime.stack.pop
60
+ if !target.is_a?(F32)
61
+ raise EvalError, "maybe empty or invalid stack"
62
+ end
63
+ value = target.value.zero? ? 1 : 0
64
+ runtime.stack.push(I32(value))
65
+
66
+
67
+ when :f32_eq
68
+ right, left = runtime.stack.pop, runtime.stack.pop
69
+ if !right.is_a?(F32) || !left.is_a?(F32)
70
+ raise EvalError, "maybe empty or invalid stack"
71
+ end
72
+ value = (left.value == right.value) ? 1 : 0
73
+ runtime.stack.push(I32(value))
74
+
75
+
76
+ when :f32_ne
77
+ right, left = runtime.stack.pop, runtime.stack.pop
78
+ if !right.is_a?(F32) || !left.is_a?(F32)
79
+ raise EvalError, "maybe empty or invalid stack"
80
+ end
81
+ value = (left.value != right.value) ? 1 : 0
82
+ runtime.stack.push(I32(value))
83
+
84
+
85
+ when :f32_lt
86
+ right, left = runtime.stack.pop, runtime.stack.pop
87
+ if !right.is_a?(F32) || !left.is_a?(F32)
88
+ raise EvalError, "maybe empty or invalid stack"
89
+ end
90
+ value = (left.value < right.value) ? 1 : 0
91
+ runtime.stack.push(I32(value))
92
+
93
+
94
+ when :f32_gt
95
+ right, left = runtime.stack.pop, runtime.stack.pop
96
+ if !right.is_a?(F32) || !left.is_a?(F32)
97
+ raise EvalError, "maybe empty or invalid stack"
98
+ end
99
+ value = (left.value > right.value) ? 1 : 0
100
+ runtime.stack.push(I32(value))
101
+
102
+
103
+ when :f32_le
104
+ right, left = runtime.stack.pop, runtime.stack.pop
105
+ if !right.is_a?(F32) || !left.is_a?(F32)
106
+ raise EvalError, "maybe empty or invalid stack"
107
+ end
108
+ value = (left.value <= right.value) ? 1 : 0
109
+ runtime.stack.push(I32(value))
110
+
111
+
112
+ when :f32_ge
113
+ right, left = runtime.stack.pop, runtime.stack.pop
114
+ if !right.is_a?(F32) || !left.is_a?(F32)
115
+ raise EvalError, "maybe empty or invalid stack"
116
+ end
117
+ value = (left.value >= right.value) ? 1 : 0
118
+ runtime.stack.push(I32(value))
119
+
120
+
121
+ when :f32_abs
122
+ x = runtime.stack.pop
123
+ if !x.is_a?(F32)
124
+ raise EvalError, "maybe empty or invalid stack"
125
+ end
126
+ runtime.stack.push(F32(x.value.abs))
127
+
128
+
129
+ when :f32_neg
130
+ x = runtime.stack.pop
131
+ if !x.is_a?(F32)
132
+ raise EvalError, "maybe empty or invalid stack"
133
+ end
134
+ runtime.stack.push(F32(-(x.value)))
135
+
136
+
137
+ when :f32_ceil
138
+ x = runtime.stack.pop
139
+ if !x.is_a?(F32)
140
+ raise EvalError, "maybe empty or invalid stack"
141
+ end
142
+ runtime.stack.push(F32(x.value.ceil.to_f))
143
+
144
+
145
+ when :f32_floor
146
+ x = runtime.stack.pop
147
+ if !x.is_a?(F32)
148
+ raise EvalError, "maybe empty or invalid stack"
149
+ end
150
+ runtime.stack.push(F32(x.value.floor.to_f))
151
+
152
+
153
+ when :f32_trunc
154
+ x = runtime.stack.pop
155
+ if !x.is_a?(F32)
156
+ raise EvalError, "maybe empty or invalid stack"
157
+ end
158
+ runtime.stack.push(F32(x.value.to_i.to_f))
159
+
160
+
161
+ when :f32_nearest
162
+ x = runtime.stack.pop
163
+ if !x.is_a?(F32)
164
+ raise EvalError, "maybe empty or invalid stack"
165
+ end
166
+ runtime.stack.push(F32(x.value.round.to_f))
167
+
168
+
169
+ when :f32_sqrt
170
+ x = runtime.stack.pop
171
+ if !x.is_a?(F32)
172
+ raise EvalError, "maybe empty or invalid stack"
173
+ end
174
+ runtime.stack.push(F32(x.value ** 0.5))
175
+
176
+
177
+ when :f32_add
178
+ right, left = runtime.stack.pop, runtime.stack.pop
179
+ if !right.is_a?(F32) || !left.is_a?(F32)
180
+ raise EvalError, "maybe empty or invalid stack"
181
+ end
182
+ runtime.stack.push(F32(left.value + right.value))
183
+
184
+
185
+ when :f32_sub
186
+ right, left = runtime.stack.pop, runtime.stack.pop
187
+ if !right.is_a?(F32) || !left.is_a?(F32)
188
+ raise EvalError, "maybe empty or invalid stack"
189
+ end
190
+ runtime.stack.push(F32(left.value - right.value))
191
+
192
+
193
+ when :f32_mul
194
+ right, left = runtime.stack.pop, runtime.stack.pop
195
+ if !right.is_a?(F32) || !left.is_a?(F32)
196
+ raise EvalError, "maybe empty or invalid stack"
197
+ end
198
+ runtime.stack.push(F32(left.value * right.value))
199
+
200
+
201
+ when :f32_div
202
+ right, left = runtime.stack.pop, runtime.stack.pop
203
+ if !right.is_a?(F32) || !left.is_a?(F32)
204
+ raise EvalError, "maybe empty or invalid stack"
205
+ end
206
+ runtime.stack.push(F32(left.value / right.value))
207
+
208
+
209
+ when :f32_min
210
+ right, left = runtime.stack.pop, runtime.stack.pop
211
+ if !right.is_a?(F32) || !left.is_a?(F32)
212
+ raise EvalError, "maybe empty or invalid stack"
213
+ end
214
+ if right.value.nan? || left.value.nan?
215
+ runtime.stack.push(F32(Float::NAN))
216
+ return
217
+ end
218
+ runtime.stack.push(F32([left.value, right.value].min))
219
+
220
+
221
+ when :f32_max
222
+ right, left = runtime.stack.pop, runtime.stack.pop
223
+ if !right.is_a?(F32) || !left.is_a?(F32)
224
+ raise EvalError, "maybe empty or invalid stack"
225
+ end
226
+ if right.value.nan? || left.value.nan?
227
+ runtime.stack.push(F32(Float::NAN))
228
+ return
229
+ end
230
+ runtime.stack.push(F32([left.value, right.value].max))
231
+
232
+
233
+ when :f32_copysign
234
+ right, left = runtime.stack.pop, runtime.stack.pop
235
+ if !right.is_a?(F32) || !left.is_a?(F32)
236
+ raise EvalError, "maybe empty or invalid stack"
237
+ end
238
+ if left.sign == right.sign
239
+ runtime.stack.push(F32(left.value))
240
+ else
241
+ runtime.stack.push(F32(-left.value))
242
+ end
243
+
244
+
245
+ else
246
+ raise "Unknown opcode for namespace #{insn.namespace}: #{insn.code}"
247
+ end
248
+ end
249
+ end
250
+ end
@@ -0,0 +1,250 @@
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.f64_eval_insn(runtime, frame, insn)
11
+ case insn.code
12
+
13
+ when :f64_load
14
+ _align = insn.operand[0] # TODO: alignment support?
15
+ offset = insn.operand[1]
16
+ raise EvalError, "[BUG] invalid type of operand" if !offset.is_a?(Integer)
17
+
18
+ addr = runtime.stack.pop
19
+ if !addr.is_a?(I32)
20
+ raise EvalError, "maybe stack too short"
21
+ end
22
+
23
+ at = addr.value + offset
24
+ data_end = at + F64.new.memsize / 8
25
+ memory = runtime.instance.store.memories[0] || raise("[BUG] no memory")
26
+ buf = memory.data[at...data_end]
27
+ if !buf
28
+ raise EvalError, "invalid memory range"
29
+ end
30
+ runtime.stack.push(F64.from_bytes(buf))
31
+
32
+
33
+ when :f64_store
34
+ _align = insn.operand[0] # TODO: alignment support?
35
+ offset = insn.operand[1]
36
+ raise EvalError, "[BUG] invalid type of operand" if !offset.is_a?(Integer)
37
+
38
+ value = runtime.stack.pop
39
+ addr = runtime.stack.pop
40
+ if !value.is_a?(F64) || !addr.is_a?(I32)
41
+ raise EvalError, "maybe stack too short"
42
+ end
43
+
44
+ at = addr.value + offset
45
+ data_end = at + value.packed.size
46
+ memory = runtime.instance.store.memories[0] || raise("[BUG] no memory")
47
+ memory.data[at...data_end] = value.packed
48
+
49
+
50
+ when :f64_const
51
+ const = insn.operand[0]
52
+ if !const.is_a?(Float)
53
+ raise EvalError, "invalid type of operand"
54
+ end
55
+ runtime.stack.push(F64(const))
56
+
57
+
58
+ when :f64_eqz
59
+ target = runtime.stack.pop
60
+ if !target.is_a?(F64)
61
+ raise EvalError, "maybe empty or invalid stack"
62
+ end
63
+ value = target.value.zero? ? 1 : 0
64
+ runtime.stack.push(I32(value))
65
+
66
+
67
+ when :f64_eq
68
+ right, left = runtime.stack.pop, runtime.stack.pop
69
+ if !right.is_a?(F64) || !left.is_a?(F64)
70
+ raise EvalError, "maybe empty or invalid stack"
71
+ end
72
+ value = (left.value == right.value) ? 1 : 0
73
+ runtime.stack.push(I32(value))
74
+
75
+
76
+ when :f64_ne
77
+ right, left = runtime.stack.pop, runtime.stack.pop
78
+ if !right.is_a?(F64) || !left.is_a?(F64)
79
+ raise EvalError, "maybe empty or invalid stack"
80
+ end
81
+ value = (left.value != right.value) ? 1 : 0
82
+ runtime.stack.push(I32(value))
83
+
84
+
85
+ when :f64_lt
86
+ right, left = runtime.stack.pop, runtime.stack.pop
87
+ if !right.is_a?(F64) || !left.is_a?(F64)
88
+ raise EvalError, "maybe empty or invalid stack"
89
+ end
90
+ value = (left.value < right.value) ? 1 : 0
91
+ runtime.stack.push(I32(value))
92
+
93
+
94
+ when :f64_gt
95
+ right, left = runtime.stack.pop, runtime.stack.pop
96
+ if !right.is_a?(F64) || !left.is_a?(F64)
97
+ raise EvalError, "maybe empty or invalid stack"
98
+ end
99
+ value = (left.value > right.value) ? 1 : 0
100
+ runtime.stack.push(I32(value))
101
+
102
+
103
+ when :f64_le
104
+ right, left = runtime.stack.pop, runtime.stack.pop
105
+ if !right.is_a?(F64) || !left.is_a?(F64)
106
+ raise EvalError, "maybe empty or invalid stack"
107
+ end
108
+ value = (left.value <= right.value) ? 1 : 0
109
+ runtime.stack.push(I32(value))
110
+
111
+
112
+ when :f64_ge
113
+ right, left = runtime.stack.pop, runtime.stack.pop
114
+ if !right.is_a?(F64) || !left.is_a?(F64)
115
+ raise EvalError, "maybe empty or invalid stack"
116
+ end
117
+ value = (left.value >= right.value) ? 1 : 0
118
+ runtime.stack.push(I32(value))
119
+
120
+
121
+ when :f64_abs
122
+ x = runtime.stack.pop
123
+ if !x.is_a?(F64)
124
+ raise EvalError, "maybe empty or invalid stack"
125
+ end
126
+ runtime.stack.push(F64(x.value.abs))
127
+
128
+
129
+ when :f64_neg
130
+ x = runtime.stack.pop
131
+ if !x.is_a?(F64)
132
+ raise EvalError, "maybe empty or invalid stack"
133
+ end
134
+ runtime.stack.push(F64(-(x.value)))
135
+
136
+
137
+ when :f64_ceil
138
+ x = runtime.stack.pop
139
+ if !x.is_a?(F64)
140
+ raise EvalError, "maybe empty or invalid stack"
141
+ end
142
+ runtime.stack.push(F64(x.value.ceil.to_f))
143
+
144
+
145
+ when :f64_floor
146
+ x = runtime.stack.pop
147
+ if !x.is_a?(F64)
148
+ raise EvalError, "maybe empty or invalid stack"
149
+ end
150
+ runtime.stack.push(F64(x.value.floor.to_f))
151
+
152
+
153
+ when :f64_trunc
154
+ x = runtime.stack.pop
155
+ if !x.is_a?(F64)
156
+ raise EvalError, "maybe empty or invalid stack"
157
+ end
158
+ runtime.stack.push(F64(x.value.to_i.to_f))
159
+
160
+
161
+ when :f64_nearest
162
+ x = runtime.stack.pop
163
+ if !x.is_a?(F64)
164
+ raise EvalError, "maybe empty or invalid stack"
165
+ end
166
+ runtime.stack.push(F64(x.value.round.to_f))
167
+
168
+
169
+ when :f64_sqrt
170
+ x = runtime.stack.pop
171
+ if !x.is_a?(F64)
172
+ raise EvalError, "maybe empty or invalid stack"
173
+ end
174
+ runtime.stack.push(F64(x.value ** 0.5))
175
+
176
+
177
+ when :f64_add
178
+ right, left = runtime.stack.pop, runtime.stack.pop
179
+ if !right.is_a?(F64) || !left.is_a?(F64)
180
+ raise EvalError, "maybe empty or invalid stack"
181
+ end
182
+ runtime.stack.push(F64(left.value + right.value))
183
+
184
+
185
+ when :f64_sub
186
+ right, left = runtime.stack.pop, runtime.stack.pop
187
+ if !right.is_a?(F64) || !left.is_a?(F64)
188
+ raise EvalError, "maybe empty or invalid stack"
189
+ end
190
+ runtime.stack.push(F64(left.value - right.value))
191
+
192
+
193
+ when :f64_mul
194
+ right, left = runtime.stack.pop, runtime.stack.pop
195
+ if !right.is_a?(F64) || !left.is_a?(F64)
196
+ raise EvalError, "maybe empty or invalid stack"
197
+ end
198
+ runtime.stack.push(F64(left.value * right.value))
199
+
200
+
201
+ when :f64_div
202
+ right, left = runtime.stack.pop, runtime.stack.pop
203
+ if !right.is_a?(F64) || !left.is_a?(F64)
204
+ raise EvalError, "maybe empty or invalid stack"
205
+ end
206
+ runtime.stack.push(F64(left.value / right.value))
207
+
208
+
209
+ when :f64_min
210
+ right, left = runtime.stack.pop, runtime.stack.pop
211
+ if !right.is_a?(F64) || !left.is_a?(F64)
212
+ raise EvalError, "maybe empty or invalid stack"
213
+ end
214
+ if right.value.nan? || left.value.nan?
215
+ runtime.stack.push(F64(Float::NAN))
216
+ return
217
+ end
218
+ runtime.stack.push(F64([left.value, right.value].min))
219
+
220
+
221
+ when :f64_max
222
+ right, left = runtime.stack.pop, runtime.stack.pop
223
+ if !right.is_a?(F64) || !left.is_a?(F64)
224
+ raise EvalError, "maybe empty or invalid stack"
225
+ end
226
+ if right.value.nan? || left.value.nan?
227
+ runtime.stack.push(F64(Float::NAN))
228
+ return
229
+ end
230
+ runtime.stack.push(F64([left.value, right.value].max))
231
+
232
+
233
+ when :f64_copysign
234
+ right, left = runtime.stack.pop, runtime.stack.pop
235
+ if !right.is_a?(F64) || !left.is_a?(F64)
236
+ raise EvalError, "maybe empty or invalid stack"
237
+ end
238
+ if left.sign == right.sign
239
+ runtime.stack.push(F64(left.value))
240
+ else
241
+ runtime.stack.push(F64(-left.value))
242
+ end
243
+
244
+
245
+ else
246
+ raise "Unknown opcode for namespace #{insn.namespace}: #{insn.code}"
247
+ end
248
+ end
249
+ end
250
+ end