@@ -4512,12 +4512,13 @@ static void initializeResilientWitnessTable(
4512
4512
}
4513
4513
}
4514
4514
4515
- // / Instantiate a brand new witness table for a resilient or generic
4516
- // / protocol conformance.
4517
- WitnessTable *
4518
- WitnessTableCacheEntry::allocate (
4519
- const ProtocolConformanceDescriptor *conformance,
4520
- const void * const *instantiationArgs) {
4515
+ // Instantiate a generic or resilient witness table into a `buffer`
4516
+ // that has already been allocated of the appropriate size and zeroed out.
4517
+ static WitnessTable *
4518
+ instantiateWitnessTable (const Metadata *Type,
4519
+ const ProtocolConformanceDescriptor *conformance,
4520
+ const void * const *instantiationArgs,
4521
+ void **fullTable) {
4521
4522
auto protocol = conformance->getProtocol ();
4522
4523
auto genericTable = conformance->getGenericWitnessTable ();
4523
4524
@@ -4533,12 +4534,6 @@ WitnessTableCacheEntry::allocate(
4533
4534
// Number of bytes for any private storage used by the conformance itself.
4534
4535
size_t privateSizeInWords = genericTable->getWitnessTablePrivateSizeInWords ();
4535
4536
4536
- // Find the allocation.
4537
- void **fullTable = reinterpret_cast <void **>(this + 1 );
4538
-
4539
- // Zero out the witness table.
4540
- memset (fullTable, 0 , getWitnessTableSize (conformance));
4541
-
4542
4537
// Advance the address point; the private storage area is accessed via
4543
4538
// negative offsets.
4544
4539
auto table = fullTable + privateSizeInWords;
@@ -4594,6 +4589,57 @@ WitnessTableCacheEntry::allocate(
4594
4589
4595
4590
return castTable;
4596
4591
}
4592
+ // / Instantiate a brand new witness table for a resilient or generic
4593
+ // / protocol conformance.
4594
+ WitnessTable *
4595
+ WitnessTableCacheEntry::allocate (
4596
+ const ProtocolConformanceDescriptor *conformance,
4597
+ const void * const *instantiationArgs) {
4598
+ // Find the allocation.
4599
+ void **fullTable = reinterpret_cast <void **>(this + 1 );
4600
+
4601
+ // Zero out the witness table.
4602
+ memset (fullTable, 0 , getWitnessTableSize (conformance));
4603
+
4604
+ // Instantiate the table.
4605
+ return instantiateWitnessTable (Type, Conformance, instantiationArgs, fullTable);
4606
+ }
4607
+
4608
+ // / Instantiate the witness table for a nondependent conformance that only has
4609
+ // / one possible instantiation.
4610
+ static WitnessTable *
4611
+ getNondependentWitnessTable (const ProtocolConformanceDescriptor *conformance,
4612
+ const Metadata *type) {
4613
+ // Check whether the table has already been instantiated.
4614
+ auto tablePtr = reinterpret_cast <std::atomic<WitnessTable*> *>(
4615
+ conformance->getGenericWitnessTable ()->PrivateData .get ());
4616
+
4617
+ auto existingTable = tablePtr->load (SWIFT_MEMORY_ORDER_CONSUME);
4618
+ if (existingTable) {
4619
+ return existingTable;
4620
+ }
4621
+
4622
+ // Allocate space for the table.
4623
+ auto tableSize = WitnessTableCacheEntry::getWitnessTableSize (conformance);
4624
+ MetadataAllocator allocator;
4625
+ auto buffer = (void **)allocator.Allocate (tableSize, alignof (void *));
4626
+ memset (buffer, 0 , tableSize);
4627
+
4628
+ // Instantiate the table.
4629
+ auto table = instantiateWitnessTable (type, conformance, nullptr , buffer);
4630
+
4631
+ // See whether we can claim to be the one true table.
4632
+ WitnessTable *orig = nullptr ;
4633
+ if (!tablePtr->compare_exchange_strong (orig, table, std::memory_order_release,
4634
+ SWIFT_MEMORY_ORDER_CONSUME)) {
4635
+ // Someone beat us to the punch. Throw away our table and return the
4636
+ // existing one.
4637
+ allocator.Deallocate (buffer);
4638
+ return orig;
4639
+ }
4640
+
4641
+ return table;
4642
+ }
4597
4643
4598
4644
const WitnessTable *
4599
4645
swift::swift_getWitnessTable (const ProtocolConformanceDescriptor *conformance,
@@ -4615,11 +4661,24 @@ swift::swift_getWitnessTable(const ProtocolConformanceDescriptor *conformance,
4615
4661
4616
4662
// When there is no generic table, or it doesn't require instantiation,
4617
4663
// use the pattern directly.
4618
- // accessor directly.
4619
4664
auto genericTable = conformance->getGenericWitnessTable ();
4620
4665
if (!genericTable || doesNotRequireInstantiation (conformance, genericTable)) {
4621
4666
return uniqueForeignWitnessTableRef (conformance->getWitnessTablePattern ());
4622
4667
}
4668
+
4669
+ // If the conformance is not dependent on generic arguments in the conforming
4670
+ // type, then there is only one instantiation possible, so we can try to
4671
+ // allocate only the table without the concurrent map structure.
4672
+ //
4673
+ // TODO: There is no metadata flag that directly encodes the "nondependent"
4674
+ // as of the Swift 5.3 ABI. However, we can check whether the conforming
4675
+ // type is generic; a nongeneric type's conformance can never be dependent (at
4676
+ // least, not today). However, a generic type conformance may also be
4677
+ // nondependent if it
4678
+ auto typeDescription = conformance->getTypeDescriptor ();
4679
+ if (typeDescription && !typeDescription->isGeneric ()) {
4680
+ return getNondependentWitnessTable (conformance, type);
4681
+ }
4623
4682
4624
4683
auto &cache = getCache (genericTable);
4625
4684
auto result = cache.getOrInsert (type, conformance, instantiationArgs);
0 commit comments