mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-05 01:20:51 +03:00
Refactor generation of interface vtbls for classes
This commit is contained in:
parent
e9021fd6c8
commit
3f452646f5
4 changed files with 80 additions and 88 deletions
|
@ -56,7 +56,7 @@ void DtoResolveClass(ClassDeclaration *cd) {
|
|||
DtoType(cd->type);
|
||||
|
||||
// create IrAggr
|
||||
IrClass *irAggr = getIrAggr(cd, true);
|
||||
getIrAggr(cd, true);
|
||||
|
||||
// make sure all fields really get their ir field
|
||||
for (auto vd : cd->fields) {
|
||||
|
@ -67,11 +67,6 @@ void DtoResolveClass(ClassDeclaration *cd) {
|
|||
}
|
||||
getIrField(vd, true);
|
||||
}
|
||||
|
||||
// interface only emit typeinfo and classinfo
|
||||
if (cd->isInterfaceDeclaration()) {
|
||||
irAggr->initializeInterface();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -172,12 +172,10 @@ IrAggr::createInitializerConstant(const VarInitMap &explicitInitializers) {
|
|||
}
|
||||
}
|
||||
|
||||
// Add the initializers for the member fields. While we are traversing the
|
||||
// class hierarchy, use the opportunity to populate interfacesWithVtbls if
|
||||
// we haven't done so previously (due to e.g. ClassReferenceExp, we can
|
||||
// have multiple initializer constants for a single class).
|
||||
// Add the initializers for the member fields.
|
||||
unsigned dummy = 0;
|
||||
addFieldInitializers(constants, explicitInitializers, aggrdecl, offset,
|
||||
irClass && irClass->interfacesWithVtbls.empty());
|
||||
dummy);
|
||||
|
||||
// tail padding?
|
||||
const size_t structsize = aggrdecl->size(Loc());
|
||||
|
@ -216,12 +214,12 @@ IrAggr::createInitializerConstant(const VarInitMap &explicitInitializers) {
|
|||
void IrAggr::addFieldInitializers(
|
||||
llvm::SmallVectorImpl<llvm::Constant *> &constants,
|
||||
const VarInitMap &explicitInitializers, AggregateDeclaration *decl,
|
||||
unsigned &offset, bool populateInterfacesWithVtbls) {
|
||||
unsigned &offset, unsigned &interfaceVtblIndex) {
|
||||
|
||||
if (ClassDeclaration *cd = decl->isClassDeclaration()) {
|
||||
if (cd->baseClass) {
|
||||
addFieldInitializers(constants, explicitInitializers, cd->baseClass,
|
||||
offset, populateInterfacesWithVtbls);
|
||||
offset, interfaceVtblIndex);
|
||||
}
|
||||
|
||||
// has interface vtbls?
|
||||
|
@ -235,14 +233,11 @@ void IrAggr::addFieldInitializers(
|
|||
}
|
||||
|
||||
IrClass *irClass = static_cast<IrClass *>(this);
|
||||
size_t inter_idx = irClass->interfacesWithVtbls.size();
|
||||
for (auto bc : *cd->vtblInterfaces) {
|
||||
constants.push_back(irClass->getInterfaceVtblSymbol(bc, inter_idx));
|
||||
constants.push_back(
|
||||
irClass->getInterfaceVtblSymbol(bc, interfaceVtblIndex));
|
||||
offset += target.ptrsize;
|
||||
inter_idx++;
|
||||
|
||||
if (populateInterfacesWithVtbls)
|
||||
irClass->interfacesWithVtbls.push_back(bc);
|
||||
++interfaceVtblIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
15
ir/iraggr.h
15
ir/iraggr.h
|
@ -103,7 +103,7 @@ private:
|
|||
void addFieldInitializers(llvm::SmallVectorImpl<llvm::Constant *> &constants,
|
||||
const VarInitMap &explicitInitializers,
|
||||
AggregateDeclaration *decl, unsigned &offset,
|
||||
bool populateInterfacesWithVtbls);
|
||||
unsigned &interfaceVtblIndex);
|
||||
};
|
||||
|
||||
/// Represents a struct.
|
||||
|
@ -122,7 +122,7 @@ private:
|
|||
/// Represents a class/interface.
|
||||
class IrClass : public IrAggr {
|
||||
public:
|
||||
explicit IrClass(ClassDeclaration *cd) : IrAggr(cd) {}
|
||||
explicit IrClass(ClassDeclaration *cd);
|
||||
|
||||
/// Creates the __ClassZ/__InterfaceZ symbol lazily.
|
||||
llvm::GlobalVariable *getClassInfoSymbol(bool define = false);
|
||||
|
@ -133,9 +133,6 @@ public:
|
|||
/// Defines all interface vtbls.
|
||||
void defineInterfaceVtbls();
|
||||
|
||||
/// Initialize interface.
|
||||
void initializeInterface();
|
||||
|
||||
private:
|
||||
/// Vtbl global.
|
||||
llvm::GlobalVariable *vtbl = nullptr;
|
||||
|
@ -157,6 +154,8 @@ private:
|
|||
/// Corresponds to the Interface instances needed to be output.
|
||||
std::vector<BaseClass *> interfacesWithVtbls;
|
||||
|
||||
void addInterfaceVtbls(ClassDeclaration *cd);
|
||||
|
||||
/// Builds the __ClassZ/__InterfaceZ initializer constant lazily.
|
||||
llvm::Constant *getClassInfoInit();
|
||||
|
||||
|
@ -165,10 +164,10 @@ private:
|
|||
|
||||
/// Returns the vtbl for an interface implementation.
|
||||
llvm::GlobalVariable *getInterfaceVtblSymbol(BaseClass *b,
|
||||
size_t interfaces_index);
|
||||
size_t interfaces_index,
|
||||
bool define = false);
|
||||
/// Defines the vtbl for an interface implementation.
|
||||
void defineInterfaceVtbl(BaseClass *b, bool new_inst,
|
||||
size_t interfaces_index);
|
||||
llvm::Constant *getInterfaceVtblInit(BaseClass *b, size_t interfaces_index);
|
||||
|
||||
/// Creates the __interfaceInfos symbol lazily.
|
||||
llvm::GlobalVariable *getInterfaceArraySymbol();
|
||||
|
|
|
@ -41,6 +41,28 @@
|
|||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
IrClass::IrClass(ClassDeclaration *cd) : IrAggr(cd) {
|
||||
addInterfaceVtbls(cd);
|
||||
|
||||
assert(interfacesWithVtbls.size() ==
|
||||
stripModifiers(type)->ctype->isClass()->getNumInterfaceVtbls() &&
|
||||
"inconsistent number of interface vtables in this class");
|
||||
}
|
||||
|
||||
void IrClass::addInterfaceVtbls(ClassDeclaration *cd) {
|
||||
if (cd->baseClass && !cd->isInterfaceDeclaration()) {
|
||||
addInterfaceVtbls(cd->baseClass);
|
||||
}
|
||||
|
||||
if (cd->vtblInterfaces) {
|
||||
for (auto bc : *cd->vtblInterfaces) {
|
||||
interfacesWithVtbls.push_back(bc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
LLGlobalVariable *IrClass::getVtblSymbol(bool define) {
|
||||
if (!vtbl) {
|
||||
const auto irMangle = getIRMangledVTableSymbolName(aggrdecl);
|
||||
|
@ -410,15 +432,14 @@ LLConstant *IrClass::getClassInfoInit() {
|
|||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
llvm::GlobalVariable *IrClass::getInterfaceVtblSymbol(BaseClass *b,
|
||||
size_t interfaces_index) {
|
||||
auto it = interfaceVtblMap.find({b->sym, interfaces_index});
|
||||
size_t interfaces_index,
|
||||
bool define) {
|
||||
LLGlobalVariable *gvar = nullptr;
|
||||
|
||||
const auto it = interfaceVtblMap.find({b->sym, interfaces_index});
|
||||
if (it != interfaceVtblMap.end()) {
|
||||
return it->second;
|
||||
}
|
||||
|
||||
ClassDeclaration *cd = aggrdecl->isClassDeclaration();
|
||||
assert(cd && "not a class aggregate");
|
||||
|
||||
gvar = it->second;
|
||||
} else {
|
||||
llvm::Type *vtblType =
|
||||
LLArrayType::get(getVoidPtrType(), b->sym->vtbl.length);
|
||||
|
||||
|
@ -430,7 +451,7 @@ llvm::GlobalVariable *IrClass::getInterfaceVtblSymbol(BaseClass *b,
|
|||
|
||||
OutBuffer mangledName;
|
||||
mangledName.writestring("_D");
|
||||
mangleToBuffer(cd, &mangledName);
|
||||
mangleToBuffer(aggrdecl, &mangledName);
|
||||
mangledName.writestring("11__interface");
|
||||
mangleToBuffer(b->sym, &mangledName);
|
||||
mangledName.writestring(thunkPrefixLen);
|
||||
|
@ -439,16 +460,22 @@ llvm::GlobalVariable *IrClass::getInterfaceVtblSymbol(BaseClass *b,
|
|||
|
||||
const auto irMangle = getIRMangledVarName(mangledName.peekChars(), LINKd);
|
||||
|
||||
LLGlobalVariable *gvar = declareGlobal(cd->loc, gIR->module, vtblType,
|
||||
irMangle, /*isConstant=*/true);
|
||||
gvar = declareGlobal(aggrdecl->loc, gIR->module, vtblType, irMangle,
|
||||
/*isConstant=*/true);
|
||||
|
||||
// insert into the vtbl map
|
||||
interfaceVtblMap.insert({{b->sym, interfaces_index}, gvar});
|
||||
}
|
||||
|
||||
if (define && !gvar->hasInitializer()) {
|
||||
auto init = getInterfaceVtblInit(b, interfaces_index);
|
||||
defineGlobal(gvar, init, aggrdecl);
|
||||
}
|
||||
|
||||
return gvar;
|
||||
}
|
||||
|
||||
void IrClass::defineInterfaceVtbl(BaseClass *b, bool new_instance,
|
||||
LLConstant *IrClass::getInterfaceVtblInit(BaseClass *b,
|
||||
size_t interfaces_index) {
|
||||
IF_LOG Logger::println(
|
||||
"Defining vtbl for implementation of interface %s in class %s",
|
||||
|
@ -459,6 +486,7 @@ void IrClass::defineInterfaceVtbl(BaseClass *b, bool new_instance,
|
|||
assert(cd && "not a class aggregate");
|
||||
|
||||
FuncDeclarations vtbl_array;
|
||||
const bool new_instance = b->sym == cd;
|
||||
b->fillVtbl(cd, &vtbl_array, new_instance);
|
||||
|
||||
std::vector<llvm::Constant *> constants;
|
||||
|
@ -623,9 +651,7 @@ void IrClass::defineInterfaceVtbl(BaseClass *b, bool new_instance,
|
|||
llvm::Constant *vtbl_constant = LLConstantArray::get(
|
||||
LLArrayType::get(voidPtrTy, constants.size()), constants);
|
||||
|
||||
// define the global
|
||||
const auto gvar = getInterfaceVtblSymbol(b, interfaces_index);
|
||||
defineGlobal(gvar, vtbl_constant, cd);
|
||||
return vtbl_constant;
|
||||
}
|
||||
|
||||
void IrClass::defineInterfaceVtbls() {
|
||||
|
@ -635,11 +661,7 @@ void IrClass::defineInterfaceVtbls() {
|
|||
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
auto baseClass = interfacesWithVtbls[i];
|
||||
|
||||
// false when it's not okay to use functions from super classes
|
||||
bool newinsts = (baseClass->sym == aggrdecl->isClassDeclaration());
|
||||
|
||||
defineInterfaceVtbl(baseClass, newinsts, i);
|
||||
getInterfaceVtblSymbol(baseClass, i, /*define=*/true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -700,9 +722,7 @@ LLConstant *IrClass::getClassInfoInterfaces() {
|
|||
if (cd->isInterfaceDeclaration()) {
|
||||
vtb = DtoConstSlice(DtoConstSize_t(0), getNullValue(voidptrptr_type));
|
||||
} else {
|
||||
auto itv = interfaceVtblMap.find({it->sym, i});
|
||||
assert(itv != interfaceVtblMap.end() && "interface vtbl not found");
|
||||
vtb = itv->second;
|
||||
vtb = getInterfaceVtblSymbol(it, i);
|
||||
vtb = DtoBitCast(vtb, voidptrptr_type);
|
||||
auto vtblSize = itc->getVtblType()->getNumContainedTypes();
|
||||
vtb = DtoConstSlice(DtoConstSize_t(vtblSize), vtb);
|
||||
|
@ -742,20 +762,3 @@ LLConstant *IrClass::getClassInfoInterfaces() {
|
|||
// return as a slice
|
||||
return DtoConstSlice(DtoConstSize_t(cd->vtblInterfaces->length), ptr);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void IrClass::initializeInterface() {
|
||||
InterfaceDeclaration *base = aggrdecl->isInterfaceDeclaration();
|
||||
assert(base && "not interface");
|
||||
|
||||
// has interface vtbls?
|
||||
if (!base->vtblInterfaces) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto bc : *base->vtblInterfaces) {
|
||||
// add to the interface list
|
||||
interfacesWithVtbls.push_back(bc);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue