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