@@ -1437,7 +1437,13 @@ namespace {
1437
1437
}
1438
1438
1439
1439
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
+ }
1441
1447
}
1442
1448
1443
1449
void addMethodOverride (SILDeclRef baseRef, SILDeclRef declRef) {
@@ -1521,9 +1527,6 @@ namespace {
1521
1527
}
1522
1528
1523
1529
void addVTable () {
1524
- if (VTableEntries.empty ())
1525
- return ;
1526
-
1527
1530
LLVM_DEBUG (
1528
1531
llvm::dbgs () << " VTable entries for " << getType ()->getName () << " :\n " ;
1529
1532
for (auto entry : VTableEntries) {
@@ -1533,6 +1536,9 @@ namespace {
1533
1536
}
1534
1537
);
1535
1538
1539
+ if (VTableEntries.empty ())
1540
+ return ;
1541
+
1536
1542
// Only emit a method lookup function if the class is resilient
1537
1543
// and has a non-empty vtable.
1538
1544
if (IGM.hasResilientMetadata (getType (), ResilienceExpansion::Minimal))
@@ -1595,8 +1601,25 @@ namespace {
1595
1601
IGM.emitDispatchThunk (fn);
1596
1602
}
1597
1603
}
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
+ }
1598
1610
1599
1611
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
+
1600
1623
if (OverrideTableEntries.empty ())
1601
1624
return ;
1602
1625
@@ -2702,12 +2725,12 @@ namespace {
2702
2725
using super::asImpl;
2703
2726
using super::IGM;
2704
2727
using super::Target;
2728
+ using super::VTable;
2705
2729
2706
2730
ConstantStructBuilder &B;
2707
2731
2708
2732
const ClassLayout &FieldLayout;
2709
2733
const ClassMetadataLayout &MetadataLayout;
2710
- const SILVTable *VTable;
2711
2734
2712
2735
Size AddressPoint;
2713
2736
@@ -2717,8 +2740,7 @@ namespace {
2717
2740
const ClassLayout &fieldLayout)
2718
2741
: super(IGM, theClass), B(builder),
2719
2742
FieldLayout (fieldLayout),
2720
- MetadataLayout(IGM.getClassMetadataLayout(theClass)),
2721
- VTable(IGM.getSILModule().lookUpVTable(theClass)) {}
2743
+ MetadataLayout(IGM.getClassMetadataLayout(theClass)) {}
2722
2744
2723
2745
public:
2724
2746
SILType getLoweredType () {
@@ -2854,7 +2876,7 @@ namespace {
2854
2876
PointerAuthEntity::Special::HeapDestructor);
2855
2877
} else {
2856
2878
// In case the optimizer removed the function. See comment in
2857
- // addMethod ().
2879
+ // addReifiedVTableEntry ().
2858
2880
B.addNullPointer (IGM.FunctionPtrTy );
2859
2881
}
2860
2882
}
@@ -2973,7 +2995,7 @@ namespace {
2973
2995
B.add (data);
2974
2996
}
2975
2997
2976
- void addMethod (SILDeclRef fn) {
2998
+ void addReifiedVTableEntry (SILDeclRef fn) {
2977
2999
// Find the vtable entry.
2978
3000
assert (VTable && " no vtable?!" );
2979
3001
auto entry = VTable->getEntry (IGM.getSILModule (), fn);
@@ -5086,3 +5108,33 @@ void IRGenModule::emitOpaqueTypeDecl(OpaqueTypeDecl *D) {
5086
5108
// Emit the opaque type descriptor.
5087
5109
OpaqueTypeDescriptorBuilder (*this , D).emit ();
5088
5110
}
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