watr 2.2.5 → 2.3.0
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/package.json +3 -2
- package/readme.md +13 -36
- package/src/compile.js +88 -25
- package/src/const.js +15 -2
- package/src/encode.js +123 -0
- package/src/util.js +2 -115
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "watr",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.0",
|
|
4
4
|
"description": "Ligth & fast WAT compiler",
|
|
5
5
|
"main": "watr.js",
|
|
6
6
|
"exports": {
|
|
@@ -39,8 +39,9 @@
|
|
|
39
39
|
},
|
|
40
40
|
"homepage": "https://github.com/audio-lab/watr#readme",
|
|
41
41
|
"devDependencies": {
|
|
42
|
-
"tst": "^7.
|
|
42
|
+
"tst": "^7.3.0",
|
|
43
43
|
"wabt": "^1.0.28",
|
|
44
|
+
"wassemble": "^0.0.2",
|
|
44
45
|
"wat-compiler": "^1.0.0"
|
|
45
46
|
}
|
|
46
47
|
}
|
package/readme.md
CHANGED
|
@@ -1,44 +1,26 @@
|
|
|
1
|
-
# watr [](https://github.com/audio-lab/watr/actions/workflows/test.js.yml) [](https://bundlephobia.com/package/watr)
|
|
1
|
+
# watr [](https://github.com/audio-lab/watr/actions/workflows/test.js.yml) [](https://bundlephobia.com/package/watr) [](https://npmjs.org/watr)
|
|
2
2
|
|
|
3
|
-
Bare minimum wasm text compiler
|
|
3
|
+
Bare minimum wasm text compiler/formatter.<br/>
|
|
4
|
+
A light & fast alternative to [wat2wasm](https://github.com/AssemblyScript/wabt.js).<br/>
|
|
4
5
|
Useful for hi-level languages or dynamic (in-browser) compilation.<br>
|
|
5
6
|
|
|
6
7
|
<!-- See [REPL](https://audio-lab.github.io/watr/repl.html).-->
|
|
7
8
|
|
|
8
9
|
| Size (gzipped) | Performance (op/s)
|
|
9
|
-
|
|
10
|
+
---|---|---|---
|
|
10
11
|
watr | 3.8 kb | 6000
|
|
11
12
|
[wat-compiler](https://github.com/stagas/wat-compiler) | 6 kb | 348
|
|
12
13
|
[wabt](https://github.com/AssemblyScript/wabt.js) | 300 kb | 574
|
|
14
|
+
[wassemble](https://github.com/wingo/wassemble) | ? kb | ?
|
|
13
15
|
|
|
14
16
|
## Usage
|
|
15
17
|
|
|
16
|
-
```js
|
|
17
|
-
import wat from 'watr'
|
|
18
|
-
|
|
19
|
-
// compile text to binary
|
|
20
|
-
const buffer = wat(`(func
|
|
21
|
-
(export "double") (param f64) (result f64)
|
|
22
|
-
(f64.mul (local.get 0) (f64.const 2))
|
|
23
|
-
)`)
|
|
24
|
-
|
|
25
|
-
// create instance
|
|
26
|
-
const module = new WebAssembly.Module(buffer)
|
|
27
|
-
const instance = new WebAssembly.Instance(module)
|
|
28
|
-
|
|
29
|
-
// use API
|
|
30
|
-
const {double} = instance.exports
|
|
31
|
-
double(108) // 216
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
## API
|
|
35
|
-
|
|
36
18
|
### Compile
|
|
37
19
|
|
|
38
|
-
|
|
20
|
+
Compile wasm text or syntax tree into wasm binary.
|
|
39
21
|
|
|
40
22
|
```js
|
|
41
|
-
import { compile } from 'watr'
|
|
23
|
+
import compile from 'watr' // or `import { compile } from 'watr'`
|
|
42
24
|
|
|
43
25
|
const buffer = compile(`(func (export "double")
|
|
44
26
|
(param f64) (result f64)
|
|
@@ -99,10 +81,12 @@ parse(`(func (export "double") (param f64) (result f64) (f64.mul (local.get 0) (
|
|
|
99
81
|
## Status
|
|
100
82
|
|
|
101
83
|
* [x] wasm core
|
|
102
|
-
* [x]
|
|
103
|
-
* [x] bulk memory ops
|
|
104
|
-
* [ ]
|
|
105
|
-
* [ ] multiple memories
|
|
84
|
+
* [x] [multi-value](https://github.com/WebAssembly/spec/blob/master/proposals/multi-value/Overview.md)
|
|
85
|
+
* [x] [bulk memory ops](https://github.com/WebAssembly/bulk-memory-operations/blob/master/proposals/bulk-memory-operations/Overview.md)
|
|
86
|
+
* [x] [simd](https://github.com/WebAssembly/simd/blob/master/proposals/simd/SIMD.md)
|
|
87
|
+
* [ ] [multiple memories](https://github.com/WebAssembly/multi-memory/blob/master/proposals/multi-memory/Overview.md)
|
|
88
|
+
* [ ] [func refs](https://github.com/WebAssembly/function-references/blob/main/proposals/function-references/Overview.md)
|
|
89
|
+
* [ ] [gc](https://github.com/WebAssembly/gc)
|
|
106
90
|
|
|
107
91
|
|
|
108
92
|
<!--
|
|
@@ -134,11 +118,4 @@ parse(`(func (export "double") (param f64) (result f64) (f64.mul (local.get 0) (
|
|
|
134
118
|
* [leb128b](https://github.com/shmishtopher/wasm-LEB128/tree/master/esm)
|
|
135
119
|
-->
|
|
136
120
|
|
|
137
|
-
## Alternatives
|
|
138
|
-
|
|
139
|
-
* [wabt](https://www.npmjs.com/package/wabt) − port of WABT for the web, de-facto standard.
|
|
140
|
-
* [wat-compiler](https://www.npmjs.com/package/wat-compiler) − compact alternative for WABT, older brother of _watr_.
|
|
141
|
-
* [wassemble](https://github.com/wingo/wassemble)
|
|
142
|
-
* [web49](https://github.com/FastVM/Web49)
|
|
143
|
-
|
|
144
121
|
<p align=center><a href="https://github.com/krsnzd/license/">🕉</a></p>
|
package/src/compile.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as encode from './encode.js'
|
|
2
|
+
import { uleb } from './encode.js'
|
|
2
3
|
import { OP, SECTION, ALIGN, TYPE, KIND } from './const.js'
|
|
3
4
|
import parse from './parse.js'
|
|
5
|
+
import { err, TypedArray } from './util.js'
|
|
4
6
|
|
|
5
|
-
const OP_END = 0xb, OP_I32_CONST = 0x41, OP_I64_CONST = 0x42, OP_F32_CONST = 0x43, OP_F64_CONST = 0x44, OP_SKIP = 0x6
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* Converts a WebAssembly Text Format (WAT) tree to a WebAssembly binary format (Wasm).
|
|
@@ -121,11 +122,38 @@ const build = {
|
|
|
121
122
|
|
|
122
123
|
// NOTE: numeric comparison is faster than generic hash lookup
|
|
123
124
|
|
|
125
|
+
// v128s: (v128.load x) etc
|
|
126
|
+
// https://github.com/WebAssembly/simd/blob/master/proposals/simd/BinarySIMD.md
|
|
127
|
+
if (opCode >= 268) {
|
|
128
|
+
opCode -= 268
|
|
129
|
+
immed = [0xfd, ...uleb(opCode)]
|
|
130
|
+
// (v128.load)
|
|
131
|
+
if (opCode <= 0x0b) {
|
|
132
|
+
const o = consumeParams(args)
|
|
133
|
+
immed.push(Math.log2(o.align ?? ALIGN[op]), ...uleb(o.offset ?? 0))
|
|
134
|
+
}
|
|
135
|
+
// (v128.load_lane offset? align? idx)
|
|
136
|
+
else if (opCode >= 0x54 && opCode <= 0x5d) {
|
|
137
|
+
const o = consumeParams(args)
|
|
138
|
+
immed.push(Math.log2(o.align ?? ALIGN[op]), ...uleb(o.offset ?? 0))
|
|
139
|
+
// (v128.load_lane_zero)
|
|
140
|
+
if (opCode <= 0x5b) immed.push(...uleb(args.shift()))
|
|
141
|
+
}
|
|
142
|
+
// (v128.const i32x4), (i8x16.shuffle 0 1 ... 15 a b)
|
|
143
|
+
else if (opCode === 0x0c || opCode === 0x0d) {
|
|
144
|
+
immed.push(...consumeConst(op.split('.')[0], args))
|
|
145
|
+
}
|
|
146
|
+
// (i8x16.extract_lane_s 0 ...)
|
|
147
|
+
else if (opCode >= 0x15 && opCode <= 0x22) {
|
|
148
|
+
immed.push(...uleb(args.shift()))
|
|
149
|
+
}
|
|
150
|
+
opCode = null // ignore opcode
|
|
151
|
+
}
|
|
124
152
|
|
|
125
153
|
// bulk memory: (memory.init) (memory.copy) etc
|
|
126
154
|
// https://github.com/WebAssembly/bulk-memory-operations/blob/master/proposals/bulk-memory-operations/Overview.md#instruction-encoding
|
|
127
|
-
if (opCode >= 252) {
|
|
128
|
-
immed = [0xfc, opCode
|
|
155
|
+
else if (opCode >= 252) {
|
|
156
|
+
immed = [0xfc, ...uleb(opCode -= 252)]
|
|
129
157
|
// memory.init idx, memory.drop idx, table.init idx, table.drop idx
|
|
130
158
|
if (!(opCode & 0b10)) immed.push(...uleb(args.shift()))
|
|
131
159
|
else immed.push(0)
|
|
@@ -134,20 +162,19 @@ const build = {
|
|
|
134
162
|
opCode = null // ignore opcode
|
|
135
163
|
}
|
|
136
164
|
|
|
137
|
-
// binary/unary -
|
|
138
|
-
else if (opCode >=
|
|
165
|
+
// binary/unary (i32.add a b) - no immed
|
|
166
|
+
else if (opCode >= 0x45) { }
|
|
139
167
|
|
|
140
|
-
// (i32.store align=n offset=m at value)
|
|
168
|
+
// (i32.store align=n offset=m at value) etc
|
|
141
169
|
else if (opCode >= 40 && opCode <= 62) {
|
|
142
170
|
// FIXME: figure out point in Math.log2 aligns
|
|
143
|
-
let o =
|
|
144
|
-
|
|
145
|
-
immed = [Math.log2(o.align), ...uleb(o.offset)]
|
|
171
|
+
let o = consumeParams(args)
|
|
172
|
+
immed = [Math.log2(o.align ?? ALIGN[op]), ...uleb(o.offset ?? 0)]
|
|
146
173
|
}
|
|
147
174
|
|
|
148
|
-
// (i32.const 123)
|
|
149
|
-
else if (opCode >=
|
|
150
|
-
immed = (
|
|
175
|
+
// (i32.const 123), (f32.const 123.45) etc
|
|
176
|
+
else if (opCode >= 0x41 && opCode <= 0x44) {
|
|
177
|
+
immed = encode[op.split('.')[0]](args.shift())
|
|
151
178
|
}
|
|
152
179
|
|
|
153
180
|
// (local.get $id), (local.tee $id x)
|
|
@@ -156,7 +183,7 @@ const build = {
|
|
|
156
183
|
}
|
|
157
184
|
|
|
158
185
|
// (global.get id), (global.set id)
|
|
159
|
-
else if (opCode ==
|
|
186
|
+
else if (opCode == 0x23 || opCode == 36) {
|
|
160
187
|
immed = uleb(args[0]?.[0] === '$' ? ctx.global[args.shift()] : args.shift())
|
|
161
188
|
}
|
|
162
189
|
|
|
@@ -264,7 +291,7 @@ const build = {
|
|
|
264
291
|
return () => {
|
|
265
292
|
const bytes = []
|
|
266
293
|
while (body.length) consume(body, bytes)
|
|
267
|
-
ctx.code.push([...uleb(bytes.length + 2 + locTypes.length), ...uleb(locTypes.length >> 1), ...locTypes, ...bytes,
|
|
294
|
+
ctx.code.push([...uleb(bytes.length + 2 + locTypes.length), ...uleb(locTypes.length >> 1), ...locTypes, ...bytes, 0x0b])
|
|
268
295
|
}
|
|
269
296
|
},
|
|
270
297
|
|
|
@@ -284,7 +311,7 @@ const build = {
|
|
|
284
311
|
let name = args[0][0] === '$' && args.shift()
|
|
285
312
|
if (name) ctx.global[name] = ctx.global.length
|
|
286
313
|
let [type, init] = args, mut = type[0] === 'mut' ? 1 : 0
|
|
287
|
-
ctx.global.push([TYPE[mut ? type[1] : type], mut, ...
|
|
314
|
+
ctx.global.push([TYPE[mut ? type[1] : type], mut, ...initGlobal(init)])
|
|
288
315
|
},
|
|
289
316
|
|
|
290
317
|
// (table 1 2? funcref)
|
|
@@ -299,7 +326,7 @@ const build = {
|
|
|
299
326
|
// (elem (i32.const 0) $f1 $f2), (elem (global.get 0) $f1 $f2)
|
|
300
327
|
elem([, offset, ...elems], ctx) {
|
|
301
328
|
const tableIdx = 0 // FIXME: table index can be defined
|
|
302
|
-
ctx.elem.push([tableIdx, ...
|
|
329
|
+
ctx.elem.push([tableIdx, ...initGlobal(offset, ctx), ...uleb(elems.length), ...elems.flatMap(el => uleb(el[0] === '$' ? ctx.func[el] : el))])
|
|
303
330
|
},
|
|
304
331
|
|
|
305
332
|
// (export "name" (kind $name|idx))
|
|
@@ -341,9 +368,18 @@ const build = {
|
|
|
341
368
|
},
|
|
342
369
|
|
|
343
370
|
// (data (i32.const 0) "\aa" "\bb"?)
|
|
344
|
-
data(
|
|
345
|
-
|
|
346
|
-
|
|
371
|
+
// (data (offset (i32.const 0)) (memory ref) "\aa" "\bb"?)
|
|
372
|
+
// (data (global.get $x) "\aa" "\bb"?)
|
|
373
|
+
data([, ...inits], ctx) {
|
|
374
|
+
let offset, mem
|
|
375
|
+
|
|
376
|
+
if (inits[0]?.[0] === 'offset') [, offset] = inits.shift()
|
|
377
|
+
if (inits[0]?.[0] === 'memory') [, mem] = inits.shift()
|
|
378
|
+
if (inits[0]?.[0] === 'offset') [, offset] = inits.shift()
|
|
379
|
+
if (!offset && !mem) offset = inits.shift()
|
|
380
|
+
if (!offset) offset = ['i32.const', 0]
|
|
381
|
+
|
|
382
|
+
ctx.data.push([0, ...initGlobal(offset, ctx), ...str(inits.map(i => i[0] === '"' ? i.slice(1, -1) : i).join(''))])
|
|
347
383
|
},
|
|
348
384
|
|
|
349
385
|
// (start $main)
|
|
@@ -352,11 +388,33 @@ const build = {
|
|
|
352
388
|
}
|
|
353
389
|
}
|
|
354
390
|
|
|
355
|
-
// (i32.const 0) - instantiation time initializer
|
|
356
|
-
const
|
|
357
|
-
|
|
358
|
-
[
|
|
391
|
+
// (i32.const 0), (global.get idx) - instantiation time initializer
|
|
392
|
+
const initGlobal = ([op, literal, ...args], ctx) => {
|
|
393
|
+
if (op === 'global.get') return [0x23, ...uleb(literal[0] === '$' ? ctx.global[literal] : literal), 0x0b]
|
|
394
|
+
const [type] = op.split('.')
|
|
395
|
+
// (v128.const i32x4 1 2 3 4)
|
|
396
|
+
return [...(type === 'v128' ? [0xfd, 0x0c] : [0x41 + ['i32', 'i64', 'f32', 'f64'].indexOf(type)]), ...consumeConst(type, [literal, ...args]), 0x0b]
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
// consume cost, no op type
|
|
400
|
+
const consumeConst = (type, args) => {
|
|
401
|
+
// (v128.const i32x4 1 2 3 4), (i8x16.shuffle 1 2 ... 15)
|
|
402
|
+
if (type === 'v128' || type === 'i8x16') {
|
|
403
|
+
let [t, n] = (type === 'v128' ? args.shift() : type).split('x'),
|
|
404
|
+
bytes = new Uint8Array(16),
|
|
405
|
+
arr = new TypedArray[t](bytes.buffer)
|
|
406
|
+
|
|
407
|
+
for (let i = 0; i < n; i++) {
|
|
408
|
+
arr[i] = encode[t].parse(args.shift())
|
|
409
|
+
}
|
|
359
410
|
|
|
411
|
+
return bytes
|
|
412
|
+
}
|
|
413
|
+
// (i32.const 1)
|
|
414
|
+
return encode[type](args[0])
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
// escape codes
|
|
360
418
|
const escape = { n: 10, r: 13, t: 9, v: 1, '\\': 92 }
|
|
361
419
|
|
|
362
420
|
// build string binary
|
|
@@ -402,4 +460,9 @@ const consumeType = (nodes, ctx) => {
|
|
|
402
460
|
return [idx, params, result]
|
|
403
461
|
}
|
|
404
462
|
|
|
405
|
-
|
|
463
|
+
// consume align/offset/etc params
|
|
464
|
+
const consumeParams = (args) => {
|
|
465
|
+
let params = {}, param
|
|
466
|
+
while (args[0]?.includes('=')) param = args.shift().split('='), params[param[0]] = Number(param[1])
|
|
467
|
+
return params
|
|
468
|
+
}
|
package/src/const.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// ref: https://github.com/stagas/wat-compiler/blob/main/lib/const.js
|
|
2
2
|
// NOTE: squashing into a string doesn't save up gzipped size
|
|
3
|
+
// FIXME: object would allow faster lookup and number of immediates, which would allow reducing size of compile fn
|
|
3
4
|
export const OP = [
|
|
4
5
|
'unreachable', 'nop', 'block', 'loop', 'if', 'else', 'then', , , , ,
|
|
5
6
|
'end', 'br', 'br_if', 'br_table', 'return', 'call', 'call_indirect', , , , , , , , ,
|
|
@@ -26,10 +27,17 @@ export const OP = [
|
|
|
26
27
|
'f32.convert_i32_s', 'f32.convert_i32_u', 'f32.convert_i64_s', 'f32.convert_i64_u', 'f32.demote_f64',
|
|
27
28
|
'f64.convert_i32_s', 'f64.convert_i32_u', 'f64.convert_i64_s', 'f64.convert_i64_u', 'f64.promote_f32',
|
|
28
29
|
'i32.reinterpret_f32', 'i64.reinterpret_f64', 'f32.reinterpret_i32', 'f64.reinterpret_i64', , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,
|
|
29
|
-
'memory.init', 'data.drop', 'memory.copy', 'memory.fill', 'table.init', 'elem.drop', 'table.copy'
|
|
30
|
+
'memory.init', 'data.drop', 'memory.copy', 'memory.fill', 'table.init', 'elem.drop', 'table.copy', ,
|
|
31
|
+
|
|
32
|
+
// ref: https://github.com/WebAssembly/simd/blob/master/proposals/simd/BinarySIMD.md
|
|
33
|
+
"v128.load", "v128.load8x8_s", "v128.load8x8_u", "v128.load16x4_s", "v128.load16x4_u", "v128.load32x2_s", "v128.load32x2_u", "v128.load8_splat", "v128.load16_splat", "v128.load32_splat", "v128.load64_splat", "v128.store", "v128.const", "i8x16.shuffle",
|
|
34
|
+
"i8x16.swizzle", "i8x16.splat", "i16x8.splat", "i32x4.splat", "i64x2.splat", "f32x4.splat", "f64x2.splat", "i8x16.extract_lane_s", "i8x16.extract_lane_u", "i8x16.replace_lane", "i16x8.extract_lane_s", "i16x8.extract_lane_u", "i16x8.replace_lane", "i32x4.extract_lane", "i32x4.replace_lane", "i64x2.extract_lane", "i64x2.replace_lane", "f32x4.extract_lane", "f32x4.replace_lane", "f64x2.extract_lane", "f64x2.replace_lane",
|
|
35
|
+
"i8x16.eq", "i8x16.ne", "i8x16.lt_s", "i8x16.lt_u", "i8x16.gt_s", "i8x16.gt_u", "i8x16.le_s", "i8x16.le_u", "i8x16.ge_s", "i8x16.ge_u", "i16x8.eq", "i16x8.ne", "i16x8.lt_s", "i16x8.lt_u", "i16x8.gt_s", "i16x8.gt_u", "i16x8.le_s", "i16x8.le_u", "i16x8.ge_s", "i16x8.ge_u", "i32x4.eq", "i32x4.ne", "i32x4.lt_s", "i32x4.lt_u", "i32x4.gt_s", "i32x4.gt_u", "i32x4.le_s", "i32x4.le_u", "i32x4.ge_s", "i32x4.ge_u", "f32x4.eq", "f32x4.ne", "f32x4.lt", "f32x4.gt", "f32x4.le", "f32x4.ge", "f64x2.eq", "f64x2.ne", "f64x2.lt", "f64x2.gt", "f64x2.le", "f64x2.ge", "v128.not", "v128.and", "v128.andnot", "v128.or", "v128.xor", "v128.bitselect", "v128.any_true",
|
|
36
|
+
"v128.load8_lane", "v128.load16_lane", "v128.load32_lane", "v128.load64_lane", "v128.store8_lane", "v128.store16_lane", "v128.store32_lane", "v128.store64_lane", "v128.load32_zero", "v128.load64_zero", "f32x4.demote_f64x2_zero", "f64x2.promote_low_f32x4",
|
|
37
|
+
"i8x16.abs", "i8x16.neg", "i8x16.popcnt", "i8x16.all_true", "i8x16.bitmask", "i8x16.narrow_i16x8_s", "i8x16.narrow_i16x8_u", "f32x4.ceil", "f32x4.floor", "f32x4.trunc", "f32x4.nearest", "i8x16.shl", "i8x16.shr_s", "i8x16.shr_u", "i8x16.add", "i8x16.add_sat_s", "i8x16.add_sat_u", "i8x16.sub", "i8x16.sub_sat_s", "i8x16.sub_sat_u", "f64x2.ceil", "f64x2.floor", "i8x16.min_s", "i8x16.min_u", "i8x16.max_s", "i8x16.max_u", "f64x2.trunc", "i8x16.avgr_u", "i16x8.extadd_pairwise_i8x16_s", "i16x8.extadd_pairwise_i8x16_u", "i32x4.extadd_pairwise_i16x8_s", "i32x4.extadd_pairwise_i16x8_u", "i16x8.abs", "i16x8.neg", "i16x8.q15mulr_sat_s", "i16x8.all_true", "i16x8.bitmask", "i16x8.narrow_i32x4_s", "i16x8.narrow_i32x4_u", "i16x8.extend_low_i8x16_s", "i16x8.extend_high_i8x16_s", "i16x8.extend_low_i8x16_u", "i16x8.extend_high_i8x16_u", "i16x8.shl", "i16x8.shr_s", "i16x8.shr_u", "i16x8.add", "i16x8.add_sat_s", "i16x8.add_sat_u", "i16x8.sub", "i16x8.sub_sat_s", "i16x8.sub_sat_u", "f64x2.nearest", "i16x8.mul", "i16x8.min_s", "i16x8.min_u", "i16x8.max_s", "i16x8.max_u", , "i16x8.avgr_u", "i16x8.extmul_low_i8x16_s", "i16x8.extmul_high_i8x16_s", "i16x8.extmul_low_i8x16_u", "i16x8.extmul_high_i8x16_u", "i32x4.abs", "i32x4.neg", , "i32x4.all_true", "i32x4.bitmask", , , "i32x4.extend_low_i16x8_s", "i32x4.extend_high_i16x8_s", "i32x4.extend_low_i16x8_u", "i32x4.extend_high_i16x8_u", "i32x4.shl", "i32x4.shr_s", "i32x4.shr_u", "i32x4.add", , , "i32x4.sub", , , , "i32x4.mul", "i32x4.min_s", "i32x4.min_u", "i32x4.max_s", "i32x4.max_u", "i32x4.dot_i16x8_s", , "i32x4.extmul_low_i16x8_s", "i32x4.extmul_high_i16x8_s", "i32x4.extmul_low_i16x8_u", "i32x4.extmul_high_i16x8_u", "i64x2.abs", "i64x2.neg", , "i64x2.all_true", "i64x2.bitmask", , , "i64x2.extend_low_i32x4_s", "i64x2.extend_high_i32x4_s", "i64x2.extend_low_i32x4_u", "i64x2.extend_high_i32x4_u", "i64x2.shl", "i64x2.shr_s", "i64x2.shr_u", "i64x2.add", , , "i64x2.sub", , , , "i64x2.mul", "i64x2.eq", "i64x2.ne", "i64x2.lt_s", "i64x2.gt_s", "i64x2.le_s", "i64x2.ge_s", "i64x2.extmul_low_i32x4_s", "i64x2.extmul_high_i32x4_s", "i64x2.extmul_low_i32x4_u", "i64x2.extmul_high_i32x4_u", "f32x4.abs", "f32x4.neg", , "f32x4.sqrt", "f32x4.add", "f32x4.sub", "f32x4.mul", "f32x4.div", "f32x4.min", "f32x4.max", "f32x4.pmin", "f32x4.pmax", "f64x2.abs", "f64x2.neg", , "f64x2.sqrt", "f64x2.add", "f64x2.sub", "f64x2.mul", "f64x2.div", "f64x2.min", "f64x2.max", "f64x2.pmin", "f64x2.pmax", "i32x4.trunc_sat_f32x4_s", "i32x4.trunc_sat_f32x4_u", "f32x4.convert_i32x4_s", "f32x4.convert_i32x4_u", "i32x4.trunc_sat_f64x2_s_zero", "i32x4.trunc_sat_f64x2_u_zero", "f64x2.convert_low_i32x4_s", "f64x2.convert_low_i32x4_u"
|
|
30
38
|
],
|
|
31
39
|
SECTION = { type: 1, import: 2, func: 3, table: 4, memory: 5, global: 6, export: 7, start: 8, elem: 9, code: 10, data: 11 },
|
|
32
|
-
TYPE = { i32: 0x7f, i64: 0x7e, f32: 0x7d, f64: 0x7c, void: 0x40, func: 0x60, funcref: 0x70 },
|
|
40
|
+
TYPE = { i32: 0x7f, i64: 0x7e, f32: 0x7d, f64: 0x7c, void: 0x40, func: 0x60, funcref: 0x70, v128: 0x7B },
|
|
33
41
|
KIND = { func: 0, table: 1, memory: 2, global: 3 },
|
|
34
42
|
ALIGN = {
|
|
35
43
|
'i32.load': 4, 'i64.load': 8, 'f32.load': 4, 'f64.load': 8,
|
|
@@ -37,6 +45,11 @@ export const OP = [
|
|
|
37
45
|
'i64.load8_s': 1, 'i64.load8_u': 1, 'i64.load16_s': 2, 'i64.load16_u': 2, 'i64.load32_s': 4, 'i64.load32_u': 4, 'i32.store': 4,
|
|
38
46
|
'i64.store': 8, 'f32.store': 4, 'f64.store': 8,
|
|
39
47
|
'i32.store8': 1, 'i32.store16': 2, 'i64.store8': 1, 'i64.store16': 2, 'i64.store32': 4,
|
|
48
|
+
|
|
49
|
+
'v128.load': 16, 'v128.load8x8_s': 8, 'v128.load8x8_u': 8, 'v128.load16x4_s': 8, 'v128.load16x4_u': 8, 'v128.load32x2_s': 8, 'v128.load32x2_u': 8, 'v128.load8_splat': 1, 'v128.load16_splat': 2, 'v128.load32_splat': 4, 'v128.load64_splat': 8, 'v128.store': 16,
|
|
50
|
+
'v128.load': 16,
|
|
51
|
+
|
|
52
|
+
"v128.load8_lane": 1, "v128.load16_lane": 2, "v128.load32_lane": 4, "v128.load64_lane": 8, "v128.store8_lane": 1, "v128.store16_lane": 2, "v128.store32_lane": 4, "v128.store64_lane": 8, "v128.load32_zero": 4, "v128.load64_zero": 8
|
|
40
53
|
},
|
|
41
54
|
BLOCK = {
|
|
42
55
|
loop: 1, block: 1, if: 1, end: -1, return: -1
|
package/src/encode.js
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
// encoding ref: https://github.com/j-s-n/WebBS/blob/master/compiler/byteCode.js
|
|
2
|
+
|
|
3
|
+
// uleb
|
|
4
|
+
export const uleb = (n, buffer = []) => {
|
|
5
|
+
if (typeof n === 'string') n = i32.parse(n)
|
|
6
|
+
|
|
7
|
+
let byte = n & 0b01111111;
|
|
8
|
+
n = n >>> 7;
|
|
9
|
+
|
|
10
|
+
if (n === 0) {
|
|
11
|
+
buffer.push(byte);
|
|
12
|
+
return buffer;
|
|
13
|
+
} else {
|
|
14
|
+
buffer.push(byte | 0b10000000);
|
|
15
|
+
return uleb(n, buffer);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// leb
|
|
20
|
+
export function i32(n, buffer = []) {
|
|
21
|
+
if (typeof n === 'string') n = i32.parse(n)
|
|
22
|
+
|
|
23
|
+
while (true) {
|
|
24
|
+
const byte = Number(n & 0x7F)
|
|
25
|
+
n >>= 7
|
|
26
|
+
if ((n === 0 && (byte & 0x40) === 0) || (n === -1 && (byte & 0x40) !== 0)) {
|
|
27
|
+
buffer.push(byte)
|
|
28
|
+
break
|
|
29
|
+
}
|
|
30
|
+
buffer.push((byte | 0x80))
|
|
31
|
+
}
|
|
32
|
+
return buffer
|
|
33
|
+
}
|
|
34
|
+
// alias
|
|
35
|
+
export const i8 = i32, i16 = i32
|
|
36
|
+
|
|
37
|
+
i32.parse = n => parseInt(n.replaceAll('_', ''))
|
|
38
|
+
|
|
39
|
+
// bigleb
|
|
40
|
+
export function i64(n, buffer = []) {
|
|
41
|
+
if (typeof n === 'string') n = i64.parse(n)
|
|
42
|
+
|
|
43
|
+
while (true) {
|
|
44
|
+
const byte = Number(n & 0x7Fn)
|
|
45
|
+
n >>= 7n
|
|
46
|
+
if ((n === 0n && (byte & 0x40) === 0) || (n === -1n && (byte & 0x40) !== 0)) {
|
|
47
|
+
buffer.push(byte)
|
|
48
|
+
break
|
|
49
|
+
}
|
|
50
|
+
buffer.push((byte | 0x80))
|
|
51
|
+
}
|
|
52
|
+
return buffer
|
|
53
|
+
}
|
|
54
|
+
i64.parse = n => {
|
|
55
|
+
n = n.replaceAll('_', '')
|
|
56
|
+
n = n[0] === '-' ? -BigInt(n.slice(1)) : BigInt(n)
|
|
57
|
+
byteView.setBigInt64(0, n)
|
|
58
|
+
return n = byteView.getBigInt64(0)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const byteView = new DataView(new BigInt64Array(1).buffer)
|
|
62
|
+
|
|
63
|
+
const F32_SIGN = 0x80000000, F32_NAN = 0x7f800000
|
|
64
|
+
export function f32(input, value, idx) {
|
|
65
|
+
if (~(idx = input.indexOf('nan:'))) {
|
|
66
|
+
value = parseInt(input.slice(idx + 4))
|
|
67
|
+
value |= F32_NAN
|
|
68
|
+
if (input[0] === '-') value |= F32_SIGN
|
|
69
|
+
byteView.setInt32(0, value)
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
value = typeof input === 'string' ? f32.parse(input) : input
|
|
73
|
+
byteView.setFloat32(0, value);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return [
|
|
77
|
+
byteView.getUint8(3),
|
|
78
|
+
byteView.getUint8(2),
|
|
79
|
+
byteView.getUint8(1),
|
|
80
|
+
byteView.getUint8(0)
|
|
81
|
+
];
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const F64_SIGN = 0x8000000000000000n, F64_NAN = 0x7ff0000000000000n
|
|
85
|
+
export function f64(input, value, idx) {
|
|
86
|
+
if (~(idx = input.indexOf('nan:'))) {
|
|
87
|
+
value = BigInt(input.slice(idx + 4))
|
|
88
|
+
value |= F64_NAN
|
|
89
|
+
if (input[0] === '-') value |= F64_SIGN
|
|
90
|
+
byteView.setBigInt64(0, value)
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
value = typeof input === 'string' ? f64.parse(input) : input
|
|
94
|
+
byteView.setFloat64(0, value);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return [
|
|
98
|
+
byteView.getUint8(7),
|
|
99
|
+
byteView.getUint8(6),
|
|
100
|
+
byteView.getUint8(5),
|
|
101
|
+
byteView.getUint8(4),
|
|
102
|
+
byteView.getUint8(3),
|
|
103
|
+
byteView.getUint8(2),
|
|
104
|
+
byteView.getUint8(1),
|
|
105
|
+
byteView.getUint8(0)
|
|
106
|
+
];
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
f32.parse = f64.parse = input => {
|
|
110
|
+
if (input.includes('nan')) return input[0] === '-' ? -NaN : NaN;
|
|
111
|
+
if (input.includes('inf')) return input[0] === '-' ? -Infinity : Infinity;
|
|
112
|
+
|
|
113
|
+
input = input.replaceAll('_', '')
|
|
114
|
+
|
|
115
|
+
// 0x1.5p3
|
|
116
|
+
if (input.includes('0x')) {
|
|
117
|
+
let [sig, exp] = input.split(/p/i), [dec, fract] = sig.split('.'), sign = dec[0] === '-' ? -1 : 1
|
|
118
|
+
sig = parseInt(dec) * sign + (fract ? parseInt(fract, 16) / (16 ** fract.length) : 0)
|
|
119
|
+
return sign * (exp ? sig * 2 ** parseInt(exp, 10) : sig);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return parseFloat(input)
|
|
123
|
+
}
|
package/src/util.js
CHANGED
|
@@ -1,116 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
export const uleb = (n, buffer = []) => {
|
|
3
|
-
if (typeof n === 'string') n = parseInt(n.replaceAll('_', ''))
|
|
1
|
+
export const TypedArray = { i64: BigInt64Array, i32: Int32Array, i16: Int16Array, i8: Int8Array, f64: Float64Array, f32: Float32Array }
|
|
4
2
|
|
|
5
|
-
|
|
6
|
-
n = n >>> 7;
|
|
7
|
-
|
|
8
|
-
if (n === 0) {
|
|
9
|
-
buffer.push(byte);
|
|
10
|
-
return buffer;
|
|
11
|
-
} else {
|
|
12
|
-
buffer.push(byte | 0b10000000);
|
|
13
|
-
return uleb(n, buffer);
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export function leb(n, buffer = []) {
|
|
18
|
-
if (typeof n === 'string') n = parseInt(n.replaceAll('_', ''))
|
|
19
|
-
|
|
20
|
-
while (true) {
|
|
21
|
-
const byte = Number(n & 0x7F)
|
|
22
|
-
n >>= 7
|
|
23
|
-
if ((n === 0 && (byte & 0x40) === 0) || (n === -1 && (byte & 0x40) !== 0)) {
|
|
24
|
-
buffer.push(byte)
|
|
25
|
-
break
|
|
26
|
-
}
|
|
27
|
-
buffer.push((byte | 0x80))
|
|
28
|
-
}
|
|
29
|
-
return buffer
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export function bigleb(n, buffer = []) {
|
|
33
|
-
if (typeof n === 'string') {
|
|
34
|
-
n = n.replaceAll('_', '')
|
|
35
|
-
n = n[0] === '-' ? -BigInt(n.slice(1)) : BigInt(n)
|
|
36
|
-
byteView.setBigInt64(0, n)
|
|
37
|
-
n = byteView.getBigInt64(0)
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
while (true) {
|
|
41
|
-
const byte = Number(n & 0x7Fn)
|
|
42
|
-
n >>= 7n
|
|
43
|
-
if ((n === 0n && (byte & 0x40) === 0) || (n === -1n && (byte & 0x40) !== 0)) {
|
|
44
|
-
buffer.push(byte)
|
|
45
|
-
break
|
|
46
|
-
}
|
|
47
|
-
buffer.push((byte | 0x80))
|
|
48
|
-
}
|
|
49
|
-
return buffer
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// generalized float cases parser
|
|
53
|
-
const flt = input => {
|
|
54
|
-
if (input.includes('nan')) return input[0] === '-' ? -NaN : NaN;
|
|
55
|
-
if (input.includes('inf')) return input[0] === '-' ? -Infinity : Infinity;
|
|
56
|
-
|
|
57
|
-
input = input.replaceAll('_', '')
|
|
58
|
-
|
|
59
|
-
// 0x1.5p3
|
|
60
|
-
if (input.includes('0x')) {
|
|
61
|
-
let [sig, exp] = input.split(/p/i), [dec, fract] = sig.split('.'), sign = dec[0] === '-' ? -1 : 1
|
|
62
|
-
sig = parseInt(dec) * sign + (fract ? parseInt(fract, 16) / (16 ** fract.length) : 0)
|
|
63
|
-
return sign * (exp ? sig * 2 ** parseInt(exp, 10) : sig);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
return parseFloat(input)
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
const byteView = new DataView(new BigInt64Array(1).buffer)
|
|
71
|
-
|
|
72
|
-
const F32_SIGN = 0x80000000, F32_NAN = 0x7f800000
|
|
73
|
-
export function f32(input, value, idx) {
|
|
74
|
-
if (~(idx = input.indexOf('nan:'))) {
|
|
75
|
-
value = parseInt(input.slice(idx + 4))
|
|
76
|
-
value |= F32_NAN
|
|
77
|
-
if (input[0] === '-') value |= F32_SIGN
|
|
78
|
-
byteView.setInt32(0, value)
|
|
79
|
-
}
|
|
80
|
-
else {
|
|
81
|
-
value = typeof input === 'string' ? flt(input) : input
|
|
82
|
-
byteView.setFloat32(0, value);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
return [
|
|
86
|
-
byteView.getUint8(3),
|
|
87
|
-
byteView.getUint8(2),
|
|
88
|
-
byteView.getUint8(1),
|
|
89
|
-
byteView.getUint8(0)
|
|
90
|
-
];
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
const F64_SIGN = 0x8000000000000000n, F64_NAN = 0x7ff0000000000000n
|
|
94
|
-
export function f64(input, value, idx) {
|
|
95
|
-
if (~(idx = input.indexOf('nan:'))) {
|
|
96
|
-
value = BigInt(input.slice(idx + 4))
|
|
97
|
-
value |= F64_NAN
|
|
98
|
-
if (input[0] === '-') value |= F64_SIGN
|
|
99
|
-
byteView.setBigInt64(0, value)
|
|
100
|
-
}
|
|
101
|
-
else {
|
|
102
|
-
value = typeof input === 'string' ? flt(input) : input
|
|
103
|
-
byteView.setFloat64(0, value);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
return [
|
|
107
|
-
byteView.getUint8(7),
|
|
108
|
-
byteView.getUint8(6),
|
|
109
|
-
byteView.getUint8(5),
|
|
110
|
-
byteView.getUint8(4),
|
|
111
|
-
byteView.getUint8(3),
|
|
112
|
-
byteView.getUint8(2),
|
|
113
|
-
byteView.getUint8(1),
|
|
114
|
-
byteView.getUint8(0)
|
|
115
|
-
];
|
|
116
|
-
}
|
|
3
|
+
export const err = text => { throw Error(text) }
|