Files
9b2c9ccddd gcasm: fix cross-chunk symbol gaps in the direct-call path (#64)
* 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]>
2026-09-02 20:02:20 +09:00

61 lines
2.1 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package asmgen
import "testing"
// TestPlan9AsmPathSafe pins the shared safety predicate that decides
// whether an import path can be embedded verbatim into a plan 9 asm
// symbol operand (mapping "/" → "∕" and "." → "·") or whether the
// generators must fall back to per-chunk Go-body wrappers because
// some byte of the path has no plan 9 identifier substitute.
func TestPlan9AsmPathSafe(t *testing.T) {
cases := []struct {
path string
want bool
}{
// Single-name stdlib-style paths: safe.
{"runtime", true},
{"syscall", true},
// Nested paths with letters / digits / underscores: safe.
{"internal/runtime/atomic", true},
{"a/b/c", true},
{"foo_bar/baz", true},
{"_x/y", true},
{"gentest/pkg", true},
// Domain-style paths: dots are remapped to U+00B7, still safe.
{"github.com/foo/bar", true},
{"github.com/goccy/wasm2go/internal", true},
{"x.y.z/pkg", true},
{"example.org/x_y/v2", true},
// Digits are identifier runes only AFTER the first rune: a
// digit-leading host would put a digit at position 0 of the
// spelled operand, which the asm lexer scans as a number, not
// an identifier. Real Go module hosts like this exist.
{"4d63.com/mymod/pkg", false},
{"0xacab.org/x", false},
// ...while a digit anywhere later in the path is fine.
{"h4d63.com/mymod/pkg", true},
{"example.org/0user/pkg", true},
// Hyphen has no identifier-rune substitute — unsafe. This is
// what makes any module path containing a "-" fall back to
// the per-chunk Go-body wrappers.
{"github.com/example/foo-bar", false},
{"github.com/goccy/some-hyphen/pkg", false},
{"a-b", false},
// Other punctuation that can legally appear in module paths
// but breaks plan 9 asm identifier scanning.
{"a+b", false},
{"host.tld/a+b", false},
{"a~b", false},
{"foo bar", false},
{"host.tld/sp ace", false},
// Empty path: treated as unsafe so the caller skips the
// optimization rather than emitting "·" alone.
{"", false},
}
for _, c := range cases {
if got := Plan9AsmPathSafe(c.path); got != c.want {
t.Errorf("Plan9AsmPathSafe(%q) = %v, want %v", c.path, got, c.want)
}
}
}