Include access functions for the metadata and witness tables

of associated types in protocol witness tables.

We use the global access functions when the result isn't
dependent, and a simple accessor when the result can be cheaply
recovered from the conforming metadata.  Otherwise, we add a
cache slot to a private section of the witness table, forcing
an instantiation per conformance.  Like generic type metadata,
concrete instantiations of generic conformances are memoized.

There's a fair amount of code in this patch that can't be
dynamically tested at the moment because of the widespread
reliance on recursive expansion of archetypes / dependent
types.  That's something we're now theoretically in a position
to change, and as we do so, we'll test more of this code.
This commit is contained in:
John McCall
2015-12-23 00:24:00 -08:00
parent 0d037ad917
commit b1e3120a28
30 changed files with 1605 additions and 250 deletions

View File

@@ -2595,3 +2595,65 @@ namespace llvm { namespace hashing { namespace detail {
size_t fixed_seed_override = 0;
} } }
/*** Protocol witness tables *************************************************/
namespace {
class WitnessTableCacheEntry : public CacheEntry<WitnessTableCacheEntry> {
public:
static const char *getName() { return "WitnessTableCache"; }
WitnessTableCacheEntry(size_t numArguments) {}
static constexpr size_t getNumArguments() {
return 1;
}
};
}
using GenericWitnessTableCache = MetadataCache<WitnessTableCacheEntry>;
using LazyGenericWitnessTableCache = Lazy<GenericWitnessTableCache>;
/// Fetch the cache for a generic witness-table structure.
static GenericWitnessTableCache &getCache(GenericWitnessTable *gen) {
// Keep this assert even if you change the representation above.
static_assert(sizeof(LazyGenericWitnessTableCache) <=
sizeof(GenericWitnessTable::PrivateData),
"metadata cache is larger than the allowed space");
auto lazyCache =
reinterpret_cast<LazyGenericWitnessTableCache*>(gen->PrivateData);
return lazyCache->get();
}
extern "C" const WitnessTable *
swift::swift_getGenericWitnessTable(GenericWitnessTable *genericTable,
const Metadata *type,
void * const *instantiationArgs) {
// Search the cache.
constexpr const size_t numGenericArgs = 1;
const void *args[] = { type };
auto &cache = getCache(genericTable);
auto entry = cache.findOrAdd(args, numGenericArgs,
[&]() -> WitnessTableCacheEntry* {
// Create a new entry for the cache.
auto entry = WitnessTableCacheEntry::allocate(cache.getAllocator(),
args, numGenericArgs,
genericTable->WitnessTableSizeInWords * sizeof(void*));
auto *table = entry->getData<WitnessTable>();
memcpy((void**) table, (void* const *) &*genericTable->Pattern,
genericTable->WitnessTableSizeInWordsToCopy * sizeof(void*));
bzero((void**) table + genericTable->WitnessTableSizeInWordsToCopy,
(genericTable->WitnessTableSizeInWords
- genericTable->WitnessTableSizeInWordsToCopy) * sizeof(void*));
// Call the instantiation function.
if (!genericTable->Instantiator.isNull()) {
genericTable->Instantiator(table, type, instantiationArgs);
}
return entry;
});
return entry->getData<WitnessTable>();
}