watr 4.5.0 → 4.5.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/watr.js +139 -100
- package/dist/watr.min.js +6 -6
- package/package.json +1 -1
- package/readme.md +1 -1
- package/src/compile.js +9 -2
- package/src/const.js +2 -2
- package/src/encode.js +33 -12
- package/src/optimize.js +131 -87
- package/types/src/const.d.ts +2 -0
- package/types/src/encode.d.ts.map +1 -1
- package/types/src/optimize.d.ts +13 -0
- package/types/src/optimize.d.ts.map +1 -1
package/src/compile.js
CHANGED
|
@@ -308,7 +308,7 @@ function normalize(nodes, ctx) {
|
|
|
308
308
|
else if ((node.startsWith('memory.') || node.endsWith('load') || node.endsWith('store')) && isIdx(nodes[0])) out.push(nodes.shift())
|
|
309
309
|
}
|
|
310
310
|
else if (Array.isArray(node)) {
|
|
311
|
-
|
|
311
|
+
let op = node[0]
|
|
312
312
|
node.loc != null && (err.loc = node.loc) // track position for errors
|
|
313
313
|
|
|
314
314
|
// code metadata annotations - pass through as marker with metadata type and data
|
|
@@ -348,6 +348,13 @@ function normalize(nodes, ctx) {
|
|
|
348
348
|
}
|
|
349
349
|
out.push(...normalize(parts, ctx), 'end')
|
|
350
350
|
}
|
|
351
|
+
else if (op === 'ref.test' || op === 'ref.cast') {
|
|
352
|
+
const type = parts[0]
|
|
353
|
+
const isNullable = !Array.isArray(type) || type[1] === 'null' || type[0] !== 'ref'
|
|
354
|
+
if (isNullable) op += '_null'
|
|
355
|
+
out.push(...normalize(parts.slice(1), ctx), op, type)
|
|
356
|
+
nodes.unshift(...out.splice(out.length - 2))
|
|
357
|
+
}
|
|
351
358
|
else {
|
|
352
359
|
const imm = []
|
|
353
360
|
// Collect immediate operands (non-arrays or special forms like type/param/result/ref)
|
|
@@ -965,7 +972,7 @@ const instr = (nodes, ctx) => {
|
|
|
965
972
|
// select: becomes typed select (opcode+1) if next node is an array with result types
|
|
966
973
|
if (op === 'select' && nodes[0]?.length) bytes[0]++
|
|
967
974
|
// ref.type|cast: opcode+1 if type is nullable: (ref null $t) or (funcref, anyref, etc.)
|
|
968
|
-
else if (HANDLER[op] === IMM.reftype && (nodes[0][1] === 'null' || nodes[0][0] !== 'ref')) {
|
|
975
|
+
else if (HANDLER[op] === IMM.reftype && !op.endsWith('_null') && (nodes[0][1] === 'null' || nodes[0][0] !== 'ref')) {
|
|
969
976
|
bytes[bytes.length - 1]++
|
|
970
977
|
}
|
|
971
978
|
bytes.push(...HANDLER[op](nodes, ctx, op))
|
package/src/const.js
CHANGED
|
@@ -59,7 +59,7 @@ export const INSTR = [
|
|
|
59
59
|
'struct.new typeidx', 'struct.new_default typeidx', 'struct.get typeidx_field', 'struct.get_s typeidx_field', 'struct.get_u typeidx_field', 'struct.set typeidx_field',
|
|
60
60
|
'array.new typeidx', 'array.new_default typeidx', 'array.new_fixed typeidx_multi', 'array.new_data typeidx_dataidx', 'array.new_elem typeidx_elemidx',
|
|
61
61
|
'array.get typeidx', 'array.get_s typeidx', 'array.get_u typeidx', 'array.set typeidx', 'array.len', 'array.fill typeidx', 'array.copy typeidx_typeidx',
|
|
62
|
-
'array.init_data typeidx_dataidx', 'array.init_elem typeidx_elemidx', 'ref.test reftype', '', 'ref.cast reftype', '', 'br_on_cast reftype2', 'br_on_cast_fail reftype2',
|
|
62
|
+
'array.init_data typeidx_dataidx', 'array.init_elem typeidx_elemidx', 'ref.test reftype', 'ref.test_null reftype', 'ref.cast reftype', 'ref.cast_null reftype', 'br_on_cast reftype2', 'br_on_cast_fail reftype2',
|
|
63
63
|
'any.convert_extern', 'extern.convert_any', 'ref.i31', 'i31.get_s', 'i31.get_u',
|
|
64
64
|
// custom descriptors (Phase 3): 0xFB 0x20-0x26
|
|
65
65
|
, 'struct.new_desc typeidx', 'struct.new_default_desc typeidx', 'ref.get_desc typeidx', 'ref.cast_desc_eq reftype', , 'br_on_cast_desc_eq reftype2', 'br_on_cast_desc_eq_fail reftype2',
|
|
@@ -182,7 +182,7 @@ export const TYPE = {
|
|
|
182
182
|
// Value types
|
|
183
183
|
i8: 0x78, i16: 0x77, i32: 0x7f, i64: 0x7e, f32: 0x7d, f64: 0x7c, void: 0x40, v128: 0x7B,
|
|
184
184
|
// Heap types
|
|
185
|
-
exn: 0x69, noexn: 0x74, nofunc: 0x73, noextern: 0x72, none: 0x71, func: 0x70, extern: 0x6F, any: 0x6E, eq: 0x6D, i31: 0x6C, struct: 0x6B, array: 0x6A,
|
|
185
|
+
exn: 0x69, noexn: 0x74, nofunc: 0x73, noextern: 0x72, none: 0x71, func: 0x70, extern: 0x6F, any: 0x6E, eq: 0x6D, i31: 0x6C, struct: 0x6B, array: 0x6A, data: 0x6B,
|
|
186
186
|
cont: 0x68, nocont: 0x75, // stack switching (Phase 3)
|
|
187
187
|
string: 0x67, stringview_wtf8: 0x66, stringview_wtf16: 0x60, stringview_iter: 0x61, // stringref
|
|
188
188
|
// Reference type abbreviations (absheaptype abbrs)
|
package/src/encode.js
CHANGED
|
@@ -128,16 +128,30 @@ const _u8 = new Uint8Array(_buf), _i32 = new Int32Array(_buf), _f32 = new Float3
|
|
|
128
128
|
|
|
129
129
|
i64.parse = n => {
|
|
130
130
|
n = cleanInt(n)
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
131
|
+
const neg = n[0] === '-'
|
|
132
|
+
const body = neg ? n.slice(1) : n
|
|
133
|
+
// Range check on the literal string before BigInt conversion (lexicographic compare on clean digits).
|
|
134
|
+
let max
|
|
135
|
+
if (body[0] === '0' && (body[1] === 'x' || body[1] === 'X')) {
|
|
136
|
+
const hex = body.slice(2).replace(/^0+/, '') || '0'
|
|
137
|
+
max = neg ? '8000000000000000' : 'ffffffffffffffff'
|
|
138
|
+
if (hex.length > 16 || (hex.length === 16 && hex.toLowerCase() > max)) err(`i64 constant out of range`)
|
|
139
|
+
} else {
|
|
140
|
+
const dec = body.replace(/^0+/, '') || '0'
|
|
141
|
+
max = neg ? '9223372036854775808' : '18446744073709551615'
|
|
142
|
+
if (dec.length > max.length || (dec.length === max.length && dec > max)) err(`i64 constant out of range`)
|
|
143
|
+
}
|
|
144
|
+
let bi = BigInt(body)
|
|
145
|
+
if (neg) bi = 0n - bi
|
|
146
|
+
_i64[0] = bi
|
|
134
147
|
return _i64[0]
|
|
135
148
|
}
|
|
136
149
|
|
|
137
|
-
const F32_SIGN = 0x80000000, F32_NAN = 0x7f800000
|
|
150
|
+
const F32_SIGN = 0x80000000, F32_NAN = 0x7f800000, F32_QUIET = 0x400000
|
|
138
151
|
export function f32(input, value, idx) {
|
|
139
|
-
|
|
140
|
-
|
|
152
|
+
// Plain `nan` / `-nan` (with optional `:0xPAYLOAD`) — set the bit pattern explicitly.
|
|
153
|
+
if (typeof input === 'string' && (idx = input.indexOf('nan')) >= 0) {
|
|
154
|
+
value = input[idx + 3] === ':' ? i32.parse(input.slice(idx + 4)) : F32_QUIET
|
|
141
155
|
value |= F32_NAN
|
|
142
156
|
if (input[0] === '-') value |= F32_SIGN
|
|
143
157
|
_i32[0] = value
|
|
@@ -150,10 +164,11 @@ export function f32(input, value, idx) {
|
|
|
150
164
|
return [_u8[0], _u8[1], _u8[2], _u8[3]]
|
|
151
165
|
}
|
|
152
166
|
|
|
153
|
-
const F64_SIGN = 0x8000000000000000n, F64_NAN = 0x7ff0000000000000n
|
|
167
|
+
const F64_SIGN = 0x8000000000000000n, F64_NAN = 0x7ff0000000000000n, F64_QUIET = 0x8000000000000n
|
|
154
168
|
export function f64(input, value, idx) {
|
|
155
|
-
|
|
156
|
-
|
|
169
|
+
// Plain `nan` / `-nan` (with optional `:0xPAYLOAD`) — set the bit pattern explicitly.
|
|
170
|
+
if (typeof input === 'string' && (idx = input.indexOf('nan')) >= 0) {
|
|
171
|
+
value = input[idx + 3] === ':' ? i64.parse(input.slice(idx + 4)) : F64_QUIET
|
|
157
172
|
value |= F64_NAN
|
|
158
173
|
if (input[0] === '-') value |= F64_SIGN
|
|
159
174
|
_i64[0] = value
|
|
@@ -179,9 +194,15 @@ f64.parse = (input, max=Number.MAX_VALUE) => {
|
|
|
179
194
|
let [int, fract=''] = sig.split('.'); // integer and fractional parts
|
|
180
195
|
let flen = fract.length ?? 0;
|
|
181
196
|
|
|
182
|
-
// Parse integer part
|
|
183
|
-
|
|
184
|
-
|
|
197
|
+
// Parse integer part — accumulate from least-significant digit to preserve precision.
|
|
198
|
+
// parseInt loses low bits for values > 2^53 because left-to-right
|
|
199
|
+
// accumulation rounds at each step; right-to-left keeps intermediates
|
|
200
|
+
// small so the final large+small addition rounds correctly.
|
|
201
|
+
let intVal = 0;
|
|
202
|
+
for (let i = int.length - 1; i >= 2; i--) {
|
|
203
|
+
let digit = parseInt(int[i], 16);
|
|
204
|
+
intVal += digit * (16 ** (int.length - 1 - i));
|
|
205
|
+
}
|
|
185
206
|
|
|
186
207
|
// 0x10a.fbc = 0x10afbc * 16⁻³ = 266.9833984375
|
|
187
208
|
// Parse fractional part: fract / 16^flen
|