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 "reflect" 20) 21 22// This file implements Providers, modelled after Bazel 23// (https://docs.bazel.build/versions/master/skylark/rules.html#providers). 24// Each provider can be associated with a mutator, in which case the value for the provider for a 25// module can only be set during the mutator call for the module, and the value can only be 26// retrieved after the mutator call for the module. For providers not associated with a mutator, the 27// value can for the provider for a module can only be set during GenerateBuildActions for the 28// module, and the value can only be retrieved after GenerateBuildActions for the module. 29// 30// Providers are globally registered during init() and given a unique ID. The value of a provider 31// for a module is stored in an []interface{} indexed by the ID. If the value of a provider has 32// not been set, the value in the []interface{} will be nil. 33// 34// If the storage used by the provider value arrays becomes too large: 35// sizeof([]interface) * number of providers * number of modules that have a provider value set 36// then the storage can be replaced with something like a bitwise trie. 37// 38// The purpose of providers is to provide a serializable checkpoint between modules to enable 39// Blueprint to skip parts of the analysis phase when inputs haven't changed. To that end, 40// values passed to providers should be treated as immutable by callers to both the getters and 41// setters. Go doesn't provide any way to enforce immutability on arbitrary types, so it may be 42// necessary for the getters and setters to make deep copies of the values, likely extending 43// proptools.CloneProperties to do so. 44 45type provider struct { 46 id int 47 typ reflect.Type 48 zero interface{} 49 mutator string 50} 51 52type ProviderKey *provider 53 54var providerRegistry []ProviderKey 55 56// NewProvider returns a ProviderKey for the type of the given example value. The example value 57// is otherwise unused. 58// 59// The returned ProviderKey can be used to set a value of the ProviderKey's type for a module 60// inside GenerateBuildActions for the module, and to get the value from GenerateBuildActions from 61// any module later in the build graph. 62// 63// Once Go has generics the exampleValue parameter will not be necessary: 64// NewProvider(type T)() ProviderKey(T) 65func NewProvider(exampleValue interface{}) ProviderKey { 66 return NewMutatorProvider(exampleValue, "") 67} 68 69// NewMutatorProvider returns a ProviderKey for the type of the given example value. The example 70// value is otherwise unused. 71// 72// The returned ProviderKey can be used to set a value of the ProviderKey's type for a module inside 73// the given mutator for the module, and to get the value from GenerateBuildActions from any 74// module later in the build graph in the same mutator, or any module in a later mutator or during 75// GenerateBuildActions. 76// 77// Once Go has generics the exampleValue parameter will not be necessary: 78// NewMutatorProvider(type T)(mutator string) ProviderKey(T) 79func NewMutatorProvider(exampleValue interface{}, mutator string) ProviderKey { 80 checkCalledFromInit() 81 82 typ := reflect.TypeOf(exampleValue) 83 zero := reflect.Zero(typ).Interface() 84 85 provider := &provider{ 86 id: len(providerRegistry), 87 typ: typ, 88 zero: zero, 89 mutator: mutator, 90 } 91 92 providerRegistry = append(providerRegistry, provider) 93 94 return provider 95} 96 97// initProviders fills c.providerMutators with the *mutatorInfo associated with each provider ID, 98// if any. 99func (c *Context) initProviders() { 100 c.providerMutators = make([]*mutatorInfo, len(providerRegistry)) 101 for _, provider := range providerRegistry { 102 for _, mutator := range c.mutatorInfo { 103 if mutator.name == provider.mutator { 104 c.providerMutators[provider.id] = mutator 105 } 106 } 107 } 108} 109 110// setProvider sets the value for a provider on a moduleInfo. Verifies that it is called during the 111// appropriate mutator or GenerateBuildActions pass for the provider, and that the value is of the 112// appropriate type. The value should not be modified after being passed to setProvider. 113// 114// Once Go has generics the value parameter can be typed: 115// setProvider(type T)(m *moduleInfo, provider ProviderKey(T), value T) 116func (c *Context) setProvider(m *moduleInfo, provider ProviderKey, value interface{}) { 117 if provider.mutator == "" { 118 if !m.startedGenerateBuildActions { 119 panic(fmt.Sprintf("Can't set value of provider %s before GenerateBuildActions started", 120 provider.typ)) 121 } else if m.finishedGenerateBuildActions { 122 panic(fmt.Sprintf("Can't set value of provider %s after GenerateBuildActions finished", 123 provider.typ)) 124 } 125 } else { 126 expectedMutator := c.providerMutators[provider.id] 127 if expectedMutator == nil { 128 panic(fmt.Sprintf("Can't set value of provider %s associated with unregistered mutator %s", 129 provider.typ, provider.mutator)) 130 } else if c.mutatorFinishedForModule(expectedMutator, m) { 131 panic(fmt.Sprintf("Can't set value of provider %s after mutator %s finished", 132 provider.typ, provider.mutator)) 133 } else if !c.mutatorStartedForModule(expectedMutator, m) { 134 panic(fmt.Sprintf("Can't set value of provider %s before mutator %s started", 135 provider.typ, provider.mutator)) 136 } 137 } 138 139 if typ := reflect.TypeOf(value); typ != provider.typ { 140 panic(fmt.Sprintf("Value for provider has incorrect type, wanted %s, got %s", 141 provider.typ, typ)) 142 } 143 144 if m.providers == nil { 145 m.providers = make([]interface{}, len(providerRegistry)) 146 } 147 148 if m.providers[provider.id] != nil { 149 panic(fmt.Sprintf("Value of provider %s is already set", provider.typ)) 150 } 151 152 m.providers[provider.id] = value 153} 154 155// provider returns the value, if any, for a given provider for a module. Verifies that it is 156// called after the appropriate mutator or GenerateBuildActions pass for the provider on the module. 157// If the value for the provider was not set it returns the zero value of the type of the provider, 158// which means the return value can always be type-asserted to the type of the provider. The return 159// value should always be considered read-only. 160// 161// Once Go has generics the return value can be typed and the type assert by callers can be dropped: 162// provider(type T)(m *moduleInfo, provider ProviderKey(T)) T 163func (c *Context) provider(m *moduleInfo, provider ProviderKey) (interface{}, bool) { 164 if provider.mutator == "" { 165 if !m.finishedGenerateBuildActions { 166 panic(fmt.Sprintf("Can't get value of provider %s before GenerateBuildActions finished", 167 provider.typ)) 168 } 169 } else { 170 expectedMutator := c.providerMutators[provider.id] 171 if expectedMutator != nil && !c.mutatorFinishedForModule(expectedMutator, m) { 172 panic(fmt.Sprintf("Can't get value of provider %s before mutator %s finished", 173 provider.typ, provider.mutator)) 174 } 175 } 176 177 if len(m.providers) > provider.id { 178 if p := m.providers[provider.id]; p != nil { 179 return p, true 180 } 181 } 182 183 return provider.zero, false 184} 185 186func (c *Context) mutatorFinishedForModule(mutator *mutatorInfo, m *moduleInfo) bool { 187 if c.finishedMutators[mutator] { 188 // mutator pass finished for all modules 189 return true 190 } 191 192 if c.startedMutator == mutator { 193 // mutator pass started, check if it is finished for this module 194 return m.finishedMutator == mutator 195 } 196 197 // mutator pass hasn't started 198 return false 199} 200 201func (c *Context) mutatorStartedForModule(mutator *mutatorInfo, m *moduleInfo) bool { 202 if c.finishedMutators[mutator] { 203 // mutator pass finished for all modules 204 return true 205 } 206 207 if c.startedMutator == mutator { 208 // mutator pass is currently running 209 if m.startedMutator == mutator { 210 // mutator has started for this module 211 return true 212 } 213 } 214 215 return false 216} 217