@@ -1437,7 +1437,13 @@ namespace {
14371437 }
14381438
14391439 void addMethod (SILDeclRef fn) {
1440- VTableEntries.push_back (fn);
1440+ if (methodRequiresReifiedVTableEntry (IGM, VTable, fn)) {
1441+ VTableEntries.push_back (fn);
1442+ } else if (getType ()->getEffectiveAccess () >= AccessLevel::Public) {
1443+ // Emit a stub method descriptor and lookup function for nonoverridden
1444+ // methods so that resilient code sequences can still use them.
1445+ emitNonoverriddenMethod (fn);
1446+ }
14411447 }
14421448
14431449 void addMethodOverride (SILDeclRef baseRef, SILDeclRef declRef) {
@@ -1521,9 +1527,6 @@ namespace {
15211527 }
15221528
15231529 void addVTable () {
1524- if (VTableEntries.empty ())
1525- return ;
1526-
15271530 LLVM_DEBUG (
15281531 llvm::dbgs () << " VTable entries for " << getType ()->getName () << " :\n " ;
15291532 for (auto entry : VTableEntries) {
@@ -1533,6 +1536,9 @@ namespace {
15331536 }
15341537 );
15351538
1539+ if (VTableEntries.empty ())
1540+ return ;
1541+
15361542 // Only emit a method lookup function if the class is resilient
15371543 // and has a non-empty vtable.
15381544 if (IGM.hasResilientMetadata (getType (), ResilienceExpansion::Minimal))
@@ -1595,8 +1601,25 @@ namespace {
15951601 IGM.emitDispatchThunk (fn);
15961602 }
15971603 }
1604+
1605+ void emitNonoverriddenMethod (SILDeclRef fn) {
1606+ // TODO: Emit a freestanding method descriptor structure, and a method
1607+ // lookup function, to present the ABI of an overridable method even
1608+ // though the method has no real overrides currently.
1609+ }
15981610
15991611 void addOverrideTable () {
1612+ LLVM_DEBUG (
1613+ llvm::dbgs () << " Override Table entries for " << getType ()->getName () << " :\n " ;
1614+ for (auto entry : OverrideTableEntries) {
1615+ llvm::dbgs () << " " ;
1616+ entry.first .print (llvm::dbgs ());
1617+ llvm::dbgs () << " -> " ;
1618+ entry.second .print (llvm::dbgs ());
1619+ llvm::dbgs () << ' \n ' ;
1620+ }
1621+ );
1622+
16001623 if (OverrideTableEntries.empty ())
16011624 return ;
16021625
@@ -2702,12 +2725,12 @@ namespace {
27022725 using super::asImpl;
27032726 using super::IGM;
27042727 using super::Target;
2728+ using super::VTable;
27052729
27062730 ConstantStructBuilder &B;
27072731
27082732 const ClassLayout &FieldLayout;
27092733 const ClassMetadataLayout &MetadataLayout;
2710- const SILVTable *VTable;
27112734
27122735 Size AddressPoint;
27132736
@@ -2717,8 +2740,7 @@ namespace {
27172740 const ClassLayout &fieldLayout)
27182741 : super(IGM, theClass), B(builder),
27192742 FieldLayout (fieldLayout),
2720- MetadataLayout(IGM.getClassMetadataLayout(theClass)),
2721- VTable(IGM.getSILModule().lookUpVTable(theClass)) {}
2743+ MetadataLayout(IGM.getClassMetadataLayout(theClass)) {}
27222744
27232745 public:
27242746 SILType getLoweredType () {
@@ -2854,7 +2876,7 @@ namespace {
28542876 PointerAuthEntity::Special::HeapDestructor);
28552877 } else {
28562878 // In case the optimizer removed the function. See comment in
2857- // addMethod ().
2879+ // addReifiedVTableEntry ().
28582880 B.addNullPointer (IGM.FunctionPtrTy );
28592881 }
28602882 }
@@ -2973,7 +2995,7 @@ namespace {
29732995 B.add (data);
29742996 }
29752997
2976- void addMethod (SILDeclRef fn) {
2998+ void addReifiedVTableEntry (SILDeclRef fn) {
29772999 // Find the vtable entry.
29783000 assert (VTable && " no vtable?!" );
29793001 auto entry = VTable->getEntry (IGM.getSILModule (), fn);
@@ -5086,3 +5108,33 @@ void IRGenModule::emitOpaqueTypeDecl(OpaqueTypeDecl *D) {
50865108 // Emit the opaque type descriptor.
50875109 OpaqueTypeDescriptorBuilder (*this , D).emit ();
50885110}
5111+
5112+ bool irgen::methodRequiresReifiedVTableEntry (IRGenModule &IGM,
5113+ const SILVTable *vtable,
5114+ SILDeclRef method) {
5115+ auto &M = IGM.getSILModule ();
5116+ auto entry = vtable->getEntry (IGM.getSILModule (), method);
5117+ if (!entry) {
5118+ return true ;
5119+ }
5120+
5121+ // We may be able to elide the vtable entry, ABI permitting, if it's not
5122+ // overridden.
5123+ if (!entry->isNonOverridden ()) {
5124+ return true ;
5125+ }
5126+
5127+ // Does the ABI require a vtable entry to exist? If the class is public,
5128+ // and it's either marked fragile or part of a non-resilient module, then
5129+ // other modules will directly address vtable offsets and we can't remove
5130+ // vtable entries.
5131+ if (vtable->getClass ()->getEffectiveAccess () >= AccessLevel::Public) {
5132+ // TODO: Check whether we use a resilient ABI to access this
5133+ // class's methods. We can drop unnecessary vtable entries if we do;
5134+ // otherwise fixed vtable offsets are part of the ABI.
5135+ return true ;
5136+ }
5137+
5138+ // Otherwise, we can leave this method out of the runtime vtable.
5139+ return false ;
5140+ }
0 commit comments