@@ -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.
14851511func 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 , "\t DefaultAPILevel = %d\n " , defaultAPI )
1499-
15001523 versionIDs := sortedKeys (allTables )
1501- buf .WriteString ("\t Tables = 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 , "\t DefaultAPILevel = %d\n " , defaultAPI )
1564+
1565+ buf .WriteString ("\t Tables = 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 ("\t Revisions = APIRevisions{\n " )
0 commit comments