watr 0.0.0 → 1.0.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/example/amp.wasm +0 -0
- package/example/amp.wat +81 -0
- package/example/array.wat +26 -0
- package/example/global.wasm +0 -0
- package/example/global.wat +28 -0
- package/example/loops.wasm +0 -0
- package/example/loops.wat +34 -0
- package/example/memory.wasm +0 -0
- package/example/memory.wat +34 -0
- package/example/multivar.wasm +0 -0
- package/example/multivar.wat +13 -0
- package/example/stack.wasm +0 -0
- package/example/stack.wat +38 -0
- package/example/table.wasm +0 -0
- package/example/table.wat +24 -0
- package/example/types.wasm +0 -0
- package/example/types.wat +21 -0
- package/lib/wabt.js +36 -0
- package/lib/wat-compiler.js +1 -0
- package/package.json +14 -4
- package/plan.md +21 -0
- package/readme.md +145 -0
- package/repl.html +44 -0
- package/src/compile.js +456 -0
- package/src/parse.js +31 -0
- package/src/watr.js +8 -0
- package/test/compile.js +1090 -0
- package/test/examples.js +155 -0
- package/test/index.html +14 -0
- package/test/index.js +2 -0
- package/test/parse.js +179 -0
- package/watr.js +428 -0
- package/watr.min.js +1 -0
package/test/examples.js
ADDED
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import fs from 'fs'
|
|
2
|
+
import t from 'tst'
|
|
3
|
+
|
|
4
|
+
t.only('table', () => {
|
|
5
|
+
var buffer = fs.readFileSync('./table.wasm');
|
|
6
|
+
const mod = new WebAssembly.Module(buffer)
|
|
7
|
+
const instance = new WebAssembly.Instance(mod)
|
|
8
|
+
|
|
9
|
+
// console.time('instantiate')
|
|
10
|
+
// for (let i = 0; i < 30000; i++) new WebAssembly.Instance(mod)
|
|
11
|
+
// console.timeEnd('instantiate')
|
|
12
|
+
// 290ms to instantiate 30k modules
|
|
13
|
+
|
|
14
|
+
const {callByIndex, getByIndex} = instance.exports
|
|
15
|
+
|
|
16
|
+
console.log(callByIndex(0)) // => 42
|
|
17
|
+
console.log(callByIndex(1)) // => 13
|
|
18
|
+
// console.log(callByIndex(2)) // => error
|
|
19
|
+
|
|
20
|
+
let fn = getByIndex(0)
|
|
21
|
+
console.log(fn, fn?.())
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
t('global', () => {
|
|
25
|
+
var buf = fs.readFileSync('./global.wasm')
|
|
26
|
+
const mod = new WebAssembly.Module(buf)
|
|
27
|
+
const importObj = {
|
|
28
|
+
"js": {
|
|
29
|
+
"log": arg=>console.log(arg),
|
|
30
|
+
"g1": new WebAssembly.Global({value: 'i32', mutable: true}, 123)
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
console.log(importObj.js.g1)
|
|
35
|
+
const instance = new WebAssembly.Instance(mod, importObj)
|
|
36
|
+
const {getG1, setG1, getG0} = instance.exports
|
|
37
|
+
|
|
38
|
+
// console.log(getG0())
|
|
39
|
+
console.log(getG1())
|
|
40
|
+
setG1(100)
|
|
41
|
+
console.log(getG1())
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
t('stack', () => {
|
|
46
|
+
var buf = fs.readFileSync('./stack.wasm')
|
|
47
|
+
const mod = new WebAssembly.Module(buf)
|
|
48
|
+
const importObj = {"js": {}}
|
|
49
|
+
const instance = new WebAssembly.Instance(mod, importObj)
|
|
50
|
+
const {get, swap, mul} = instance.exports
|
|
51
|
+
console.log(mul(12,13))
|
|
52
|
+
// console.log(swap(1,2,3,4))
|
|
53
|
+
// console.log(get())
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
t('memory', () => {
|
|
57
|
+
var buf = fs.readFileSync('./memory.wasm')
|
|
58
|
+
const mod = new WebAssembly.Module(buf)
|
|
59
|
+
const mem = new WebAssembly.Memory({ initial: 1 })
|
|
60
|
+
|
|
61
|
+
const importObj = {
|
|
62
|
+
js: { log: arg=>console.log(arg) }
|
|
63
|
+
}
|
|
64
|
+
const instance = new WebAssembly.Instance(mod, importObj)
|
|
65
|
+
const api = instance.exports
|
|
66
|
+
|
|
67
|
+
console.log(mem.buffer)
|
|
68
|
+
// console.log(api.mem, api.g)
|
|
69
|
+
|
|
70
|
+
// api.populate()
|
|
71
|
+
// let view = new DataView(mem.buffer)
|
|
72
|
+
// view.setInt16(1, 123)
|
|
73
|
+
let i32 = new Int32Array(mem.buffer)
|
|
74
|
+
i32[1] = 123
|
|
75
|
+
console.log(api.get(4))
|
|
76
|
+
api.set(4,2)
|
|
77
|
+
console.log(api.get(4))
|
|
78
|
+
|
|
79
|
+
// grow by one page
|
|
80
|
+
// console.log(mem.grow(4))
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
t('loop', () => {
|
|
86
|
+
var buf = fs.readFileSync('./loops.wasm')
|
|
87
|
+
const mod = new WebAssembly.Module(buf)
|
|
88
|
+
// const mem = new WebAssembly.Memory({ initial:1 })
|
|
89
|
+
// const f32mem = new Float32Array(mem.buffer)
|
|
90
|
+
const importObj = {console: {log:(arg)=>console.log(arg)}}
|
|
91
|
+
const instance = new WebAssembly.Instance(mod, importObj)
|
|
92
|
+
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
t('amp bench', () => {
|
|
97
|
+
const BLOCK = 1024
|
|
98
|
+
var buf = fs.readFileSync('./array.wasm')
|
|
99
|
+
const mod = new WebAssembly.Module(buf)
|
|
100
|
+
const mem = new WebAssembly.Memory({ initial:1 })
|
|
101
|
+
const blockSize = new WebAssembly.Global({value: 'i32', mutable: true}, BLOCK)
|
|
102
|
+
// blockSize.value
|
|
103
|
+
const f32mem = new Float32Array(mem.buffer)
|
|
104
|
+
const importObj = {js: {mem, blockSize}, console:{log(a,b){console.log(a,b)}}}
|
|
105
|
+
const instance = new WebAssembly.Instance(mod, importObj)
|
|
106
|
+
const {amp, ampMulti, ampShort} = instance.exports
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
let src = Array.from({length:BLOCK}, (a,i)=>i)
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
f32mem.set(src)
|
|
113
|
+
amp('2')
|
|
114
|
+
console.log(f32mem)
|
|
115
|
+
|
|
116
|
+
const MAX = 1e5
|
|
117
|
+
f32mem.set(src)
|
|
118
|
+
console.time('warmup')
|
|
119
|
+
for (let i = 0; i < MAX; i++) amp(.5)
|
|
120
|
+
console.timeEnd('warmup')
|
|
121
|
+
|
|
122
|
+
f32mem.set(src)
|
|
123
|
+
console.time('wasm amp')
|
|
124
|
+
for (let i = 0; i < MAX; i++) amp(.5)
|
|
125
|
+
console.timeEnd('wasm amp')
|
|
126
|
+
|
|
127
|
+
f32mem.set(src)
|
|
128
|
+
console.time('wasm amp multivariable')
|
|
129
|
+
for (let i = 0; i < MAX; i++) ampMulti(.5)
|
|
130
|
+
console.timeEnd('wasm amp multivariable')
|
|
131
|
+
|
|
132
|
+
f32mem.set(src)
|
|
133
|
+
console.time('wasm short')
|
|
134
|
+
for (let i = 0; i < MAX; i++) ampShort(.5)
|
|
135
|
+
console.timeEnd('wasm short')
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
console.time('js amp')
|
|
139
|
+
for (let i = 0; i < MAX; i++) for (let j = 0; j < src.length; j++) src[j]*=.5
|
|
140
|
+
console.timeEnd('js amp')
|
|
141
|
+
})
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
t('types', () => {
|
|
146
|
+
var buf = fs.readFileSync('./types.wasm')
|
|
147
|
+
const mod = new WebAssembly.Module(buf)
|
|
148
|
+
// const mem = new WebAssembly.Memory({ initial:1 })
|
|
149
|
+
// const f32mem = new Float32Array(mem.buffer)
|
|
150
|
+
const importObj = {console: {log:(...abc)=>console.log(...abc)}}
|
|
151
|
+
const instance = new WebAssembly.Instance(mod, importObj)
|
|
152
|
+
const {run} = instance.exports
|
|
153
|
+
|
|
154
|
+
console.log(run(123, 13.3, 'abc'))
|
|
155
|
+
})
|
package/test/index.html
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<doctype html>
|
|
2
|
+
|
|
3
|
+
<script type="importmap">
|
|
4
|
+
{
|
|
5
|
+
"imports": {
|
|
6
|
+
"tst": "../node_modules/tst/tst.js",
|
|
7
|
+
"subscript": "../../subscript/subscript.js",
|
|
8
|
+
"subscript/parse.js": "../node_modules/subscript/parse.js"
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
</script>
|
|
12
|
+
|
|
13
|
+
<script src="./parse.js" type="module"></script>
|
|
14
|
+
<script src="./compile.js" type="module"></script>
|
package/test/index.js
ADDED
package/test/parse.js
ADDED
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import t, { is, ok, same } from 'tst'
|
|
2
|
+
import parse from '../src/parse.js'
|
|
3
|
+
|
|
4
|
+
t('parser: s-expr', () => {
|
|
5
|
+
const tree = parse('(module)')
|
|
6
|
+
is(tree, ['module'])
|
|
7
|
+
})
|
|
8
|
+
|
|
9
|
+
t.skip('parser: s-expr no instruction (throws)', () => {
|
|
10
|
+
try {
|
|
11
|
+
parse('()')
|
|
12
|
+
} catch (error) {
|
|
13
|
+
ok(/Empty/.test(error.message))
|
|
14
|
+
return
|
|
15
|
+
}
|
|
16
|
+
throw 'Failed'
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
t('parser: s-expr named', () => {
|
|
20
|
+
const tree = parse('(module $hello)')
|
|
21
|
+
is(tree, ['module', '$hello'])
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
t('parser: ref labels as children', () => {
|
|
25
|
+
const tree = parse('(elem (i32.const 0) $f1 $f2)')
|
|
26
|
+
is(tree, ['elem', ['i32.const', '0'], '$f1', '$f2'])
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
t('parser: s-expr number params', () => {
|
|
30
|
+
const tree = parse('(memory 1 2)')
|
|
31
|
+
is(tree, ['memory', '1', '2'])
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
t('parser: s-expr number params + named params', () => {
|
|
35
|
+
const tree = parse('(memory 1 2 shared)')
|
|
36
|
+
is(tree, ['memory', '1', '2', 'shared'])
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
t('parser: s-expr named params with = value', () => {
|
|
40
|
+
const tree = parse('(i32.load offset=0 align=4)')
|
|
41
|
+
is(tree, ['i32.load', ['offset','0'], ['align','4']])
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
t('parser: stack instruction', () => {
|
|
45
|
+
const code = '(func i32.const 42)'
|
|
46
|
+
const tree = parse(code)
|
|
47
|
+
is(tree, ['func', 'i32.const', '42'])
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
t('parser: many stack instructions', () => {
|
|
51
|
+
const code = '(func i32.const 22 i32.const 20 i32.add)'
|
|
52
|
+
const tree = parse(code)
|
|
53
|
+
is(tree, ['func', 'i32.const', '22', 'i32.const', '20', 'i32.add'])
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
t('parser: children', () => {
|
|
57
|
+
const code = '(func $answer (result i32) (i32.add (i32.const 20) (i32.const 22)))'
|
|
58
|
+
const tree = parse(code)
|
|
59
|
+
is(tree, ['func', '$answer', ['result', 'i32'], ['i32.add', ['i32.const', '20'], ['i32.const', '22']]])
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
t('parser: minimal export function', () => {
|
|
63
|
+
const code = '(func (export "answer") (result i32) (i32.const 42))'
|
|
64
|
+
const tree = parse(code)
|
|
65
|
+
is(tree, ['func', ['export', '"answer"'], ['result', 'i32'], ['i32.const', '42']])
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
t.skip('parser: children', () => {
|
|
69
|
+
const code = String.raw`(data (i32.const 0) "\2a")`
|
|
70
|
+
const tree = parse(code)
|
|
71
|
+
console.log(code)
|
|
72
|
+
is(tree, ['data', ['i32.const', '0'], '"\\2a"'])
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
t('parse: instr', () => {
|
|
76
|
+
const tokens = parse('hello')
|
|
77
|
+
is(tokens, 'hello')
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
t('parse: param', () => {
|
|
81
|
+
const tokens = parse('align=4')
|
|
82
|
+
is(tokens, ['align', '4'])
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
t('parse: label', () => {
|
|
86
|
+
const tokens = parse('$$hi')
|
|
87
|
+
is(tokens, '$$hi')
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
t.skip('parse: string', () => {
|
|
91
|
+
const r = String.raw
|
|
92
|
+
const tokens = parse(r`"hello""ano\"t\n\ther""more"`)
|
|
93
|
+
expect(tokens).to.deep.equal([
|
|
94
|
+
{ value: 'hello', kind: 'string', index: 0 },
|
|
95
|
+
{ value: r`ano\"t\n\ther`, kind: 'string', index: 7 },
|
|
96
|
+
{ value: 'more', kind: 'string', index: 22 }
|
|
97
|
+
])
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
t('parse: number', () => {
|
|
101
|
+
const tokens = parse('123')
|
|
102
|
+
is(tokens, '123')
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
t('parse: hex', () => {
|
|
106
|
+
const tokens = parse('0xf2')
|
|
107
|
+
is(tokens, '0xf2')
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
t('parse: comments', () => {
|
|
111
|
+
const tokens = parse('(an (; inline ;) comment\n;; line comment\n1)')
|
|
112
|
+
is(tokens, ['an', 'comment', '1'])
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
t('parse: nul', () => {
|
|
116
|
+
const tokens = parse(' \n\t')
|
|
117
|
+
is(tokens, undefined)
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
t.skip('parse: error', () => {
|
|
121
|
+
try {
|
|
122
|
+
let tree = parse('§what')
|
|
123
|
+
} catch (e) {
|
|
124
|
+
ok(/syntax/.test(e.message))
|
|
125
|
+
}
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
t('parse: number', t => {
|
|
129
|
+
;[
|
|
130
|
+
'12',
|
|
131
|
+
'12.3',
|
|
132
|
+
'-12.3',
|
|
133
|
+
'+12.3',
|
|
134
|
+
'1e5',
|
|
135
|
+
'1.23e5',
|
|
136
|
+
'1.23e-5',
|
|
137
|
+
'1.23e+5',
|
|
138
|
+
'nan',
|
|
139
|
+
'inf',
|
|
140
|
+
'+inf',
|
|
141
|
+
'-inf',
|
|
142
|
+
].forEach(n => {
|
|
143
|
+
const tokens = parse(n)
|
|
144
|
+
is(tokens, n)
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
;[
|
|
148
|
+
'-0xf2',
|
|
149
|
+
'+0xf2',
|
|
150
|
+
'0xf2.ef',
|
|
151
|
+
'0xf2.ePf',
|
|
152
|
+
'0xf2.P-f',
|
|
153
|
+
'nan:0xff',
|
|
154
|
+
].forEach(n => {
|
|
155
|
+
const tokens = parse(n)
|
|
156
|
+
is(tokens, n)
|
|
157
|
+
})
|
|
158
|
+
})
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
t('parse: complex case 1', () => {
|
|
162
|
+
const tokens = parse(`(
|
|
163
|
+
(hello $hi
|
|
164
|
+
"world")
|
|
165
|
+
;; (should) be a comment
|
|
166
|
+
and (; another ;) line 0x312 43.23
|
|
167
|
+
)`)
|
|
168
|
+
is(tokens, [['hello', '$hi', '"world"'], 'and', 'line', '0x312', '43.23'])
|
|
169
|
+
})
|
|
170
|
+
|
|
171
|
+
t('parse: minimal function', () => {
|
|
172
|
+
let tokens = parse('(func (export "answer") (result i32) (i32.const 42))')
|
|
173
|
+
is(tokens, ['func', ['export', '"answer"'], ['result', 'i32'], ['i32.const', '42']])
|
|
174
|
+
})
|
|
175
|
+
|
|
176
|
+
t('parse: multiple functions', () => {
|
|
177
|
+
let tokens = parse('(func $a) (func $b)')
|
|
178
|
+
is(tokens, [['func','$a'],['func','$b']])
|
|
179
|
+
})
|