watr 2.3.0 → 2.4.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "watr",
3
- "version": "2.3.0",
3
+ "version": "2.4.0",
4
4
  "description": "Ligth & fast WAT compiler",
5
5
  "main": "watr.js",
6
6
  "exports": {
@@ -15,7 +15,7 @@
15
15
  },
16
16
  "repository": {
17
17
  "type": "git",
18
- "url": "git+https://github.com/audio-lab/watr.git"
18
+ "url": "git+https://github.com/dy/watr.git"
19
19
  },
20
20
  "files": [
21
21
  "src",
@@ -35,9 +35,9 @@
35
35
  "author": "Dmitry Iv",
36
36
  "license": "MIT",
37
37
  "bugs": {
38
- "url": "https://github.com/audio-lab/watr/issues"
38
+ "url": "https://github.com/dy/watr/issues"
39
39
  },
40
- "homepage": "https://github.com/audio-lab/watr#readme",
40
+ "homepage": "https://github.com/dy/watr#readme",
41
41
  "devDependencies": {
42
42
  "tst": "^7.3.0",
43
43
  "wabt": "^1.0.28",
package/readme.md CHANGED
@@ -1,18 +1,8 @@
1
1
  # watr [![test](https://github.com/audio-lab/watr/actions/workflows/test.js.yml/badge.svg)](https://github.com/audio-lab/watr/actions/workflows/test.js.yml) [![npm bundle size](https://img.shields.io/bundlephobia/minzip/watr/latest?color=brightgreen&label=gzip)](https://bundlephobia.com/package/watr) [![npm](https://img.shields.io/npm/v/watr?color=red)](https://npmjs.org/watr)
2
2
 
3
- Bare minimum wasm text compiler/formatter.<br/>
4
- A light & fast alternative to [wat2wasm](https://github.com/AssemblyScript/wabt.js).<br/>
3
+ Bare minimum wasm text compiler/formatter. A light & fast alternative to [wat2wasm](https://github.com/AssemblyScript/wabt.js).<br/>
5
4
  Useful for hi-level languages or dynamic (in-browser) compilation.<br>
6
5
 
7
- <!-- See [REPL](https://audio-lab.github.io/watr/repl.html).-->
8
-
9
- &nbsp; | Size (gzipped) | Performance (op/s)
10
- ---|---|---|---
11
- watr | 3.8 kb | 6000
12
- [wat-compiler](https://github.com/stagas/wat-compiler) | 6 kb | 348
13
- [wabt](https://github.com/AssemblyScript/wabt.js) | 300 kb | 574
14
- [wassemble](https://github.com/wingo/wassemble) | ? kb | ?
15
-
16
6
  ## Usage
17
7
 
18
8
  ### Compile
@@ -78,16 +68,27 @@ parse(`(func (export "double") (param f64) (result f64) (f64.mul (local.get 0) (
78
68
  // ]
79
69
  ```
80
70
 
71
+ <!-- See [REPL](https://audio-lab.github.io/watr/repl.html).-->
72
+
81
73
  ## Status
82
74
 
83
- * [x] wasm core
75
+ * [x] core
84
76
  * [x] [multi-value](https://github.com/WebAssembly/spec/blob/master/proposals/multi-value/Overview.md)
85
77
  * [x] [bulk memory ops](https://github.com/WebAssembly/bulk-memory-operations/blob/master/proposals/bulk-memory-operations/Overview.md)
86
78
  * [x] [simd](https://github.com/WebAssembly/simd/blob/master/proposals/simd/SIMD.md)
79
+ * [x] [extended const](https://github.com/WebAssembly/extended-const/blob/main/proposals/extended-const/Overview.md)
87
80
  * [ ] [multiple memories](https://github.com/WebAssembly/multi-memory/blob/master/proposals/multi-memory/Overview.md)
88
81
  * [ ] [func refs](https://github.com/WebAssembly/function-references/blob/main/proposals/function-references/Overview.md)
89
82
  * [ ] [gc](https://github.com/WebAssembly/gc)
90
83
 
84
+ ## Alternatives
85
+
86
+ &nbsp; | Size (gzipped) | Performance (op/s)
87
+ ---|---|---
88
+ watr | 5 kb | 6000
89
+ [wat-compiler](https://github.com/stagas/wat-compiler) | 6 kb | 348
90
+ [wabt](https://github.com/AssemblyScript/wabt.js) | 300 kb | 574
91
+ <!-- [wassemble](https://github.com/wingo/wassemble) | ? kb | ? -->
91
92
 
92
93
  <!--
93
94
  ## Projects using watr
package/src/compile.js CHANGED
@@ -2,7 +2,7 @@ import * as encode from './encode.js'
2
2
  import { uleb } from './encode.js'
3
3
  import { OP, SECTION, ALIGN, TYPE, KIND } from './const.js'
4
4
  import parse from './parse.js'
5
- import { err, TypedArray } from './util.js'
5
+ import { err } from './util.js'
6
6
 
7
7
 
8
8
  /**
@@ -139,9 +139,15 @@ const build = {
139
139
  // (v128.load_lane_zero)
140
140
  if (opCode <= 0x5b) immed.push(...uleb(args.shift()))
141
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))
142
+ // (i8x16.shuffle 0 1 ... 15 a b)
143
+ else if (opCode === 0x0d) {
144
+ // i8, i16, i32 - bypass the encoding
145
+ for (let i = 0; i < 16; i++) immed.push(encode.i32.parse(args.shift()))
146
+ }
147
+ // (v128.const i32x4)
148
+ else if (opCode === 0x0c) {
149
+ args.unshift(op)
150
+ immed = consumeConst(args, ctx)
145
151
  }
146
152
  // (i8x16.extract_lane_s 0 ...)
147
153
  else if (opCode >= 0x15 && opCode <= 0x22) {
@@ -310,8 +316,8 @@ const build = {
310
316
  global([, ...args], ctx) {
311
317
  let name = args[0][0] === '$' && args.shift()
312
318
  if (name) ctx.global[name] = ctx.global.length
313
- let [type, init] = args, mut = type[0] === 'mut' ? 1 : 0
314
- ctx.global.push([TYPE[mut ? type[1] : type], mut, ...initGlobal(init)])
319
+ let [type, [...init]] = args, mut = type[0] === 'mut' ? 1 : 0
320
+ ctx.global.push([TYPE[mut ? type[1] : type], mut, ...consumeConst(init, ctx), 0x0b])
315
321
  },
316
322
 
317
323
  // (table 1 2? funcref)
@@ -324,9 +330,9 @@ const build = {
324
330
  },
325
331
 
326
332
  // (elem (i32.const 0) $f1 $f2), (elem (global.get 0) $f1 $f2)
327
- elem([, offset, ...elems], ctx) {
333
+ elem([, [...offset], ...elems], ctx) {
328
334
  const tableIdx = 0 // FIXME: table index can be defined
329
- ctx.elem.push([tableIdx, ...initGlobal(offset, ctx), ...uleb(elems.length), ...elems.flatMap(el => uleb(el[0] === '$' ? ctx.func[el] : el))])
335
+ ctx.elem.push([tableIdx, ...consumeConst(offset, ctx), 0x0b, ...uleb(elems.length), ...elems.flatMap(el => uleb(el[0] === '$' ? ctx.func[el] : el))])
330
336
  },
331
337
 
332
338
  // (export "name" (kind $name|idx))
@@ -379,7 +385,7 @@ const build = {
379
385
  if (!offset && !mem) offset = inits.shift()
380
386
  if (!offset) offset = ['i32.const', 0]
381
387
 
382
- ctx.data.push([0, ...initGlobal(offset, ctx), ...str(inits.map(i => i[0] === '"' ? i.slice(1, -1) : i).join(''))])
388
+ ctx.data.push([0, ...consumeConst([...offset], ctx), 0x0b, ...str(inits.map(i => i[0] === '"' ? i.slice(1, -1) : i).join(''))])
383
389
  },
384
390
 
385
391
  // (start $main)
@@ -388,30 +394,50 @@ const build = {
388
394
  }
389
395
  }
390
396
 
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('.')
397
+ // instantiation time const initializer
398
+ const consumeConst = (node, ctx) => {
399
+ let op = node.shift(), [type, cmd] = op.split('.')
400
+
401
+ // (global.get idx)
402
+ if (type === 'global') return [0x23, ...uleb(node[0][0] === '$' ? ctx.global[node[0]] : node[0])]
403
+
395
404
  // (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]
405
+ if (type === 'v128') return [0xfd, 0x0c, ...v128(node)]
406
+
407
+ // (i32.const 1)
408
+ if (cmd === 'const') return [0x41 + ['i32', 'i64', 'f32', 'f64'].indexOf(type), ...encode[type](node[0])]
409
+
410
+ // (i32.add a b), (i32.mult a b) etc
411
+ return [
412
+ ...consumeConst(node.shift(), ctx),
413
+ ...consumeConst(node.shift(), ctx),
414
+ OP.indexOf(op)
415
+ ]
397
416
  }
398
417
 
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)
418
+ // (v128.const i32x4 1 2 3 4)
419
+ const v128 = (args) => {
420
+ let [t, n] = args.shift().split('x'),
421
+ stride = t.slice(1) >>> 3 // i16 -> 2, f32 -> 4
422
+
423
+ n = +n
406
424
 
425
+ // i8, i16, i32 - bypass the encoding
426
+ if (t[0] === 'i') {
427
+ let arr = n === 16 ? new Uint8Array(16) : n === 8 ? new Uint16Array(8) : n === 4 ? new Uint32Array(4) : new BigInt64Array(2)
407
428
  for (let i = 0; i < n; i++) {
408
429
  arr[i] = encode[t].parse(args.shift())
409
430
  }
431
+ return new Uint8Array(arr.buffer)
432
+ }
410
433
 
411
- return bytes
434
+ // f32, f64 - encode
435
+ let arr = new Uint8Array(16)
436
+ for (let i = 0; i < n; i++) {
437
+ arr.set(encode[t](args.shift()), i * stride)
412
438
  }
413
- // (i32.const 1)
414
- return encode[type](args[0])
439
+
440
+ return arr
415
441
  }
416
442
 
417
443
  // escape codes
package/src/encode.js CHANGED
@@ -63,7 +63,7 @@ const byteView = new DataView(new BigInt64Array(1).buffer)
63
63
  const F32_SIGN = 0x80000000, F32_NAN = 0x7f800000
64
64
  export function f32(input, value, idx) {
65
65
  if (~(idx = input.indexOf('nan:'))) {
66
- value = parseInt(input.slice(idx + 4))
66
+ value = i32.parse(input.slice(idx + 4))
67
67
  value |= F32_NAN
68
68
  if (input[0] === '-') value |= F32_SIGN
69
69
  byteView.setInt32(0, value)
@@ -84,7 +84,7 @@ export function f32(input, value, idx) {
84
84
  const F64_SIGN = 0x8000000000000000n, F64_NAN = 0x7ff0000000000000n
85
85
  export function f64(input, value, idx) {
86
86
  if (~(idx = input.indexOf('nan:'))) {
87
- value = BigInt(input.slice(idx + 4))
87
+ value = i64.parse(input.slice(idx + 4))
88
88
  value |= F64_NAN
89
89
  if (input[0] === '-') value |= F64_SIGN
90
90
  byteView.setBigInt64(0, value)
package/src/parse.js CHANGED
@@ -17,13 +17,14 @@ export default (str) => {
17
17
 
18
18
  const parseLevel = () => {
19
19
  for (let c, root; i < str.length;) {
20
+
20
21
  c = str.charCodeAt(i)
21
22
  if (c === DQUOTE) commit(), buf = str.slice(i++, i = str.indexOf('"', i) + 1), commit()
22
23
  else if (c === OPAREN) {
23
24
  if (str.charCodeAt(i + 1) === SEMIC) i = str.indexOf(';)', i) + 2 // (; ... ;)
24
25
  else commit(), i++, (root = level).push(level = []), parseLevel(), level = root
25
26
  }
26
- else if (c === SEMIC) i = str.indexOf('\n', i) + 1 // ; ...
27
+ else if (c === SEMIC) i = str.indexOf('\n', i) + 1 || str.length // ; ...
27
28
  else if (c <= SPACE) commit(), i++
28
29
  else if (c === CPAREN) return commit(), i++
29
30
  else buf += str[i++]
package/src/util.js CHANGED
@@ -1,3 +1 @@
1
- export const TypedArray = { i64: BigInt64Array, i32: Int32Array, i16: Int16Array, i8: Int8Array, f64: Float64Array, f32: Float32Array }
2
-
3
1
  export const err = text => { throw Error(text) }