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