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 if m.providerInitialValueHashes == nil { 190 m.providerInitialValueHashes = make([]uint64, len(providerRegistry)) 191 } 192 hash, err := proptools.CalculateHash(value) 193 if err != nil { 194 panic(fmt.Sprintf("Can't set value of provider %s: %s", provider.typ, err.Error())) 195 } 196 m.providerInitialValueHashes[provider.id] = hash 197} 198 199// provider returns the value, if any, for a given provider for a module. Verifies that it is 200// called after the appropriate mutator or GenerateBuildActions pass for the provider on the module. 201// If the value for the provider was not set it returns nil. The return value should always be considered read-only. 202// 203// Once Go has generics the return value can be typed and the type assert by callers can be dropped: 204// provider(type T)(m *moduleInfo, provider ProviderKey(T)) T 205func (c *Context) provider(m *moduleInfo, provider *providerKey) (any, bool) { 206 if provider.mutator == "" { 207 if !m.finishedGenerateBuildActions { 208 panic(fmt.Sprintf("Can't get value of provider %s before GenerateBuildActions finished", 209 provider.typ)) 210 } 211 } else { 212 expectedMutator := c.providerMutators[provider.id] 213 if expectedMutator != nil && !c.mutatorFinishedForModule(expectedMutator, m) { 214 panic(fmt.Sprintf("Can't get value of provider %s before mutator %s finished", 215 provider.typ, provider.mutator)) 216 } 217 } 218 219 if len(m.providers) > provider.id { 220 if p := m.providers[provider.id]; p != nil { 221 return p, true 222 } 223 } 224 225 return nil, false 226} 227 228func (c *Context) mutatorFinishedForModule(mutator *mutatorInfo, m *moduleInfo) bool { 229 if c.finishedMutators[mutator.index] { 230 // mutator pass finished for all modules 231 return true 232 } 233 234 return m.finishedMutator >= mutator.index 235} 236 237func (c *Context) mutatorStartedForModule(mutator *mutatorInfo, m *moduleInfo) bool { 238 if c.finishedMutators[mutator.index] { 239 // mutator pass finished for all modules 240 return true 241 } 242 243 return m.startedMutator >= mutator.index 244} 245 246// OtherModuleProviderContext is a helper interface that is a subset of ModuleContext, BottomUpMutatorContext, or 247// TopDownMutatorContext for use in OtherModuleProvider. 248type OtherModuleProviderContext interface { 249 OtherModuleProvider(m Module, provider AnyProviderKey) (any, bool) 250} 251 252var _ OtherModuleProviderContext = BaseModuleContext(nil) 253var _ OtherModuleProviderContext = ModuleContext(nil) 254var _ OtherModuleProviderContext = BottomUpMutatorContext(nil) 255var _ OtherModuleProviderContext = TopDownMutatorContext(nil) 256 257// OtherModuleProvider reads the provider for the given module. If the provider has been set the value is 258// returned and the boolean is true. If it has not been set the zero value of the provider's type is returned 259// and the boolean is false. The value returned may be a deep copy of the value originally passed to SetProvider. 260// 261// OtherModuleProviderContext is a helper interface that accepts ModuleContext, BottomUpMutatorContext, or 262// TopDownMutatorContext. 263func OtherModuleProvider[K any](ctx OtherModuleProviderContext, module Module, provider ProviderKey[K]) (K, bool) { 264 value, ok := ctx.OtherModuleProvider(module, provider) 265 if !ok { 266 var k K 267 return k, false 268 } 269 return value.(K), ok 270} 271 272// SingletonModuleProviderContext is a helper interface that is a subset of Context and SingletonContext for use in 273// SingletonModuleProvider. 274type SingletonModuleProviderContext interface { 275 ModuleProvider(m Module, provider AnyProviderKey) (any, bool) 276} 277 278var _ SingletonModuleProviderContext = &Context{} 279var _ SingletonModuleProviderContext = SingletonContext(nil) 280 281// SingletonModuleProvider reads the provider for the given module. If the provider has been set the value is 282// returned and the boolean is true. If it has not been set the zero value of the provider's type is returned 283// and the boolean is false. The value returned may be a deep copy of the value originally passed to SetProvider. 284// 285// SingletonModuleProviderContext is a helper interface that accepts Context or SingletonContext. 286func SingletonModuleProvider[K any](ctx SingletonModuleProviderContext, module Module, provider ProviderKey[K]) (K, bool) { 287 value, ok := ctx.ModuleProvider(module, provider) 288 if !ok { 289 var k K 290 return k, false 291 } 292 return value.(K), ok 293} 294 295// ModuleProviderContext is a helper interface that is a subset of ModuleContext, BottomUpMutatorContext, or 296// TopDownMutatorContext for use in ModuleProvider. 297type ModuleProviderContext interface { 298 Provider(provider AnyProviderKey) (any, bool) 299} 300 301var _ ModuleProviderContext = BaseModuleContext(nil) 302var _ ModuleProviderContext = ModuleContext(nil) 303var _ ModuleProviderContext = BottomUpMutatorContext(nil) 304var _ ModuleProviderContext = TopDownMutatorContext(nil) 305 306// ModuleProvider reads the provider for the current module. If the provider has been set the value is 307// returned and the boolean is true. If it has not been set the zero value of the provider's type is returned 308// and the boolean is false. The value returned may be a deep copy of the value originally passed to SetProvider. 309// 310// ModuleProviderContext is a helper interface that accepts ModuleContext, BottomUpMutatorContext, or 311// TopDownMutatorContext. 312func ModuleProvider[K any](ctx ModuleProviderContext, provider ProviderKey[K]) (K, bool) { 313 value, ok := ctx.Provider(provider) 314 if !ok { 315 var k K 316 return k, false 317 } 318 return value.(K), ok 319} 320 321// SetProviderContext is a helper interface that is a subset of ModuleContext, BottomUpMutatorContext, or 322// TopDownMutatorContext for use in SetProvider. 323type SetProviderContext interface { 324 SetProvider(provider AnyProviderKey, value any) 325} 326 327var _ SetProviderContext = BaseModuleContext(nil) 328var _ SetProviderContext = ModuleContext(nil) 329var _ SetProviderContext = BottomUpMutatorContext(nil) 330var _ SetProviderContext = TopDownMutatorContext(nil) 331 332// SetProvider sets the value for a provider for the current module. It panics if not called 333// during the appropriate mutator or GenerateBuildActions pass for the provider, if the value 334// is not of the appropriate type, or if the value has already been set. The value should not 335// be modified after being passed to SetProvider. 336// 337// SetProviderContext is a helper interface that accepts ModuleContext, BottomUpMutatorContext, or 338// TopDownMutatorContext. 339func SetProvider[K any](ctx SetProviderContext, provider ProviderKey[K], value K) { 340 ctx.SetProvider(provider, value) 341} 342