mirror of
https://github.com/hanzoai/wasm2go.git
synced 2026-10-30 15:06:48 +00:00
* gcasm: fix cross-chunk symbol gaps in the direct-call path Follow-ups to the direct cross-chunk asm calls change (#61): - The direct-asm resolvers (CalleeSymbol / MemHelperSymbol) trimmed calleeSig's leading "·" and let asmgen's goAsmSymbol re-derive the CALL operand. A spelled remote symbol ("github·com∕...∕p2·Fn0") has no ASCII "." for goAsmSymbol to split on, so it was re-wrapped as a current-package reference ("CALL ·github·com∕...(SB)") that can never link — any direct-asm-retained function making a resolved cross-chunk call produced an undefined symbol at consumer link time. The resolver contract now carries the exact plan 9 operand (without the "(SB)" suffix) and asmgen emits it verbatim. - plan9AsmPathSafe accepted digit-leading import paths ("4d63.com/...", "0xacab.org/..."), but the plan 9 asm lexer accepts digits only after the first identifier rune, so the spelled CALL would fail to assemble. The predicate now requires a letter or "_" at position 0. - That predicate existed as two byte-for-byte copies (codegen's isPlan9AsmSafe, gcasm's plan9AsmPathSafe) under a comment claiming an import cycle prevents sharing; no such cycle exists. Both packages now consult one exported asmgen.Plan9AsmPathSafe, so the linkname alias shape and the direct-CALL / gcasmABI0Keep anchor gates can never disagree. - buildPkg now verifies every captured fn leaves the emission loop either with a TEXT body or registered as a pure-Go fallback. A future degrade path that forgets fallbackNames would otherwise surface only as a link error in the consumer build, with no Build-time diagnostic; it is a Build error naming the fn now. The new cg_crosscall_directasm fixture keeps every op native (no rotl/rotr, which lower to helper CALLs the direct-asm emitter's ForbidCalls refuses) so the retained functions actually emit via asmgen; its regression test fails against the pre-fix resolvers with the mangled current-package spelling in the emitted bundle. Co-Authored-By: Claude Fable 5 <[email protected]> * asmgen: restructure the first-rune check as a switch to satisfy staticcheck golangci-lint's staticcheck (QF1001) flagged the negated compound condition in Plan9AsmPathSafe; the positive-switch form matches the per-byte loop below it. No behavior change. Co-Authored-By: Claude Fable 5 <[email protected]> --------- Co-authored-by: Claude Fable 5 <[email protected]>
82 lines
3.9 KiB
WebAssembly Text Format
82 lines
3.9 KiB
WebAssembly Text Format
(module
|
|
;; Cross-chunk direct calls made from direct-asm-retained bodies.
|
|
;; Unlike cg_crosscall.wat, every op here lowers to native
|
|
;; instructions (no rotl/rotr/div, which become helper CALLs the
|
|
;; direct-asm emitter's ForbidCalls refuses), so the retained
|
|
;; functions actually emit via internal/asmgen and their
|
|
;; cross-chunk CALL operands are exercised. Bodies are padded past
|
|
;; the tiny multi-package chunk budgets the tests use, so each
|
|
;; function lands in its own chunk package.
|
|
|
|
;; leafA: a long dependent i64 chain of native-lowering ops.
|
|
(func $leafA (param $a i64) (param $b i64) (result i64)
|
|
(local $x i64)
|
|
(local.set $x (i64.add (local.get $a) (local.get $b)))
|
|
(local.set $x (i64.mul (local.get $x) (i64.const 31)))
|
|
(local.set $x (i64.xor (local.get $x) (i64.const 0x9e3779b97f4a7c15)))
|
|
(local.set $x (i64.add (local.get $x) (i64.shr_u (local.get $x) (i64.const 7))))
|
|
(local.set $x (i64.mul (local.get $x) (i64.const 0x100000001b3)))
|
|
(local.set $x (i64.xor (local.get $x) (i64.shl (local.get $x) (i64.const 13))))
|
|
(local.set $x (i64.add (local.get $x) (i64.const 12345)))
|
|
(local.set $x (i64.sub (local.get $x) (i64.shl (local.get $a) (i64.const 17))))
|
|
(local.set $x (i64.xor (local.get $x) (i64.shr_u (local.get $b) (i64.const 9))))
|
|
(local.set $x (i64.mul (local.get $x) (i64.const 7)))
|
|
(i64.add (local.get $x) (i64.shr_s (local.get $x) (i64.const 3))))
|
|
|
|
;; leafB: a different long chain.
|
|
(func $leafB (param $a i64) (result i64)
|
|
(local $y i64)
|
|
(local.set $y (i64.mul (local.get $a) (i64.const 0x5851f42d4c957f2d)))
|
|
(local.set $y (i64.add (local.get $y) (i64.const 0x14057b7ef767814f)))
|
|
(local.set $y (i64.xor (local.get $y) (i64.shr_u (local.get $y) (i64.const 33))))
|
|
(local.set $y (i64.mul (local.get $y) (i64.const 0xff51afd7ed558ccd)))
|
|
(local.set $y (i64.xor (local.get $y) (i64.shr_u (local.get $y) (i64.const 29))))
|
|
(local.set $y (i64.add (local.get $y) (i64.shl (local.get $a) (i64.const 5))))
|
|
(local.set $y (i64.sub (local.get $y) (i64.const 999)))
|
|
(local.set $y (i64.or (local.get $y) (i64.const 1)))
|
|
(i64.mul (local.get $y) (i64.const 3)))
|
|
|
|
;; mid combines both leaves; retained for direct-asm, so its two
|
|
;; cross-chunk calls come out of the asmgen emitter.
|
|
(func $mid (param $a i64) (param $b i64) (result i64)
|
|
(local $z i64)
|
|
(local.set $z (i64.add
|
|
(call $leafA (local.get $a) (local.get $b))
|
|
(call $leafB (local.get $a))))
|
|
(local.set $z (i64.xor (local.get $z) (i64.shr_u (local.get $z) (i64.const 11))))
|
|
(local.set $z (i64.mul (local.get $z) (i64.const 5)))
|
|
(local.set $z (i64.add (local.get $z) (i64.shr_u (local.get $b) (i64.const 21))))
|
|
(local.set $z (i64.sub (local.get $z) (i64.shl (local.get $a) (i64.const 2))))
|
|
(local.set $z (i64.xor (local.get $z) (i64.const 0x0f0f0f0f0f0f0f0f)))
|
|
(i64.add (local.get $z) (i64.const 42)))
|
|
|
|
;; wide: enough i64 params to overflow the register ABI, so this
|
|
;; function keeps its pure Go body (sig fallback) while its callers
|
|
;; are transformed — a direct-asm caller's CALL then resolves
|
|
;; against the ABI0 wrapper the gcasmABI0Keep anchor forces out.
|
|
(func $wide
|
|
(param i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64)
|
|
(result i64)
|
|
(i64.add (local.get 0)
|
|
(i64.add (local.get 1)
|
|
(i64.add (local.get 2)
|
|
(i64.add (local.get 3)
|
|
(i64.add (local.get 4)
|
|
(i64.add (local.get 5)
|
|
(i64.add (local.get 6)
|
|
(i64.add (local.get 7)
|
|
(i64.add (local.get 8)
|
|
(i64.add (local.get 9)
|
|
(i64.add (local.get 10) (local.get 11)))))))))))))
|
|
|
|
(func (export "crosscall_da") (param $a i64) (param $b i64) (result i64)
|
|
(i64.add
|
|
(i64.add
|
|
(call $mid (local.get $a) (local.get $b))
|
|
(call $leafB (local.get $b)))
|
|
(call $wide
|
|
(local.get $a) (local.get $b) (local.get $a) (local.get $b)
|
|
(local.get $a) (local.get $b) (local.get $a) (local.get $b)
|
|
(local.get $a) (local.get $b) (local.get $a) (local.get $b))))
|
|
)
|