Skip to content

Commit

Permalink
Make better use of vec
Browse files Browse the repository at this point in the history
  • Loading branch information
dy committed Dec 30, 2024
1 parent e36f516 commit 6a9fd90
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 44 deletions.
2 changes: 1 addition & 1 deletion readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,9 @@ print(src, {
* [x] [simd](https://github.com/WebAssembly/simd/blob/master/proposals/simd/SIMD.md)
* [x] [relaxed simd](https://github.com/WebAssembly/relaxed-simd)
* [x] [fixed-width simd](https://github.com/WebAssembly/simd/blob/master/proposals/simd/SIMD.md)
* [x] [tail_call](https://github.com/WebAssembly/tail-call)
* [x] [ref types](https://github.com/WebAssembly/reference-types/blob/master/proposals/reference-types/Overview.md)
* [ ] [func refs](https://github.com/WebAssembly/function-references/blob/main/proposals/function-references/Overview.md)
* [x] [tail_call](https://github.com/WebAssembly/tail-call)
* [ ] [gc](https://github.com/WebAssembly/gc)
* [ ] [exceptions](https://github.com/WebAssembly/exception-handling)
* [ ] [memory64](https://github.com/WebAssembly/memory64)
Expand Down
38 changes: 19 additions & 19 deletions src/compile.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ export default function watr(nodes) {
// convert nodes to bytes
const bin = (kind, count = true) => {
let items = sections[kind].filter(Boolean).map(item => build[kind](item, sections))
return !items.length ? [] : [kind, ...vec([...(count ? uleb(items.length) : []), ...items.flat()])]
return !items.length ? [] : [kind, ...vec(count ? vec(items) : items)]
}

// build final binary
Expand Down Expand Up @@ -289,11 +289,11 @@ const build = [,
details = limits(dfn)
}
else if (kind === 'global') {
let [type] = dfn, mut = type[0] === 'mut' ? 1 : 0
details = [TYPE[mut ? type[1] : type], mut]
let [t] = dfn, mut = t[0] === 'mut' ? 1 : 0
details = [...type(mut ? t[1] : t, ctx), mut]
}
else if (kind === 'table') {
details = [TYPE[dfn.pop()], ...limits(dfn)]
details = [...type(dfn.pop(), ctx), ...limits(dfn)]
}

return ([...vec(str(mod.slice(1, -1))), ...vec(str(field.slice(1, -1))), KIND[kind], ...details])
Expand All @@ -303,24 +303,24 @@ const build = [,
([[, typeidx]], ctx) => (uleb(id(typeidx, ctx.type))),

// (table id? 1 2? funcref)
(node, ctx) => ([TYPE[node.pop()], ...limits(node)]),
(node, ctx) => ([...type(node.pop(), ctx), ...limits(node)]),

// (memory id? export* min max shared)
(node, ctx) => limits(node),

// (global $id? (mut i32) (i32.const 42))
(node, ctx) => {
let [type] = node, mut = type[0] === 'mut' ? 1 : 0
let [t] = node, mut = t[0] === 'mut' ? 1 : 0

let [, init] = node
return ([TYPE[mut ? type[1] : type], mut, ...expr(init, ctx), 0x0b])
return ([...type(mut ? t[1] : t, ctx), mut, ...expr(init, ctx), 0x0b])
},

// (export "name" (func|table|mem $name|idx))
([nm, [kind, l]], ctx) => ([...vec(str(nm.slice(1, -1))), KIND[kind], ...uleb(id(l, ctx[kind]))]),

// (start $main)
([l], ctx) => (uleb(id(l, ctx.func))),
([l], ctx) => uleb(id(l, ctx.func)),

// (elem elem*) - passive
// (elem declare elem*) - declarative
Expand Down Expand Up @@ -386,13 +386,13 @@ const build = [,
// 0b111 et:reftype el*:vec(expr) | type=et, init el*, passive declare
[TYPE[reftype]]
),
...uleb(parts.length),
...parts.flatMap(mode & 0b100 ?
// ((ref.func y)end)*
el => [...expr(typeof el === 'string' ? ['ref.func', el] : el, ctx), 0x0b] :
// el*
el => uleb(id(el, ctx.func))
)
...vec(
parts.map(mode & 0b100 ?
// ((ref.func y)end)*
el => [...expr(typeof el === 'string' ? ['ref.func', el] : el, ctx), 0x0b] :
// el*
el => uleb(id(el, ctx.func))
))
])
},

Expand All @@ -413,7 +413,7 @@ const build = [,
while (body[0]?.[0] === 'local') {
let [, ...types] = body.shift()
if (types[0]?.[0] === '$') ctx.local[types.shift()] = ctx.local.length
ctx.local.push(...types.flatMap(t => type(t, ctx)))
ctx.local.push(...types)
}

const bytes = []
Expand All @@ -428,7 +428,7 @@ const build = [,
ctx.local = ctx.block = null

// https://webassembly.github.io/spec/core/binary/modules.html#code-section
return (vec([...uleb(loctypes.length), ...loctypes.flatMap(([n, t]) => [...uleb(n), t]), ...bytes]))
return vec([...vec(loctypes.map(([n, t]) => [...uleb(n), ...type(t, ctx)])), ...bytes])
},

// (data (i32.const 0) "\aa" "\bb"?)
Expand Down Expand Up @@ -469,7 +469,7 @@ const build = [,

// insert type, either direct or ref type
const type = (t, ctx) =>
t[0] === 'ref' ? ([t[1] == 'null' ? TYPE.refnull : TYPE.ref, ...uleb(TYPE[t[t.length - 1]] || id(t[t.length - 1], ctx.type))])
t[0] === 'ref' ? ([t[1] == 'null' ? TYPE.refnull : TYPE.ref, ...uleb(TYPE[t[t.length - 1]] || id(t[t.length - 1], ctx.type))])
: [TYPE[t] ?? err(`Unknown type ${t}`)]

// consume one instruction from nodes sequence
Expand Down Expand Up @@ -653,7 +653,7 @@ const instr = (nodes, ctx) => {
else if (code == 0x1b) {
let result = nodes.shift()
// 0x1b -> 0x1c
if (result.length) immed.push(immed.pop() + 1, ...uleb(result.length), ...result.flatMap(t => type(t, ctx)))
if (result.length) immed.push(immed.pop() + 1, ...vec(result.map(t => type(t, ctx))))
}

// ref.func $id
Expand Down
13 changes: 6 additions & 7 deletions test/compile.js
Original file line number Diff line number Diff line change
Expand Up @@ -2164,14 +2164,13 @@ t('feature: function refs', () => {
inline(src)

src=`
(module
(type $t (func))
(func (param $r (ref null $t)) (drop (block (result (ref $t)) (br_on_non_null 0 (local.get $r)) (unreachable))))
(func (param $r (ref null func)) (drop (block (result (ref func)) (br_on_non_null 0 (local.get $r)) (unreachable))))
(func (param $r (ref null extern)) (drop (block (result (ref extern)) (br_on_non_null 0 (local.get $r)) (unreachable))))
)
(type $t (func))
(func (param $r (ref null $t)) (drop (block (result (ref $t)) (br_on_non_null 0 (local.get $r)) (unreachable))))
(func (param $r (ref null func)) (drop (block (result (ref func)) (br_on_non_null 0 (local.get $r)) (unreachable))))
(func (param $r (ref null extern)) (drop (block (result (ref extern)) (br_on_non_null 0 (local.get $r)) (unreachable))))
`
inline(src)

})

// examples
Expand Down Expand Up @@ -2406,7 +2405,7 @@ export async function file(path, imports = {}) {
}

// save binary (asm buffer) to file
export const save = (buf) => {
export function save (buf) {
// Create a Blob
const blob = new Blob([buf], { type: "application/wasm" });

Expand Down
34 changes: 17 additions & 17 deletions test/testsuite.js
Original file line number Diff line number Diff line change
Expand Up @@ -177,28 +177,28 @@ t('/test/official/proposals/extended-const/global.wast', async function () { awa
t('/test/official/proposals/function-references/binary.wast', async function () { await file(this.name, { spectest }) })
t('/test/official/proposals/function-references/br_on_non_null.wast', async function () { await file(this.name, { spectest }) })
t.todo('/test/official/proposals/function-references/br_table.wast', async function () { await file(this.name, { spectest }) })
t.todo('/test/official/proposals/function-references/call_ref.wast', async function () { await file(this.name, { spectest }) })
t.todo('/test/official/proposals/function-references/data.wast', async function () { await file(this.name, { spectest }) })
t('/test/official/proposals/function-references/call_ref.wast', async function () { await file(this.name, { spectest }) })
t('/test/official/proposals/function-references/data.wast', async function () { await file(this.name, { spectest }) })
t.todo('/test/official/proposals/function-references/elem.wast', async function () { await file(this.name, { spectest }) })
t.todo('/test/official/proposals/function-references/func.wast', async function () { await file(this.name, { spectest }) })
t.todo('/test/official/proposals/function-references/global.wast', async function () { await file(this.name, { spectest }) })
t.todo('/test/official/proposals/function-references/if.wast', async function () { await file(this.name, { spectest }) })
t.todo('/test/official/proposals/function-references/linking.wast', async function () { await file(this.name, { spectest }) })
t.todo('/test/official/proposals/function-references/local_get.wast', async function () { await file(this.name, { spectest }) })
t.todo('/test/official/proposals/function-references/local_init.wast', async function () { await file(this.name, { spectest }) })
t.todo('/test/official/proposals/function-references/ref_as_non_null.wast', async function () { await file(this.name, { spectest }) })
t('/test/official/proposals/function-references/func.wast', async function () { await file(this.name, { spectest }) })
t('/test/official/proposals/function-references/global.wast', async function () { await file(this.name, { spectest }) })
t('/test/official/proposals/function-references/if.wast', async function () { await file(this.name, { spectest }) })
t('/test/official/proposals/function-references/linking.wast', async function () { await file(this.name, { spectest }) })
t('/test/official/proposals/function-references/local_get.wast', async function () { await file(this.name, { spectest }) })
t('/test/official/proposals/function-references/local_init.wast', async function () { await file(this.name, { spectest }) })
t('/test/official/proposals/function-references/ref_as_non_null.wast', async function () { await file(this.name, { spectest }) })
t.todo('/test/official/proposals/function-references/ref_is_null.wast', async function () { await file(this.name, { spectest }) })
t.todo('/test/official/proposals/function-references/ref_null.wast', async function () { await file(this.name, { spectest }) })
t.todo('/test/official/proposals/function-references/ref.wast', async function () { await file(this.name, { spectest }) })
t.todo('/test/official/proposals/function-references/return_call_indirect.wast', async function () { await file(this.name, { spectest }) })
t.todo('/test/official/proposals/function-references/return_call_ref.wast', async function () { await file(this.name, { spectest }) })
t.todo('/test/official/proposals/function-references/return_call.wast', async function () { await file(this.name, { spectest }) })
t('/test/official/proposals/function-references/ref_null.wast', async function () { await file(this.name, { spectest }) })
t('/test/official/proposals/function-references/ref.wast', async function () { await file(this.name, { spectest }) })
t('/test/official/proposals/function-references/return_call_indirect.wast', async function () { await file(this.name, { spectest }) })
t('/test/official/proposals/function-references/return_call_ref.wast', async function () { await file(this.name, { spectest }) })
t('/test/official/proposals/function-references/return_call.wast', async function () { await file(this.name, { spectest }) })
t.todo('/test/official/proposals/function-references/select.wast', async function () { await file(this.name, { spectest }) })
t.todo('/test/official/proposals/function-references/table-sub.wast', async function () { await file(this.name, { spectest }) })
t('/test/official/proposals/function-references/table-sub.wast', async function () { await file(this.name, { spectest }) })
t.todo('/test/official/proposals/function-references/table.wast', async function () { await file(this.name, { spectest }) })
t.todo('/test/official/proposals/function-references/type-equivalence.wast', async function () { await file(this.name, { spectest }) })
t.todo('/test/official/proposals/function-references/unreached-invalid.wast', async function () { await file(this.name, { spectest }) })
t.todo('/test/official/proposals/function-references/unreached-valid.wast', async function () { await file(this.name, { spectest }) })
t('/test/official/proposals/function-references/unreached-invalid.wast', async function () { await file(this.name, { spectest }) })
t('/test/official/proposals/function-references/unreached-valid.wast', async function () { await file(this.name, { spectest }) })

t.todo('/test/official/proposals/gc/try_table.wast', async function () { await file(this.name, { spectest }) })

Expand Down

0 comments on commit 6a9fd90

Please sign in to comment.