Skip to content

Commit 1d12fc2

Browse files
feat(spec2go): emit flat global vars for zero-cost init in codes_gen.go
Replace nested composite literals inside init() with flat package-level variables (method slices and table vars). The Go compiler places these in the data segment, eliminating runtime initialization overhead.
1 parent 4f8a886 commit 1d12fc2

1 file changed

Lines changed: 50 additions & 9 deletions

File tree

tools/cmd/spec2go/main.go

Lines changed: 50 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1481,7 +1481,33 @@ func generateCodesFile(
14811481
return nil
14821482
}
14831483

1484+
// sanitizeIdent converts an arbitrary string into a valid Go identifier
1485+
// fragment by replacing every non-letter, non-digit character with an
1486+
// underscore. If the result starts with a digit, an underscore is prepended.
1487+
func sanitizeIdent(s string) string {
1488+
var b strings.Builder
1489+
b.Grow(len(s))
1490+
for i, r := range s {
1491+
switch {
1492+
case unicode.IsLetter(r), r == '_':
1493+
b.WriteRune(r)
1494+
case unicode.IsDigit(r):
1495+
if i == 0 {
1496+
b.WriteByte('_')
1497+
}
1498+
b.WriteRune(r)
1499+
default:
1500+
b.WriteByte('_')
1501+
}
1502+
}
1503+
return b.String()
1504+
}
1505+
14841506
// generateSource produces the Go source for codes_gen.go.
1507+
//
1508+
// The output uses flat package-level variables for method slices and compiled
1509+
// tables so the Go compiler places them in the data segment, eliminating
1510+
// runtime init cost.
14851511
func generateSource(
14861512
defaultAPI int,
14871513
allTables map[string]map[string]map[string]binder.TransactionCode,
@@ -1494,15 +1520,12 @@ func generateSource(
14941520
buf.WriteString("package versionaware\n\n")
14951521
buf.WriteString("import \"github.com/AndroidGoLab/binder/binder\"\n\n")
14961522

1497-
fmt.Fprintf(&buf, "func init() {\n")
1498-
fmt.Fprintf(&buf, "\tDefaultAPILevel = %d\n", defaultAPI)
1499-
15001523
versionIDs := sortedKeys(allTables)
1501-
buf.WriteString("\tTables = MultiVersionTable{\n")
15021524

1525+
// Phase 1: emit flat method-slice variables and table variables.
15031526
for _, vid := range versionIDs {
15041527
table := allTables[vid]
1505-
fmt.Fprintf(&buf, "\t\t%q: CompiledTable{\n", vid)
1528+
versionIdent := "v" + sanitizeIdent(vid)
15061529

15071530
descriptors := sortedKeys(table)
15081531
for _, desc := range descriptors {
@@ -1511,21 +1534,39 @@ func generateSource(
15111534
continue
15121535
}
15131536

1514-
fmt.Fprintf(&buf, "\t\t\t{Descriptor: %q, Methods: []MethodEntry{\n", desc)
1537+
descIdent := sanitizeIdent(desc)
1538+
fmt.Fprintf(&buf, "var methods_%s_%s = []MethodEntry{\n", versionIdent, descIdent)
15151539

15161540
methodNames := sortedKeys(methods)
15171541
for _, name := range methodNames {
15181542
code := methods[name]
15191543
offset := code - binder.FirstCallTransaction
1520-
fmt.Fprintf(&buf, "\t\t\t\t{Method: %q, Code: binder.FirstCallTransaction + %d},\n", name, offset)
1544+
fmt.Fprintf(&buf, "\t{Method: %q, Code: binder.FirstCallTransaction + %d},\n", name, offset)
15211545
}
15221546

1523-
buf.WriteString("\t\t\t}},\n")
1547+
buf.WriteString("}\n\n")
15241548
}
15251549

1526-
buf.WriteString("\t\t},\n")
1550+
fmt.Fprintf(&buf, "var table_%s = CompiledTable{\n", versionIdent)
1551+
for _, desc := range descriptors {
1552+
if len(table[desc]) == 0 {
1553+
continue
1554+
}
1555+
descIdent := sanitizeIdent(desc)
1556+
fmt.Fprintf(&buf, "\t{Descriptor: %q, Methods: methods_%s_%s},\n", desc, versionIdent, descIdent)
1557+
}
1558+
buf.WriteString("}\n\n")
15271559
}
15281560

1561+
// Phase 2: assemble the top-level maps in init().
1562+
fmt.Fprintf(&buf, "func init() {\n")
1563+
fmt.Fprintf(&buf, "\tDefaultAPILevel = %d\n", defaultAPI)
1564+
1565+
buf.WriteString("\tTables = MultiVersionTable{\n")
1566+
for _, vid := range versionIDs {
1567+
versionIdent := "v" + sanitizeIdent(vid)
1568+
fmt.Fprintf(&buf, "\t\t%q: table_%s,\n", vid, versionIdent)
1569+
}
15291570
buf.WriteString("\t}\n")
15301571

15311572
buf.WriteString("\tRevisions = APIRevisions{\n")

0 commit comments

Comments
 (0)