Module: Dewasm::Pozeiden::WasmModule::Rt
Defined Under Namespace
Classes: LinkError, Memory, Table, Trap, WASI
Constant Summary
collapse
- M32 =
0xffff_ffff
- M64 =
0xffff_ffff_ffff_ffff
- F32_MAX =
Round a double to single precision.
MRI's pack("e") overflows straight to infinity for out-of-float-range doubles instead of rounding, so values below the rounding boundary (2^128 - 2^103) are mapped back to the largest finite f32.
3.4028234663852886e+38
- F32_OVERFLOW =
2.0**128 - 2.0**103
Class Method Summary
collapse
-
.check_import_kind(value, kind, mod, name) ⇒ Object
A present-but-wrong-kind import (e.g. a global where a func was declared) is a link error, distinct from a missing one (which still falls through to the caller's WASI/ENOSYS/raise fallback via ||).
-
.cvt_f32_i(v) ⇒ Object
Convert a (signed) Integer to f32 with correct rounding.
-
.cvt_f64_i(v) ⇒ Object
MRI's Integer#to_f rounds to nearest-even, which is exactly the wasm convert semantics.
-
.f32(x) ⇒ Object
-
.f32_abs(x) ⇒ Object
-
.f32_bits(x) ⇒ Object
-
.f32_demote(x) ⇒ Object
-
.f32_from_bits(b) ⇒ Object
MRI's pack("e")/unpack("e") canonicalize NaNs during the double<->float conversion, losing sign and payload.
-
.f32_neg(x) ⇒ Object
-
.f32_reinterpret_i32(x) ⇒ Object
-
.f64_abs(x) ⇒ Object
-
.f64_bits(x) ⇒ Object
-
.f64_copysign(a, b) ⇒ Object
-
.f64_from_bits(b) ⇒ Object
-
.f64_neg(x) ⇒ Object
-
.f64_promote(x) ⇒ Object
-
.f64_reinterpret_i64(x) ⇒ Object
-
.ffloor(x) ⇒ Object
-
.fsqrt(x) ⇒ Object
-
.i32_clz(x) ⇒ Object
-
.i32_div_s(a, b) ⇒ Object
-
.i32_div_u(a, b) ⇒ Object
-
.i32_extend16_s(x) ⇒ Object
-
.i32_extend8_s(x) ⇒ Object
-
.i32_reinterpret_f32(x) ⇒ Object
-
.i32_rem_u(a, b) ⇒ Object
-
.i32_rotl(a, b) ⇒ Object
-
.i32_trunc_sat_s(x) ⇒ Object
-
.i32_trunc_sat_u(x) ⇒ Object
-
.i64_clz(x) ⇒ Object
-
.i64_ctz(x) ⇒ Object
-
.i64_div_u(a, b) ⇒ Object
-
.i64_extend_i32_s(x) ⇒ Object
-
.i64_reinterpret_f64(x) ⇒ Object
-
.i64_rem_u(a, b) ⇒ Object
-
.i64_rotl(a, b) ⇒ Object
-
.m64(x) ⇒ Object
-
.quiet_nan(x) ⇒ Object
Quiet a NaN (set the quiet bit), preserving sign and payload.
-
.resolve_import(imports, mod, name) ⇒ Object
Resolve one imported function from the embedder's imports table.
-
.s32(x) ⇒ Object
-
.s64(x) ⇒ Object
-
.sext(x, bits, mask) ⇒ Object
-
.trap(message) ⇒ Object
-
.trunc_sat(x, min, max) ⇒ Object
Class Method Details
.check_import_kind(value, kind, mod, name) ⇒ Object
A present-but-wrong-kind import (e.g. a global where a func was declared) is a link error, distinct from a missing one (which still falls through to the caller's WASI/ENOSYS/raise fallback via ||).
Function values are bare Method/Proc objects; the runtime's own
Global/Table/Memory wrappers self-report via wasm_kind.
20
21
22
23
24
25
26
27
28
29
30
|
# File 'lib/dewasm/pozeiden/wasm_module.rb', line 20
def check_import_kind(value, kind, mod, name)
return value if value.nil?
ok =
if kind == :func
value.is_a?(Method) || value.is_a?(Proc)
else
value.respond_to?(:wasm_kind) && value.wasm_kind == kind
end
return value if ok
raise(LinkError, "incompatible import type for #{mod}.#{name}")
end
|
.cvt_f32_i(v) ⇒ Object
Convert a (signed) Integer to f32 with correct rounding.
Values beyond
2**53 are pre-rounded to odd so that the double->single step cannot double-round.
35
36
37
38
39
40
41
42
43
44
45
46
|
# File 'lib/dewasm/pozeiden/wasm_module.rb', line 35
def cvt_f32_i(v)
a = v.abs
if a < (1 << 53)
f32(v.to_f)
else
sh = a.bit_length - 53
hi = a >> sh
hi |= 1 if a != (hi << sh)
hi = -hi if v < 0
f32(hi.to_f * (2.0**sh))
end
end
|
.cvt_f64_i(v) ⇒ Object
MRI's Integer#to_f rounds to nearest-even, which is exactly the wasm convert semantics.
49
50
51
|
# File 'lib/dewasm/pozeiden/wasm_module.rb', line 49
def cvt_f64_i(v)
v.to_f
end
|
.f32(x) ⇒ Object
58
59
60
61
62
63
64
|
# File 'lib/dewasm/pozeiden/wasm_module.rb', line 58
def f32(x)
r = [x].pack("e").unpack1("e")
if r.infinite? && x.finite? && x.abs < F32_OVERFLOW
r = x < 0 ? -F32_MAX : F32_MAX
end
r
end
|
.f32_abs(x) ⇒ Object
66
|
# File 'lib/dewasm/pozeiden/wasm_module.rb', line 66
def f32_abs(x) = f32_from_bits(f32_bits(x) & 0x7fff_ffff)
|
.f32_bits(x) ⇒ Object
68
69
70
71
72
73
74
75
76
77
|
# File 'lib/dewasm/pozeiden/wasm_module.rb', line 68
def f32_bits(x)
if x.nan?
b = f64_bits(x)
payload = (b >> 29) & 0x7f_ffff
payload = 0x40_0000 if payload == 0
(((b >> 63) & 1) << 31) | 0x7f80_0000 | payload
else
[x].pack("e").unpack1("L<")
end
end
|
.f32_demote(x) ⇒ Object
79
80
81
|
# File 'lib/dewasm/pozeiden/wasm_module.rb', line 79
def f32_demote(x)
x.nan? ? f32_from_bits((f32_bits(x) & 0x8000_0000) | 0x7fc0_0000) : f32(x)
end
|
.f32_from_bits(b) ⇒ Object
MRI's pack("e")/unpack("e") canonicalize NaNs during the double<->float conversion, losing sign and payload.
Take a software path for NaNs.
85
86
87
88
89
90
91
|
# File 'lib/dewasm/pozeiden/wasm_module.rb', line 85
def f32_from_bits(b)
if (b & 0x7f80_0000) == 0x7f80_0000 && (b & 0x7f_ffff) != 0
f64_from_bits(((b >> 31) << 63) | 0x7ff0_0000_0000_0000 | ((b & 0x7f_ffff) << 29))
else
[b].pack("L<").unpack1("e")
end
end
|
.f32_neg(x) ⇒ Object
93
|
# File 'lib/dewasm/pozeiden/wasm_module.rb', line 93
def f32_neg(x) = f32_from_bits(f32_bits(x) ^ 0x8000_0000)
|
.f32_reinterpret_i32(x) ⇒ Object
95
|
# File 'lib/dewasm/pozeiden/wasm_module.rb', line 95
def f32_reinterpret_i32(x) = f32_from_bits(x)
|
.f64_abs(x) ⇒ Object
97
|
# File 'lib/dewasm/pozeiden/wasm_module.rb', line 97
def f64_abs(x) = f64_from_bits(f64_bits(x) & 0x7fff_ffff_ffff_ffff)
|
.f64_bits(x) ⇒ Object
99
100
101
|
# File 'lib/dewasm/pozeiden/wasm_module.rb', line 99
def f64_bits(x)
[x].pack("E").unpack1("Q<")
end
|
.f64_copysign(a, b) ⇒ Object
103
104
105
|
# File 'lib/dewasm/pozeiden/wasm_module.rb', line 103
def f64_copysign(a, b)
f64_from_bits((f64_bits(a) & 0x7fff_ffff_ffff_ffff) | (f64_bits(b) & 0x8000_0000_0000_0000))
end
|
.f64_from_bits(b) ⇒ Object
107
108
109
|
# File 'lib/dewasm/pozeiden/wasm_module.rb', line 107
def f64_from_bits(b)
[b].pack("Q<").unpack1("E")
end
|
.f64_neg(x) ⇒ Object
111
|
# File 'lib/dewasm/pozeiden/wasm_module.rb', line 111
def f64_neg(x) = f64_from_bits(f64_bits(x) ^ 0x8000_0000_0000_0000)
|
113
114
115
|
# File 'lib/dewasm/pozeiden/wasm_module.rb', line 113
def f64_promote(x)
x.nan? ? quiet_nan(x) : x
end
|
.f64_reinterpret_i64(x) ⇒ Object
117
|
# File 'lib/dewasm/pozeiden/wasm_module.rb', line 117
def f64_reinterpret_i64(x) = f64_from_bits(x)
|
.ffloor(x) ⇒ Object
119
120
121
122
123
124
|
# File 'lib/dewasm/pozeiden/wasm_module.rb', line 119
def ffloor(x)
return quiet_nan(x) if x.nan?
return x unless x.finite?
return x if x == 0.0 x.floor.to_f
end
|
.fsqrt(x) ⇒ Object
126
127
128
129
130
131
|
# File 'lib/dewasm/pozeiden/wasm_module.rb', line 126
def fsqrt(x)
return quiet_nan(x) if x.nan?
return Float::NAN if x < 0.0
return x if x == 0.0 Math.sqrt(x)
end
|
.i32_clz(x) ⇒ Object
133
134
135
|
# File 'lib/dewasm/pozeiden/wasm_module.rb', line 133
def i32_clz(x)
x == 0 ? 32 : 32 - x.bit_length
end
|
.i32_div_s(a, b) ⇒ Object
137
138
139
140
141
142
143
144
145
|
# File 'lib/dewasm/pozeiden/wasm_module.rb', line 137
def i32_div_s(a, b)
sa = s32(a)
sb = s32(b)
trap("integer divide by zero") if sb == 0
q = sa.abs / sb.abs
q = -q if (sa < 0) ^ (sb < 0)
trap("integer overflow") if q > 0x7fff_ffff
q & M32
end
|
.i32_div_u(a, b) ⇒ Object
147
148
149
150
|
# File 'lib/dewasm/pozeiden/wasm_module.rb', line 147
def i32_div_u(a, b)
trap("integer divide by zero") if b == 0
a / b
end
|
.i32_extend16_s(x) ⇒ Object
152
|
# File 'lib/dewasm/pozeiden/wasm_module.rb', line 152
def i32_extend16_s(x) = sext(x, 16, M32)
|
.i32_extend8_s(x) ⇒ Object
154
|
# File 'lib/dewasm/pozeiden/wasm_module.rb', line 154
def i32_extend8_s(x) = sext(x, 8, M32)
|
.i32_reinterpret_f32(x) ⇒ Object
156
|
# File 'lib/dewasm/pozeiden/wasm_module.rb', line 156
def i32_reinterpret_f32(x) = f32_bits(x)
|
.i32_rem_u(a, b) ⇒ Object
158
159
160
161
|
# File 'lib/dewasm/pozeiden/wasm_module.rb', line 158
def i32_rem_u(a, b)
trap("integer divide by zero") if b == 0
a % b
end
|
.i32_rotl(a, b) ⇒ Object
163
164
165
166
|
# File 'lib/dewasm/pozeiden/wasm_module.rb', line 163
def i32_rotl(a, b)
r = b & 31
((a << r) | (a >> (32 - r))) & M32
end
|
.i32_trunc_sat_s(x) ⇒ Object
168
|
# File 'lib/dewasm/pozeiden/wasm_module.rb', line 168
def i32_trunc_sat_s(x) = trunc_sat(x, -0x8000_0000, 0x7fff_ffff) & M32
|
.i32_trunc_sat_u(x) ⇒ Object
170
|
# File 'lib/dewasm/pozeiden/wasm_module.rb', line 170
def i32_trunc_sat_u(x) = trunc_sat(x, 0, M32)
|
.i64_clz(x) ⇒ Object
172
173
174
|
# File 'lib/dewasm/pozeiden/wasm_module.rb', line 172
def i64_clz(x)
x == 0 ? 64 : 64 - x.bit_length
end
|
.i64_ctz(x) ⇒ Object
176
177
178
|
# File 'lib/dewasm/pozeiden/wasm_module.rb', line 176
def i64_ctz(x)
x == 0 ? 64 : (x & -x).bit_length - 1
end
|
.i64_div_u(a, b) ⇒ Object
180
181
182
183
|
# File 'lib/dewasm/pozeiden/wasm_module.rb', line 180
def i64_div_u(a, b)
trap("integer divide by zero") if b == 0
a / b
end
|
.i64_extend_i32_s(x) ⇒ Object
185
|
# File 'lib/dewasm/pozeiden/wasm_module.rb', line 185
def i64_extend_i32_s(x) = m64(s32(x))
|
.i64_reinterpret_f64(x) ⇒ Object
187
|
# File 'lib/dewasm/pozeiden/wasm_module.rb', line 187
def i64_reinterpret_f64(x) = f64_bits(x)
|
.i64_rem_u(a, b) ⇒ Object
189
190
191
192
|
# File 'lib/dewasm/pozeiden/wasm_module.rb', line 189
def i64_rem_u(a, b)
trap("integer divide by zero") if b == 0
a % b
end
|
.i64_rotl(a, b) ⇒ Object
194
195
196
197
|
# File 'lib/dewasm/pozeiden/wasm_module.rb', line 194
def i64_rotl(a, b)
r = b & 63
m64((a << r) | (a >> (64 - r)))
end
|
.m64(x) ⇒ Object
203
|
# File 'lib/dewasm/pozeiden/wasm_module.rb', line 203
def m64(x) = (x >= 0 && x <= M64) ? x : (x & M64)
|
.quiet_nan(x) ⇒ Object
Quiet a NaN (set the quiet bit), preserving sign and payload.
The f64 quiet bit maps to the f32 quiet bit for NaNs that came from f32.
207
208
209
|
# File 'lib/dewasm/pozeiden/wasm_module.rb', line 207
def quiet_nan(x)
f64_from_bits(f64_bits(x) | 0x0008_0000_0000_0000)
end
|
.resolve_import(imports, mod, name) ⇒ Object
Resolve one imported function from the embedder's imports table.
The value under a module name is either a Hash (name -> callable) or a provider object responding to import(name); providers may also define attach(instance), which generated code calls once the instance is fully constructed.
213
214
215
216
217
|
# File 'lib/dewasm/pozeiden/wasm_module.rb', line 213
def resolve_import(imports, mod, name)
source = imports[mod]
return nil if source.nil?
source.respond_to?(:import) ? source.import(name) : source[name]
end
|
.s32(x) ⇒ Object
219
220
221
|
# File 'lib/dewasm/pozeiden/wasm_module.rb', line 219
def s32(x)
x >= 0x8000_0000 ? x - 0x1_0000_0000 : x
end
|
.s64(x) ⇒ Object
223
224
225
|
# File 'lib/dewasm/pozeiden/wasm_module.rb', line 223
def s64(x)
x >= 0x8000_0000_0000_0000 ? x - 0x1_0000_0000_0000_0000 : x
end
|
.sext(x, bits, mask) ⇒ Object
227
228
229
230
|
# File 'lib/dewasm/pozeiden/wasm_module.rb', line 227
def sext(x, bits, mask)
half = 1 << (bits - 1)
(((x & ((1 << bits) - 1)) ^ half) - half) & mask
end
|
.trap(message) ⇒ Object
234
235
236
|
# File 'lib/dewasm/pozeiden/wasm_module.rb', line 234
def trap(message)
raise Trap, message
end
|
.trunc_sat(x, min, max) ⇒ Object
238
239
240
241
242
|
# File 'lib/dewasm/pozeiden/wasm_module.rb', line 238
def trunc_sat(x, min, max)
return 0 if x.nan?
t = x.infinite? ? (x > 0 ? max : min) : x.truncate
t.clamp(min, max)
end
|