1// Copyright 2020 Google Inc. All rights reserved. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package blueprint 16 17import ( 18 "fmt" 19 20 "github.com/google/blueprint/proptools" 21) 22 23// This file implements Providers, modelled after Bazel 24// (https://docs.bazel.build/versions/master/skylark/rules.html#providers). 25// Each provider can be associated with a mutator, in which case the value for the provider for a 26// module can only be set during the mutator call for the module, and the value can only be 27// retrieved after the mutator call for the module. For providers not associated with a mutator, the 28// value can for the provider for a module can only be set during GenerateBuildActions for the 29// module, and the value can only be retrieved after GenerateBuildActions for the module. 30// 31// Providers are globally registered during init() and given a unique ID. The value of a provider 32// for a module is stored in an []any indexed by the ID. If the value of a provider has 33// not been set, the value in the []any will be nil. 34// 35// If the storage used by the provider value arrays becomes too large: 36// sizeof([]interface) * number of providers * number of modules that have a provider value set 37// then the storage can be replaced with something like a bitwise trie. 38// 39// The purpose of providers is to provide a serializable checkpoint between modules to enable 40// Blueprint to skip parts of the analysis phase when inputs haven't changed. To that end, 41// values passed to providers should be treated as immutable by callers to both the getters and 42// setters. Go doesn't provide any way to enforce immutability on arbitrary types, so it may be 43// necessary for the getters and setters to make deep copies of the values, likely extending 44// proptools.CloneProperties to do so. 45 46type typedProviderKey[K any] struct { 47 providerKey 48} 49 50type providerKey struct { 51 id int 52 typ string 53 mutator string 54} 55 56func (p *providerKey) provider() *providerKey { return p } 57 58type AnyProviderKey interface { 59 provider() *providerKey 60} 61type ProviderKey[K any] struct { 62 *typedProviderKey[K] 63} 64 65var _ AnyProviderKey = (*providerKey)(nil) 66var _ AnyProviderKey = ProviderKey[bool]{} 67 68var providerRegistry []*providerKey 69 70// NewProvider returns a ProviderKey for the given type. 71// 72// The returned ProviderKey can be used to set a value of the ProviderKey's type for a module 73// inside GenerateBuildActions for the module, and to get the value from GenerateBuildActions from 74// any module later in the build graph. 75func NewProvider[K any]() ProviderKey[K] { 76 return NewMutatorProvider[K]("") 77} 78 79// NewMutatorProvider returns a ProviderKey for the given type. 80// 81// The returned ProviderKey can be used to set a value of the ProviderKey's type for a module inside 82// the given mutator for the module, and to get the value from GenerateBuildActions from any 83// module later in the build graph in the same mutator, or any module in a later mutator or during 84// GenerateBuildActions. 85func NewMutatorProvider[K any](mutator string) ProviderKey[K] { 86 checkCalledFromInit() 87 88 typ := fmt.Sprintf("%T", *new(K)) 89 90 provider := ProviderKey[K]{ 91 typedProviderKey: &typedProviderKey[K]{ 92 providerKey: providerKey{ 93 id: len(providerRegistry), 94 typ: typ, 95 mutator: mutator, 96 }, 97 }, 98 } 99 100 providerRegistry = append(providerRegistry, &provider.providerKey) 101 102 return provider 103} 104 105// initProviders fills c.providerMutators with the *mutatorInfo associated with each provider ID, 106// if any. 107func (c *Context) initProviders() { 108 c.providerMutators = make([]*mutatorInfo, len(providerRegistry)) 109 for _, provider := range providerRegistry { 110 for _, mutator := range c.mutatorInfo { 111 if mutator.name == provider.mutator { 112 c.providerMutators[provider.id] = mutator 113 } 114 } 115 } 116} 117 118// setProvider sets the value for a provider on a moduleInfo. Verifies that it is called during the 119// appropriate mutator or GenerateBuildActions pass for the provider, and that the value is of the 120// appropriate type. The value should not be modified after being passed to setProvider. 121// 122// Once Go has generics the value parameter can be typed: 123// setProvider(type T)(m *moduleInfo, provider ProviderKey(T), value T) 124func (c *Context) setProvider(m *moduleInfo, provider *providerKey, value any) { 125 if provider.mutator == "" { 126 if !m.startedGenerateBuildActions { 127 panic(fmt.Sprintf("Can't set value of provider %s before GenerateBuildActions started", 128 provider.typ)) 129 } else if m.finishedGenerateBuildActions { 130 panic(fmt.Sprintf("Can't set value of provider %s after GenerateBuildActions finished", 131 provider.typ)) 132 } 133 } else { 134 expectedMutator := c.providerMutators[provider.id] 135 if expectedMutator == nil { 136 panic(fmt.Sprintf("Can't set value of provider %s associated with unregistered mutator %s", 137 provider.typ, provider.mutator)) 138 } else if c.mutatorFinishedForModule(expectedMutator, m) { 139 panic(fmt.Sprintf("Can't set value of provider %s after mutator %s finished", 140 provider.typ, provider.mutator)) 141 } else if !c.mutatorStartedForModule(expectedMutator, m) { 142 panic(fmt.Sprintf("Can't set value of provider %s before mutator %s started", 143 provider.typ, provider.mutator)) 144 } 145 } 146 147 if m.providers == nil { 148 m.providers = make([]any, len(providerRegistry)) 149 } 150 151 if m.providers[provider.id] != nil { 152 panic(fmt.Sprintf("Value of provider %s is already set", provider.typ)) 153 } 154 155 m.providers[provider.id] = value 156 157 if c.verifyProvidersAreUnchanged { 158 if m.providerInitialValueHashes == nil { 159 m.providerInitialValueHashes = make([]uint64, len(providerRegistry)) 160 } 161 hash, err := proptools.CalculateHash(value) 162 if err != nil { 163 panic(fmt.Sprintf("Can't set value of provider %s: %s", provider.typ, err.Error())) 164 } 165 m.providerInitialValueHashes[provider.id] = hash 166 } 167} 168 169// provider returns the value, if any, for a given provider for a module. Verifies that it is 170// called after the appropriate mutator or GenerateBuildActions pass for the provider on the module. 171// If the value for the provider was not set it returns nil. The return value should always be considered read-only. 172// 173// Once Go has generics the return value can be typed and the type assert by callers can be dropped: 174// provider(type T)(m *moduleInfo, provider ProviderKey(T)) T 175func (c *Context) provider(m *moduleInfo, provider *providerKey) (any, bool) { 176 if provider.mutator == "" { 177 if !m.finishedGenerateBuildActions { 178 panic(fmt.Sprintf("Can't get value of provider %s before GenerateBuildActions finished", 179 provider.typ)) 180 } 181 } else { 182 expectedMutator := c.providerMutators[provider.id] 183 if expectedMutator != nil && !c.mutatorFinishedForModule(expectedMutator, m) { 184 panic(fmt.Sprintf("Can't get value of provider %s before mutator %s finished", 185 provider.typ, provider.mutator)) 186 } 187 } 188 189 if len(m.providers) > provider.id { 190 if p := m.providers[provider.id]; p != nil { 191 return p, true 192 } 193 } 194 195 return nil, false 196} 197 198func (c *Context) mutatorFinishedForModule(mutator *mutatorInfo, m *moduleInfo) bool { 199 if c.finishedMutators[mutator] { 200 // mutator pass finished for all modules 201 return true 202 } 203 204 if c.startedMutator == mutator { 205 // mutator pass started, check if it is finished for this module 206 return m.finishedMutator == mutator 207 } 208 209 // mutator pass hasn't started 210 return false 211} 212 213func (c *Context) mutatorStartedForModule(mutator *mutatorInfo, m *moduleInfo) bool { 214 if c.finishedMutators[mutator] { 215 // mutator pass finished for all modules 216 return true 217 } 218 219 if c.startedMutator == mutator { 220 // mutator pass is currently running 221 if m.startedMutator == mutator { 222 // mutator has started for this module 223 return true 224 } 225 } 226 227 return false 228} 229 230// OtherModuleProviderContext is a helper interface that is a subset of ModuleContext, BottomUpMutatorContext, or 231// TopDownMutatorContext for use in OtherModuleProvider. 232type OtherModuleProviderContext interface { 233 OtherModuleProvider(m Module, provider AnyProviderKey) (any, bool) 234} 235 236var _ OtherModuleProviderContext = BaseModuleContext(nil) 237var _ OtherModuleProviderContext = ModuleContext(nil) 238var _ OtherModuleProviderContext = BottomUpMutatorContext(nil) 239var _ OtherModuleProviderContext = TopDownMutatorContext(nil) 240 241// OtherModuleProvider reads the provider for the given module. If the provider has been set the value is 242// returned and the boolean is true. If it has not been set the zero value of the provider's type is returned 243// and the boolean is false. The value returned may be a deep copy of the value originally passed to SetProvider. 244// 245// OtherModuleProviderContext is a helper interface that accepts ModuleContext, BottomUpMutatorContext, or 246// TopDownMutatorContext. 247func OtherModuleProvider[K any](ctx OtherModuleProviderContext, module Module, provider ProviderKey[K]) (K, bool) { 248 value, ok := ctx.OtherModuleProvider(module, provider) 249 if !ok { 250 var k K 251 return k, false 252 } 253 return value.(K), ok 254} 255 256// SingletonModuleProviderContext is a helper interface that is a subset of Context and SingletonContext for use in 257// SingletonModuleProvider. 258type SingletonModuleProviderContext interface { 259 ModuleProvider(m Module, provider AnyProviderKey) (any, bool) 260} 261 262var _ SingletonModuleProviderContext = &Context{} 263var _ SingletonModuleProviderContext = SingletonContext(nil) 264 265// SingletonModuleProvider reads the provider for the given module. If the provider has been set the value is 266// returned and the boolean is true. If it has not been set the zero value of the provider's type is returned 267// and the boolean is false. The value returned may be a deep copy of the value originally passed to SetProvider. 268// 269// SingletonModuleProviderContext is a helper interface that accepts Context or SingletonContext. 270func SingletonModuleProvider[K any](ctx SingletonModuleProviderContext, module Module, provider ProviderKey[K]) (K, bool) { 271 value, ok := ctx.ModuleProvider(module, provider) 272 if !ok { 273 var k K 274 return k, false 275 } 276 return value.(K), ok 277} 278 279// ModuleProviderContext is a helper interface that is a subset of ModuleContext, BottomUpMutatorContext, or 280// TopDownMutatorContext for use in ModuleProvider. 281type ModuleProviderContext interface { 282 Provider(provider AnyProviderKey) (any, bool) 283} 284 285var _ ModuleProviderContext = BaseModuleContext(nil) 286var _ ModuleProviderContext = ModuleContext(nil) 287var _ ModuleProviderContext = BottomUpMutatorContext(nil) 288var _ ModuleProviderContext = TopDownMutatorContext(nil) 289 290// ModuleProvider reads the provider for the current module. If the provider has been set the value is 291// returned and the boolean is true. If it has not been set the zero value of the provider's type is returned 292// and the boolean is false. The value returned may be a deep copy of the value originally passed to SetProvider. 293// 294// ModuleProviderContext is a helper interface that accepts ModuleContext, BottomUpMutatorContext, or 295// TopDownMutatorContext. 296func ModuleProvider[K any](ctx ModuleProviderContext, provider ProviderKey[K]) (K, bool) { 297 value, ok := ctx.Provider(provider) 298 if !ok { 299 var k K 300 return k, false 301 } 302 return value.(K), ok 303} 304 305// SetProviderContext is a helper interface that is a subset of ModuleContext, BottomUpMutatorContext, or 306// TopDownMutatorContext for use in SetProvider. 307type SetProviderContext interface { 308 SetProvider(provider AnyProviderKey, value any) 309} 310 311var _ SetProviderContext = BaseModuleContext(nil) 312var _ SetProviderContext = ModuleContext(nil) 313var _ SetProviderContext = BottomUpMutatorContext(nil) 314var _ SetProviderContext = TopDownMutatorContext(nil) 315 316// SetProvider sets the value for a provider for the current module. It panics if not called 317// during the appropriate mutator or GenerateBuildActions pass for the provider, if the value 318// is not of the appropriate type, or if the value has already been set. The value should not 319// be modified after being passed to SetProvider. 320// 321// SetProviderContext is a helper interface that accepts ModuleContext, BottomUpMutatorContext, or 322// TopDownMutatorContext. 323func SetProvider[K any](ctx SetProviderContext, provider ProviderKey[K], value K) { 324 ctx.SetProvider(provider, value) 325} 326