Make BottomUpMutators parallel

Append .Parallel() to all of the RegisterBottomUpMutator calls to tell
Blueprint it can run them in parallel.

Test: identical build.ninja, passes race detector
Change-Id: I969a0689522d4cba7c8ff51e2aa00fe2fd338a89
diff --git a/android/arch.go b/android/arch.go
index c767bd7..5074c4c 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -25,10 +25,10 @@
 )
 
 func init() {
-	RegisterBottomUpMutator("defaults_deps", defaultsDepsMutator)
+	RegisterBottomUpMutator("defaults_deps", defaultsDepsMutator).Parallel()
 	RegisterTopDownMutator("defaults", defaultsMutator)
 
-	RegisterBottomUpMutator("arch", ArchMutator)
+	RegisterBottomUpMutator("arch", ArchMutator).Parallel()
 }
 
 var (
diff --git a/android/mutator.go b/android/mutator.go
index 9405f2d..c0cb3aa 100644
--- a/android/mutator.go
+++ b/android/mutator.go
@@ -44,8 +44,8 @@
 	androidBaseContextImpl
 }
 
-func RegisterBottomUpMutator(name string, mutator AndroidBottomUpMutator) {
-	soong.RegisterBottomUpMutator(name, func(ctx blueprint.BottomUpMutatorContext) {
+func RegisterBottomUpMutator(name string, mutator AndroidBottomUpMutator) soong.BottomUpMutatorHandle {
+	return soong.RegisterBottomUpMutator(name, func(ctx blueprint.BottomUpMutatorContext) {
 		if a, ok := ctx.Module().(Module); ok {
 			actx := &androidBottomUpMutatorContext{
 				BottomUpMutatorContext: ctx,
diff --git a/android/variable.go b/android/variable.go
index d2dc5b9..531125d 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -24,7 +24,7 @@
 )
 
 func init() {
-	RegisterBottomUpMutator("variable", variableMutator)
+	RegisterBottomUpMutator("variable", variableMutator).Parallel()
 }
 
 type variableProperties struct {
diff --git a/cc/cc.go b/cc/cc.go
index 6698007..752046f 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -38,17 +38,17 @@
 	// LinkageMutator must be registered after common.ArchMutator, but that is guaranteed by
 	// the Go initialization order because this package depends on common, so common's init
 	// functions will run first.
-	android.RegisterBottomUpMutator("link", linkageMutator)
-	android.RegisterBottomUpMutator("ndk_api", ndkApiMutator)
-	android.RegisterBottomUpMutator("test_per_src", testPerSrcMutator)
-	android.RegisterBottomUpMutator("begin", beginMutator)
-	android.RegisterBottomUpMutator("deps", depsMutator)
+	android.RegisterBottomUpMutator("link", linkageMutator).Parallel()
+	android.RegisterBottomUpMutator("ndk_api", ndkApiMutator).Parallel()
+	android.RegisterBottomUpMutator("test_per_src", testPerSrcMutator).Parallel()
+	android.RegisterBottomUpMutator("begin", beginMutator).Parallel()
+	android.RegisterBottomUpMutator("deps", depsMutator).Parallel()
 
 	android.RegisterTopDownMutator("asan_deps", sanitizerDepsMutator(asan))
-	android.RegisterBottomUpMutator("asan", sanitizerMutator(asan))
+	android.RegisterBottomUpMutator("asan", sanitizerMutator(asan)).Parallel()
 
 	android.RegisterTopDownMutator("tsan_deps", sanitizerDepsMutator(tsan))
-	android.RegisterBottomUpMutator("tsan", sanitizerMutator(tsan))
+	android.RegisterBottomUpMutator("tsan", sanitizerMutator(tsan)).Parallel()
 
 	pctx.Import("android/soong/cc/config")
 }
diff --git a/cc/ndk_library.go b/cc/ndk_library.go
index fe52b0e..b0fd398 100644
--- a/cc/ndk_library.go
+++ b/cc/ndk_library.go
@@ -18,6 +18,7 @@
 	"fmt"
 	"strconv"
 	"strings"
+	"sync"
 
 	"github.com/google/blueprint"
 
@@ -58,7 +59,8 @@
 
 	// These libraries have migrated over to the new ndk_library, which is added
 	// as a variation dependency via depsMutator.
-	ndkMigratedLibs = []string{}
+	ndkMigratedLibs     = []string{}
+	ndkMigratedLibsLock sync.Mutex // protects ndkMigratedLibs writes during parallel beginMutator
 )
 
 // Creates a stub shared library based on the provided version file.
@@ -177,6 +179,8 @@
 	c.baseCompiler.compilerInit(ctx)
 
 	name := strings.TrimSuffix(ctx.ModuleName(), ".ndk")
+	ndkMigratedLibsLock.Lock()
+	defer ndkMigratedLibsLock.Unlock()
 	for _, lib := range ndkMigratedLibs {
 		if lib == name {
 			return
diff --git a/genrule/genrule.go b/genrule/genrule.go
index a50af1c..ecc5ab8 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -25,7 +25,7 @@
 	soong.RegisterModuleType("gensrcs", GenSrcsFactory)
 	soong.RegisterModuleType("genrule", GenRuleFactory)
 
-	android.RegisterBottomUpMutator("genrule_deps", genruleDepsMutator)
+	android.RegisterBottomUpMutator("genrule_deps", genruleDepsMutator).Parallel()
 }
 
 var (
diff --git a/register.go b/register.go
index 353094c..5c74273 100644
--- a/register.go
+++ b/register.go
@@ -34,9 +34,10 @@
 	name            string
 	bottomUpMutator blueprint.BottomUpMutator
 	topDownMutator  blueprint.TopDownMutator
+	parallel        bool
 }
 
-var mutators []mutator
+var mutators []*mutator
 
 func RegisterModuleType(name string, factory blueprint.ModuleFactory) {
 	moduleTypes = append(moduleTypes, moduleType{name, factory})
@@ -46,12 +47,23 @@
 	singletons = append(singletons, singleton{name, factory})
 }
 
-func RegisterBottomUpMutator(name string, m blueprint.BottomUpMutator) {
-	mutators = append(mutators, mutator{name: name, bottomUpMutator: m})
+func RegisterBottomUpMutator(name string, m blueprint.BottomUpMutator) BottomUpMutatorHandle {
+	mutator := &mutator{name: name, bottomUpMutator: m}
+	mutators = append(mutators, mutator)
+	return mutator
 }
 
 func RegisterTopDownMutator(name string, m blueprint.TopDownMutator) {
-	mutators = append(mutators, mutator{name: name, topDownMutator: m})
+	mutators = append(mutators, &mutator{name: name, topDownMutator: m})
+}
+
+type BottomUpMutatorHandle interface {
+	Parallel() BottomUpMutatorHandle
+}
+
+func (mutator *mutator) Parallel() BottomUpMutatorHandle {
+	mutator.parallel = true
+	return mutator
 }
 
 func NewContext() *blueprint.Context {
@@ -67,7 +79,10 @@
 
 	for _, t := range mutators {
 		if t.bottomUpMutator != nil {
-			ctx.RegisterBottomUpMutator(t.name, t.bottomUpMutator)
+			handle := ctx.RegisterBottomUpMutator(t.name, t.bottomUpMutator)
+			if t.parallel {
+				handle.Parallel()
+			}
 		}
 		if t.topDownMutator != nil {
 			ctx.RegisterTopDownMutator(t.name, t.topDownMutator)