@@ -4535,12 +4535,13 @@ static void initializeResilientWitnessTable(
4535
4535
}
4536
4536
}
4537
4537
4538
- // / Instantiate a brand new witness table for a resilient or generic
4539
- // / protocol conformance.
4540
- WitnessTable *
4541
- WitnessTableCacheEntry::allocate (
4542
- const ProtocolConformanceDescriptor *conformance,
4543
- const void * const *instantiationArgs) {
4538
+ // Instantiate a generic or resilient witness table into a `buffer`
4539
+ // that has already been allocated of the appropriate size and zeroed out.
4540
+ static WitnessTable *
4541
+ instantiateWitnessTable (const Metadata *Type,
4542
+ const ProtocolConformanceDescriptor *conformance,
4543
+ const void * const *instantiationArgs,
4544
+ void **fullTable) {
4544
4545
auto protocol = conformance->getProtocol ();
4545
4546
auto genericTable = conformance->getGenericWitnessTable ();
4546
4547
@@ -4556,12 +4557,6 @@ WitnessTableCacheEntry::allocate(
4556
4557
// Number of bytes for any private storage used by the conformance itself.
4557
4558
size_t privateSizeInWords = genericTable->getWitnessTablePrivateSizeInWords ();
4558
4559
4559
- // Find the allocation.
4560
- void **fullTable = reinterpret_cast <void **>(this + 1 );
4561
-
4562
- // Zero out the witness table.
4563
- memset (fullTable, 0 , getWitnessTableSize (conformance));
4564
-
4565
4560
// Advance the address point; the private storage area is accessed via
4566
4561
// negative offsets.
4567
4562
auto table = fullTable + privateSizeInWords;
@@ -4617,6 +4612,57 @@ WitnessTableCacheEntry::allocate(
4617
4612
4618
4613
return castTable;
4619
4614
}
4615
+ // / Instantiate a brand new witness table for a resilient or generic
4616
+ // / protocol conformance.
4617
+ WitnessTable *
4618
+ WitnessTableCacheEntry::allocate (
4619
+ const ProtocolConformanceDescriptor *conformance,
4620
+ const void * const *instantiationArgs) {
4621
+ // Find the allocation.
4622
+ void **fullTable = reinterpret_cast <void **>(this + 1 );
4623
+
4624
+ // Zero out the witness table.
4625
+ memset (fullTable, 0 , getWitnessTableSize (conformance));
4626
+
4627
+ // Instantiate the table.
4628
+ return instantiateWitnessTable (Type, Conformance, instantiationArgs, fullTable);
4629
+ }
4630
+
4631
+ // / Instantiate the witness table for a nondependent conformance that only has
4632
+ // / one possible instantiation.
4633
+ static WitnessTable *
4634
+ getNondependentWitnessTable (const ProtocolConformanceDescriptor *conformance,
4635
+ const Metadata *type) {
4636
+ // Check whether the table has already been instantiated.
4637
+ auto tablePtr = reinterpret_cast <std::atomic<WitnessTable*> *>(
4638
+ conformance->getGenericWitnessTable ()->PrivateData .get ());
4639
+
4640
+ auto existingTable = tablePtr->load (SWIFT_MEMORY_ORDER_CONSUME);
4641
+ if (existingTable) {
4642
+ return existingTable;
4643
+ }
4644
+
4645
+ // Allocate space for the table.
4646
+ auto tableSize = WitnessTableCacheEntry::getWitnessTableSize (conformance);
4647
+ TaggedMetadataAllocator<SingletonGenericWitnessTableCacheTag> allocator;
4648
+ auto buffer = (void **)allocator.Allocate (tableSize, alignof (void *));
4649
+ memset (buffer, 0 , tableSize);
4650
+
4651
+ // Instantiate the table.
4652
+ auto table = instantiateWitnessTable (type, conformance, nullptr , buffer);
4653
+
4654
+ // See whether we can claim to be the one true table.
4655
+ WitnessTable *orig = nullptr ;
4656
+ if (!tablePtr->compare_exchange_strong (orig, table, std::memory_order_release,
4657
+ SWIFT_MEMORY_ORDER_CONSUME)) {
4658
+ // Someone beat us to the punch. Throw away our table and return the
4659
+ // existing one.
4660
+ allocator.Deallocate (buffer);
4661
+ return orig;
4662
+ }
4663
+
4664
+ return table;
4665
+ }
4620
4666
4621
4667
const WitnessTable *
4622
4668
swift::swift_getWitnessTable (const ProtocolConformanceDescriptor *conformance,
@@ -4638,11 +4684,24 @@ swift::swift_getWitnessTable(const ProtocolConformanceDescriptor *conformance,
4638
4684
4639
4685
// When there is no generic table, or it doesn't require instantiation,
4640
4686
// use the pattern directly.
4641
- // accessor directly.
4642
4687
auto genericTable = conformance->getGenericWitnessTable ();
4643
4688
if (!genericTable || doesNotRequireInstantiation (conformance, genericTable)) {
4644
4689
return uniqueForeignWitnessTableRef (conformance->getWitnessTablePattern ());
4645
4690
}
4691
+
4692
+ // If the conformance is not dependent on generic arguments in the conforming
4693
+ // type, then there is only one instantiation possible, so we can try to
4694
+ // allocate only the table without the concurrent map structure.
4695
+ //
4696
+ // TODO: There is no metadata flag that directly encodes the "nondependent"
4697
+ // as of the Swift 5.3 ABI. However, we can check whether the conforming
4698
+ // type is generic; a nongeneric type's conformance can never be dependent (at
4699
+ // least, not today). However, a generic type conformance may also be
4700
+ // nondependent if it
4701
+ auto typeDescription = conformance->getTypeDescriptor ();
4702
+ if (typeDescription && !typeDescription->isGeneric ()) {
4703
+ return getNondependentWitnessTable (conformance, type);
4704
+ }
4646
4705
4647
4706
auto &cache = getCache (genericTable);
4648
4707
auto result = cache.getOrInsert (type, conformance, instantiationArgs);
0 commit comments