Skip to content

Commit

Permalink
Support for eliminated witness methods in SILWitnessTable.
Browse files Browse the repository at this point in the history
A method entry in SILWitnessTable can now be null.
This will be needed by dead method elimination.



Swift SVN r22914
  • Loading branch information
eeckstein committed Oct 24, 2014
1 parent 6786969 commit 60cb1a6
Show file tree
Hide file tree
Showing 12 changed files with 91 additions and 23 deletions.
1 change: 1 addition & 0 deletions include/swift/SIL/SILWitnessTable.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ class SILWitnessTable : public llvm::ilist_node<SILWitnessTable>,
/// The method required.
SILDeclRef Requirement;
/// The witness for the method.
/// This can be null in case dead function elimination has removed the method.
SILFunction *Witness;
};

Expand Down
2 changes: 1 addition & 1 deletion include/swift/Serialization/ModuleFormat.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ const uint16_t VERSION_MAJOR = 0;
/// To ensure that two separate changes don't silently get merged into one
/// in source control, you should also update the comment to briefly
/// describe what change you made.
const uint16_t VERSION_MINOR = 156; // Last change: add fragile flag for witness tables
const uint16_t VERSION_MINOR = 157; // Last change: support nil in witness method entry

using DeclID = Fixnum<31>;
using DeclIDField = BCFixed<31>;
Expand Down
12 changes: 8 additions & 4 deletions lib/IRGen/GenProto.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3096,10 +3096,14 @@ namespace {
assert(entry.getMethodWitness().Requirement.getDecl() == iface
&& "sil witness table does not match protocol");

llvm::Constant *witness
= IGM.getAddrOfSILFunction(entry.getMethodWitness().Witness,
NotForDefinition);
witness = llvm::ConstantExpr::getBitCast(witness, IGM.Int8PtrTy);
SILFunction *Func = entry.getMethodWitness().Witness;
llvm::Constant *witness = nullptr;
if (Func) {
witness = IGM.getAddrOfSILFunction(Func, NotForDefinition);
witness = llvm::ConstantExpr::getBitCast(witness, IGM.Int8PtrTy);
} else {
witness = llvm::ConstantPointerNull::get(IGM.Int8PtrTy);
}
Table.push_back(witness);
return;
}
Expand Down
24 changes: 16 additions & 8 deletions lib/Parse/ParseSIL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3880,15 +3880,23 @@ bool Parser::parseSILWitnessTable() {
Identifier FuncName;
SourceLoc FuncLoc;
if (WitnessState.parseSILDeclRef(Ref) ||
parseToken(tok::colon, diag::expected_sil_witness_colon) ||
parseToken(tok::at_sign, diag::expected_sil_function_name) ||
WitnessState.parseSILIdentifier(FuncName, FuncLoc,
diag::expected_sil_value_name))
return true;
SILFunction *Func = SIL->M->lookUpFunction(FuncName.str());
if (!Func) {
diagnose(FuncLoc, diag::sil_witness_func_not_found, FuncName);
parseToken(tok::colon, diag::expected_sil_witness_colon))
return true;

SILFunction *Func = nullptr;
if (Tok.is(tok::kw_nil)) {
consumeToken();
} else {
if (parseToken(tok::at_sign, diag::expected_sil_function_name) ||
WitnessState.parseSILIdentifier(FuncName, FuncLoc,
diag::expected_sil_value_name))
return true;

Func = SIL->M->lookUpFunction(FuncName.str());
if (!Func) {
diagnose(FuncLoc, diag::sil_witness_func_not_found, FuncName);
return true;
}
}
witnessEntries.push_back(SILWitnessTable::MethodWitness{
Ref, Func
Expand Down
4 changes: 4 additions & 0 deletions lib/SIL/SILModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -524,6 +524,10 @@ class SILLinkerVisitor : public SILInstructionVisitor<SILLinkerVisitor, bool> {
if (Member.hasValue() && E.getMethodWitness().Requirement != *Member)
continue;

// The witness could be removed by dead function elimination.
if (!E.getMethodWitness().Witness)
continue;

// Otherwise if it is the requirement we are looking for or we just want
// to deserialize everything, add the function to the list of functions
// to deserialize.
Expand Down
10 changes: 7 additions & 3 deletions lib/SIL/SILPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1634,9 +1634,13 @@ void SILWitnessTable::print(llvm::raw_ostream &OS, bool Verbose) const {
OS << "method ";
methodWitness.Requirement.print(OS);
OS << ": ";
methodWitness.Witness->printName(OS);
OS << "\t// "
<< demangleSymbolAsString(methodWitness.Witness->getName());
if (methodWitness.Witness) {
methodWitness.Witness->printName(OS);
OS << "\t// "
<< demangleSymbolAsString(methodWitness.Witness->getName());
} else {
OS << "nil";
}
break;
}
case AssociatedType: {
Expand Down
8 changes: 6 additions & 2 deletions lib/SIL/SILWitnessTable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,9 @@ SILWitnessTable::~SILWitnessTable() {
for (auto entry : getEntries()) {
switch (entry.getKind()) {
case Method:
entry.getMethodWitness().Witness->decrementRefCount();
if (entry.getMethodWitness().Witness) {
entry.getMethodWitness().Witness->decrementRefCount();
}
break;
case AssociatedType:
case AssociatedTypeProtocol:
Expand All @@ -144,7 +146,9 @@ void SILWitnessTable::convertToDefinition(ArrayRef<Entry> entries,
for (auto entry : getEntries()) {
switch (entry.getKind()) {
case Method:
entry.getMethodWitness().Witness->incrementRefCount();
if (entry.getMethodWitness().Witness) {
entry.getMethodWitness().Witness->incrementRefCount();
}
break;
case AssociatedType:
case AssociatedTypeProtocol:
Expand Down
6 changes: 4 additions & 2 deletions lib/SIL/Verifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2454,8 +2454,10 @@ void SILWitnessTable::verify(const SILModule &M) const {
for (const Entry &E : getEntries())
if (E.getKind() == SILWitnessTable::WitnessKind::Method) {
SILFunction *F = E.getMethodWitness().Witness;
assert(!isLessVisibleThan(F->getLinkage(), getLinkage()) &&
"Witness tables should not reference less visible functions.");
if (F) {
assert(!isLessVisibleThan(F->getLinkage(), getLinkage()) &&
"Witness tables should not reference less visible functions.");
}
}
#endif
}
Expand Down
7 changes: 5 additions & 2 deletions lib/Serialization/DeserializeSIL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1936,8 +1936,11 @@ SILWitnessTable *SILDeserializer::readWitnessTable(DeclID WId,
ArrayRef<uint64_t> ListOfValues;
DeclID NameID;
WitnessMethodEntryLayout::readRecord(scratch, NameID, ListOfValues);
SILFunction *Func = getFuncForReference(MF->getIdentifier(NameID).str());
if (Func) {
SILFunction *Func = nullptr;
if (NameID != 0) {
Func = getFuncForReference(MF->getIdentifier(NameID).str());
}
if (Func || NameID == 0) {
unsigned NextValueIndex = 0;
witnessEntries.push_back(SILWitnessTable::MethodWitness{
getSILDeclRef(MF, ListOfValues, NextValueIndex), Func
Expand Down
6 changes: 5 additions & 1 deletion lib/Serialization/SerializeSIL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1477,10 +1477,14 @@ void SILSerializer::writeSILWitnessTable(const SILWitnessTable &wt) {
SmallVector<ValueID, 4> ListOfValues;
handleSILDeclRef(S, methodWitness.Requirement, ListOfValues);
FuncsToDeclare.insert(methodWitness.Witness);
IdentifierID witnessID = 0;
if (SILFunction *witness = methodWitness.Witness) {
witnessID = S.addIdentifierRef(Ctx.getIdentifier(witness->getName()));
}
WitnessMethodEntryLayout::emitRecord(Out, ScratchRecord,
SILAbbrCodes[WitnessMethodEntryLayout::Code],
// SILFunction name
S.addIdentifierRef(Ctx.getIdentifier(methodWitness.Witness->getName())),
witnessID,
ListOfValues);
}
}
Expand Down
17 changes: 17 additions & 0 deletions test/SIL/Parser/witness_tables.sil
Original file line number Diff line number Diff line change
Expand Up @@ -79,3 +79,20 @@ sil_witness_table public_external InheritedConformance2: InheritedProtocol1 modu
// CHECK-LABEL: sil_witness_table public InheritedConformance2: AnyProtocol module witness_tables
// CHECK-NOT: }
sil_witness_table public InheritedConformance2: AnyProtocol module witness_tables


protocol Proto {
func abc()
}

class DeadMethodClass : Proto {
func abc()
}

// CHECK-LABEL: sil_witness_table DeadMethodClass: Proto module witness_tables
// CHECK: method #Proto.abc!1: nil
// CHECK: }
sil_witness_table DeadMethodClass: Proto module witness_tables {
method #Proto.abc!1: nil
}

17 changes: 17 additions & 0 deletions test/SIL/Serialization/witness_tables.sil
Original file line number Diff line number Diff line change
Expand Up @@ -79,3 +79,20 @@ sil_witness_table InheritedConformance2: InheritedProtocol1 module witness_table
// CHECK-LABEL: sil_witness_table InheritedConformance2: AnyProtocol module witness_tables
// CHECK-NOT: }
sil_witness_table InheritedConformance2: AnyProtocol module witness_tables


protocol Proto {
func abc()
}

class DeadMethodClass : Proto {
func abc()
}

// CHECK-LABEL: sil_witness_table DeadMethodClass: Proto module witness_tables
// CHECK: method #Proto.abc!1: nil
// CHECK: }
sil_witness_table DeadMethodClass: Proto module witness_tables {
method #Proto.abc!1: nil
}

0 comments on commit 60cb1a6

Please sign in to comment.