• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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