Module: Dewasm::Pozeiden::WasmModule::Rt

Included in:
Dewasm::Pozeiden::WasmModule
Defined in:
lib/dewasm/pozeiden/wasm_module.rb

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

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.

Raises:



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)

.f64_promote(x) ⇒ Object



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 # preserves -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 # preserves -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

Raises:



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