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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "watr",
3
- "version": "2.2.5",
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.1.1",
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 [![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)
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, light & fast alternative for [wat2wasm](https://github.com/AssemblyScript/wabt.js).<br/>
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
  &nbsp; | 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
- Compiles wasm text or syntax tree into wasm binary.
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] multiple values
103
- * [x] bulk memory ops (0 index)
104
- * [ ] func/ref types
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 { uleb, leb, bigleb, f64, f32 } from './util.js'
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 %= 252]
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 - just consume immed
138
- else if (opCode >= 69) { }
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 = { align: ALIGN[op], offset: 0 }, param
144
- while (args[0]?.includes('=')) param = args.shift().split('='), o[param[0]] = Number(param[1])
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 >= 65 && opCode <= 68) {
150
- immed = (opCode == 65 ? leb : opCode == 66 ? bigleb : opCode == 67 ? f32 : f64)(args.shift())
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 == 35 || opCode == 36) {
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, OP_END])
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, ...iinit(init)])
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, ...iinit(offset, ctx), ...uleb(elems.length), ...elems.flatMap(el => uleb(el[0] === '$' ? ctx.func[el] : el))])
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([, offset, ...inits], ctx) {
345
- // FIXME: first is mem index
346
- ctx.data.push([0, ...iinit(offset, ctx), ...str(inits.map(i => i[0] === '"' ? i.slice(1, -1) : i).join(''))])
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 iinit = ([op, literal], ctx) => op[0] === 'f' ?
357
- [op[1] === '3' ? OP_F32_CONST : OP_F64_CONST, ...(op[1] === '3' ? f32 : f64)(literal), OP_END] :
358
- [op[1] === '3' ? OP_I32_CONST : OP_I64_CONST, ...(op[1] === '3' ? leb : bigleb)(literal[0] === '$' ? ctx.global[literal] : literal), OP_END]
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
- const err = text => { throw Error(text) }
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
- // encoding ref: https://github.com/j-s-n/WebBS/blob/master/compiler/byteCode.js
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
- let byte = n & 0b01111111;
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) }