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