Make ninjaString an interface
There are 8935901 *ninjaString objects generated in an AOSP
aosp_blueline-userdebug build, and 7865180 of those are a literal
string with no ninja variables.
Each of those *ninjaString objects takes a minimum of 48 bytes for
2 slices, plus 8 bytes for the pointer to the ninjaString. For
the literal string case, one of those slices has a single element,
(costing another 16 bytes for the backing array), and the other
slice is empty, for a total of 72 bytes.
Replace *ninjaString with a ninjaString interface. This increases
the size of the reference from 8 bytes to 16 bytes, but using
a type alias of a string for the literal string implementation uses
only 16 bytes, saving 40 bytes per literal string or 314 MB.
Test: ninja_strings_test
Change-Id: Ic5fe16ed1f2a244fe6a8ccdf762919634d825cbe
diff --git a/ninja_defs.go b/ninja_defs.go
index 61846fe..c5d0e4b 100644
--- a/ninja_defs.go
+++ b/ninja_defs.go
@@ -128,11 +128,11 @@
// A ruleDef describes a rule definition. It does not include the name of the
// rule.
type ruleDef struct {
- CommandDeps []*ninjaString
- CommandOrderOnly []*ninjaString
+ CommandDeps []ninjaString
+ CommandOrderOnly []ninjaString
Comment string
Pool Pool
- Variables map[string]*ninjaString
+ Variables map[string]ninjaString
}
func parseRuleParams(scope scope, params *RuleParams) (*ruleDef,
@@ -141,7 +141,7 @@
r := &ruleDef{
Comment: params.Comment,
Pool: params.Pool,
- Variables: make(map[string]*ninjaString),
+ Variables: make(map[string]ninjaString),
}
if params.Command == "" {
@@ -252,13 +252,13 @@
Comment string
Rule Rule
RuleDef *ruleDef
- Outputs []*ninjaString
- ImplicitOutputs []*ninjaString
- Inputs []*ninjaString
- Implicits []*ninjaString
- OrderOnly []*ninjaString
- Args map[Variable]*ninjaString
- Variables map[string]*ninjaString
+ Outputs []ninjaString
+ ImplicitOutputs []ninjaString
+ Inputs []ninjaString
+ Implicits []ninjaString
+ OrderOnly []ninjaString
+ Args map[Variable]ninjaString
+ Variables map[string]ninjaString
Optional bool
}
@@ -273,9 +273,9 @@
Rule: rule,
}
- setVariable := func(name string, value *ninjaString) {
+ setVariable := func(name string, value ninjaString) {
if b.Variables == nil {
- b.Variables = make(map[string]*ninjaString)
+ b.Variables = make(map[string]ninjaString)
}
b.Variables[name] = value
}
@@ -339,7 +339,7 @@
argNameScope := rule.scope()
if len(params.Args) > 0 {
- b.Args = make(map[Variable]*ninjaString)
+ b.Args = make(map[Variable]ninjaString)
for name, value := range params.Args {
if !rule.isArg(name) {
return nil, fmt.Errorf("unknown argument %q", name)
@@ -419,7 +419,7 @@
return nw.BlankLine()
}
-func valueList(list []*ninjaString, pkgNames map[*packageContext]string,
+func valueList(list []ninjaString, pkgNames map[*packageContext]string,
escaper *strings.Replacer) []string {
result := make([]string, len(list))
@@ -429,7 +429,7 @@
return result
}
-func writeVariables(nw *ninjaWriter, variables map[string]*ninjaString,
+func writeVariables(nw *ninjaWriter, variables map[string]ninjaString,
pkgNames map[*packageContext]string) error {
var keys []string
for k := range variables {