@@ -4596,12 +4596,13 @@ static void initializeResilientWitnessTable(
4596
4596
}
4597
4597
}
4598
4598
4599
- // / Instantiate a brand new witness table for a resilient or generic
4600
- // / protocol conformance.
4601
- WitnessTable *
4602
- WitnessTableCacheEntry::allocate (
4603
- const ProtocolConformanceDescriptor *conformance,
4604
- const void * const *instantiationArgs) {
4599
+ // Instantiate a generic or resilient witness table into a `buffer`
4600
+ // that has already been allocated of the appropriate size and zeroed out.
4601
+ static WitnessTable *
4602
+ instantiateWitnessTable (const Metadata *Type,
4603
+ const ProtocolConformanceDescriptor *conformance,
4604
+ const void * const *instantiationArgs,
4605
+ void **fullTable) {
4605
4606
auto protocol = conformance->getProtocol ();
4606
4607
auto genericTable = conformance->getGenericWitnessTable ();
4607
4608
@@ -4617,12 +4618,6 @@ WitnessTableCacheEntry::allocate(
4617
4618
// Number of bytes for any private storage used by the conformance itself.
4618
4619
size_t privateSizeInWords = genericTable->getWitnessTablePrivateSizeInWords ();
4619
4620
4620
- // Find the allocation.
4621
- void **fullTable = reinterpret_cast <void **>(this + 1 );
4622
-
4623
- // Zero out the witness table.
4624
- memset (fullTable, 0 , getWitnessTableSize (conformance));
4625
-
4626
4621
// Advance the address point; the private storage area is accessed via
4627
4622
// negative offsets.
4628
4623
auto table = fullTable + privateSizeInWords;
@@ -4678,6 +4673,57 @@ WitnessTableCacheEntry::allocate(
4678
4673
4679
4674
return castTable;
4680
4675
}
4676
+ // / Instantiate a brand new witness table for a resilient or generic
4677
+ // / protocol conformance.
4678
+ WitnessTable *
4679
+ WitnessTableCacheEntry::allocate (
4680
+ const ProtocolConformanceDescriptor *conformance,
4681
+ const void * const *instantiationArgs) {
4682
+ // Find the allocation.
4683
+ void **fullTable = reinterpret_cast <void **>(this + 1 );
4684
+
4685
+ // Zero out the witness table.
4686
+ memset (fullTable, 0 , getWitnessTableSize (conformance));
4687
+
4688
+ // Instantiate the table.
4689
+ return instantiateWitnessTable (Type, Conformance, instantiationArgs, fullTable);
4690
+ }
4691
+
4692
+ // / Instantiate the witness table for a nondependent conformance that only has
4693
+ // / one possible instantiation.
4694
+ static WitnessTable *
4695
+ getNondependentWitnessTable (const ProtocolConformanceDescriptor *conformance,
4696
+ const Metadata *type) {
4697
+ // Check whether the table has already been instantiated.
4698
+ auto tablePtr = reinterpret_cast <std::atomic<WitnessTable*> *>(
4699
+ conformance->getGenericWitnessTable ()->PrivateData .get ());
4700
+
4701
+ auto existingTable = tablePtr->load (SWIFT_MEMORY_ORDER_CONSUME);
4702
+ if (existingTable) {
4703
+ return existingTable;
4704
+ }
4705
+
4706
+ // Allocate space for the table.
4707
+ auto tableSize = WitnessTableCacheEntry::getWitnessTableSize (conformance);
4708
+ TaggedMetadataAllocator<SingletonGenericWitnessTableCacheTag> allocator;
4709
+ auto buffer = (void **)allocator.Allocate (tableSize, alignof (void *));
4710
+ memset (buffer, 0 , tableSize);
4711
+
4712
+ // Instantiate the table.
4713
+ auto table = instantiateWitnessTable (type, conformance, nullptr , buffer);
4714
+
4715
+ // See whether we can claim to be the one true table.
4716
+ WitnessTable *orig = nullptr ;
4717
+ if (!tablePtr->compare_exchange_strong (orig, table, std::memory_order_release,
4718
+ SWIFT_MEMORY_ORDER_CONSUME)) {
4719
+ // Someone beat us to the punch. Throw away our table and return the
4720
+ // existing one.
4721
+ allocator.Deallocate (buffer);
4722
+ return orig;
4723
+ }
4724
+
4725
+ return table;
4726
+ }
4681
4727
4682
4728
const WitnessTable *
4683
4729
swift::swift_getWitnessTable (const ProtocolConformanceDescriptor *conformance,
@@ -4699,11 +4745,24 @@ swift::swift_getWitnessTable(const ProtocolConformanceDescriptor *conformance,
4699
4745
4700
4746
// When there is no generic table, or it doesn't require instantiation,
4701
4747
// use the pattern directly.
4702
- // accessor directly.
4703
4748
auto genericTable = conformance->getGenericWitnessTable ();
4704
4749
if (!genericTable || doesNotRequireInstantiation (conformance, genericTable)) {
4705
4750
return uniqueForeignWitnessTableRef (conformance->getWitnessTablePattern ());
4706
4751
}
4752
+
4753
+ // If the conformance is not dependent on generic arguments in the conforming
4754
+ // type, then there is only one instantiation possible, so we can try to
4755
+ // allocate only the table without the concurrent map structure.
4756
+ //
4757
+ // TODO: There is no metadata flag that directly encodes the "nondependent"
4758
+ // as of the Swift 5.3 ABI. However, we can check whether the conforming
4759
+ // type is generic; a nongeneric type's conformance can never be dependent (at
4760
+ // least, not today). However, a generic type conformance may also be
4761
+ // nondependent if it
4762
+ auto typeDescription = conformance->getTypeDescriptor ();
4763
+ if (typeDescription && !typeDescription->isGeneric ()) {
4764
+ return getNondependentWitnessTable (conformance, type);
4765
+ }
4707
4766
4708
4767
auto &cache = getCache (genericTable);
4709
4768
auto result = cache.getOrInsert (type, conformance, instantiationArgs);
0 commit comments