mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-04-28 22:21:31 +03:00
Use opaque [N x i8*] for vtables
This fixes the forward-referencing issue #1741.
This commit is contained in:
parent
e1394fad5f
commit
16d15e01cb
8 changed files with 46 additions and 131 deletions
|
@ -390,7 +390,6 @@ LLValue *DtoVirtualFunctionPointer(DValue *inst, FuncDeclaration *fdecl,
|
|||
|
||||
LLValue *funcval = vthis;
|
||||
// get the vtbl for objects
|
||||
stripModifiers(inst->type->toBasetype())->ctype->isClass()->getVtblType(true);
|
||||
funcval = DtoGEPi(funcval, 0, 0);
|
||||
// load vtbl ptr
|
||||
funcval = DtoLoad(funcval);
|
||||
|
@ -398,12 +397,12 @@ LLValue *DtoVirtualFunctionPointer(DValue *inst, FuncDeclaration *fdecl,
|
|||
std::string vtblname = name;
|
||||
vtblname.append("@vtbl");
|
||||
funcval = DtoGEPi(funcval, 0, fdecl->vtblIndex, vtblname.c_str());
|
||||
// load funcptr
|
||||
// load opaque pointer
|
||||
funcval = DtoAlignedLoad(funcval);
|
||||
|
||||
IF_LOG Logger::cout() << "funcval: " << *funcval << '\n';
|
||||
|
||||
// cast to final funcptr type
|
||||
// cast to funcptr type
|
||||
funcval = DtoBitCast(funcval, getPtrToType(DtoFunctionType(fdecl)));
|
||||
|
||||
// postpone naming until after casting to get the name in call instructions
|
||||
|
|
|
@ -2664,13 +2664,12 @@ public:
|
|||
LLValue *val = DtoRVal(ex);
|
||||
|
||||
// Get and load vtbl pointer.
|
||||
stripModifiers(t)->ctype->isClass()->getVtblType(true);
|
||||
llvm::Value *vtbl = DtoLoad(DtoGEPi(val, 0, 0));
|
||||
|
||||
// TypeInfo ptr is first vtbl entry.
|
||||
llvm::Value *typinf = DtoGEPi(vtbl, 0, 0);
|
||||
|
||||
Type *resultType = Type::typeinfoclass->type;
|
||||
Type *resultType;
|
||||
if (static_cast<TypeClass *>(t)->sym->isInterfaceDeclaration()) {
|
||||
// For interfaces, the first entry in the vtbl is actually a pointer
|
||||
// to an Interface instance, which has the type info as its first
|
||||
|
@ -2678,6 +2677,9 @@ public:
|
|||
resultType = Type::typeinfointerface->type;
|
||||
typinf = DtoLoad(
|
||||
DtoBitCast(typinf, DtoType(resultType->pointerTo()->pointerTo())));
|
||||
} else {
|
||||
resultType = Type::typeinfoclass->type;
|
||||
typinf = DtoBitCast(typinf, DtoType(resultType->pointerTo()));
|
||||
}
|
||||
|
||||
result = new DLValue(resultType, typinf);
|
||||
|
|
|
@ -49,7 +49,7 @@ LLGlobalVariable *IrAggr::getVtblSymbol() {
|
|||
// create the vtblZ symbol
|
||||
auto initname = getMangledVTableSymbolName(aggrdecl);
|
||||
|
||||
LLType *vtblTy = stripModifiers(type)->ctype->isClass()->getVtblType(false);
|
||||
LLType *vtblTy = stripModifiers(type)->ctype->isClass()->getVtblType();
|
||||
|
||||
vtbl =
|
||||
getOrCreateGlobal(aggrdecl->loc, gIR->module, vtblTy, true,
|
||||
|
@ -165,11 +165,13 @@ LLConstant *IrAggr::getVtblInit() {
|
|||
std::vector<llvm::Constant *> constants;
|
||||
constants.reserve(cd->vtbl.dim);
|
||||
|
||||
const auto voidPtrType = getVoidPtrType();
|
||||
|
||||
// start with the classinfo
|
||||
llvm::Constant *c;
|
||||
if (!cd->isCPPclass()) {
|
||||
c = getClassInfoSymbol();
|
||||
c = DtoBitCast(c, DtoType(Type::typeinfoclass->type));
|
||||
c = DtoBitCast(c, voidPtrType);
|
||||
constants.push_back(c);
|
||||
}
|
||||
|
||||
|
@ -220,26 +222,12 @@ LLConstant *IrAggr::getVtblInit() {
|
|||
}
|
||||
}
|
||||
}
|
||||
constants.push_back(c);
|
||||
constants.push_back(DtoBitCast(c, voidPtrType));
|
||||
}
|
||||
|
||||
// build the constant struct
|
||||
LLType *vtblTy = stripModifiers(type)->ctype->isClass()->getVtblType(true);
|
||||
#ifndef NDEBUG
|
||||
size_t nc = constants.size();
|
||||
|
||||
for (size_t i = 0; i < nc; ++i) {
|
||||
if (constants[i]->getType() != vtblTy->getContainedType(i)) {
|
||||
llvm::errs() << "type mismatch for entry # " << i
|
||||
<< " in vtbl initializer\n";
|
||||
|
||||
constants[i]->getType()->dump();
|
||||
vtblTy->getContainedType(i)->dump();
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
constVtbl = LLConstantStruct::get(isaStruct(vtblTy), constants);
|
||||
// build the constant array
|
||||
LLArrayType *vtblTy = LLArrayType::get(voidPtrType, constants.size());
|
||||
constVtbl = LLConstantArray::get(vtblTy, constants);
|
||||
|
||||
return constVtbl;
|
||||
}
|
||||
|
@ -277,6 +265,8 @@ llvm::GlobalVariable *IrAggr::getInterfaceVtbl(BaseClass *b, bool new_instance,
|
|||
std::vector<llvm::Constant *> constants;
|
||||
constants.reserve(vtbl_array.dim);
|
||||
|
||||
const auto voidPtrTy = getVoidPtrType();
|
||||
|
||||
if (!b->sym->isCPPinterface()) { // skip interface info for CPP interfaces
|
||||
// index into the interfaces array
|
||||
llvm::Constant *idxs[2] = {DtoConstSize_t(0),
|
||||
|
@ -289,7 +279,7 @@ llvm::GlobalVariable *IrAggr::getInterfaceVtbl(BaseClass *b, bool new_instance,
|
|||
#endif
|
||||
interfaceInfosZ, idxs, true);
|
||||
|
||||
constants.push_back(c);
|
||||
constants.push_back(DtoBitCast(c, voidPtrTy));
|
||||
}
|
||||
|
||||
// Thunk prefix
|
||||
|
@ -306,7 +296,7 @@ llvm::GlobalVariable *IrAggr::getInterfaceVtbl(BaseClass *b, bool new_instance,
|
|||
// FIXME
|
||||
// why is this null?
|
||||
// happens for mini/s.d
|
||||
constants.push_back(getNullValue(getVoidPtrType()));
|
||||
constants.push_back(getNullValue(voidPtrTy));
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -327,7 +317,7 @@ llvm::GlobalVariable *IrAggr::getInterfaceVtbl(BaseClass *b, bool new_instance,
|
|||
if (fd->interfaceVirtual)
|
||||
thunkOffset -= fd->interfaceVirtual->offset;
|
||||
if (thunkOffset == 0) {
|
||||
constants.push_back(irFunc->func);
|
||||
constants.push_back(DtoBitCast(irFunc->func, voidPtrTy));
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -434,12 +424,12 @@ llvm::GlobalVariable *IrAggr::getInterfaceVtbl(BaseClass *b, bool new_instance,
|
|||
gIR->funcGenStates.pop_back();
|
||||
}
|
||||
|
||||
constants.push_back(thunk);
|
||||
constants.push_back(DtoBitCast(thunk, voidPtrTy));
|
||||
}
|
||||
|
||||
// build the vtbl constant
|
||||
llvm::Constant *vtbl_constant =
|
||||
LLConstantStruct::getAnon(gIR->context(), constants, false);
|
||||
llvm::Constant *vtbl_constant = LLConstantArray::get(
|
||||
LLArrayType::get(voidPtrTy, constants.size()), constants);
|
||||
|
||||
std::string mangledName("_D");
|
||||
mangledName.append(mangle(cd));
|
||||
|
@ -526,7 +516,8 @@ LLConstant *IrAggr::getClassInfoInterfaces() {
|
|||
assert(itv != interfaceVtblMap.end() && "interface vtbl not found");
|
||||
vtb = itv->second;
|
||||
vtb = DtoBitCast(vtb, voidptrptr_type);
|
||||
vtb = DtoConstSlice(DtoConstSize_t(itc->getVtblSize()), vtb);
|
||||
auto vtblSize = itc->getVtblType()->getNumContainedTypes();
|
||||
vtb = DtoConstSlice(DtoConstSize_t(vtblSize), vtb);
|
||||
}
|
||||
|
||||
// offset
|
||||
|
|
|
@ -25,10 +25,7 @@
|
|||
|
||||
IrTypeClass::IrTypeClass(ClassDeclaration *cd)
|
||||
: IrTypeAggr(cd), cd(cd), tc(static_cast<TypeClass *>(cd->type)) {
|
||||
std::string vtbl_name(cd->toPrettyChars());
|
||||
vtbl_name.append(".__vtbl");
|
||||
vtbl_type = LLStructType::create(gIR->context(), vtbl_name);
|
||||
vtbl_size = cd->vtbl.dim;
|
||||
vtbl_type = LLArrayType::get(getVoidPtrType(), cd->vtbl.dim);
|
||||
}
|
||||
|
||||
void IrTypeClass::addClassData(AggrTypeBuilder &builder,
|
||||
|
@ -52,15 +49,10 @@ void IrTypeClass::addClassData(AggrTypeBuilder &builder,
|
|||
IF_LOG Logger::println("Adding interface vtbl for %s",
|
||||
b->sym->toPrettyChars());
|
||||
|
||||
FuncDeclarations arr;
|
||||
b->fillVtbl(cd, &arr, currCd == cd);
|
||||
|
||||
// add to the interface map
|
||||
addInterfaceToMap(b->sym, builder.currentFieldIndex());
|
||||
Type* first = b->sym->isCPPinterface() ? nullptr : interfacePtrType;
|
||||
const auto ivtblType =
|
||||
llvm::StructType::get(gIR->context(), buildVtblType(first, &arr));
|
||||
builder.addType(llvm::PointerType::get(ivtblType, 0), Target::ptrsize);
|
||||
auto vtblTy = LLArrayType::get(getVoidPtrType(), b->sym->vtbl.dim);
|
||||
builder.addType(llvm::PointerType::get(vtblTy, 0), Target::ptrsize);
|
||||
|
||||
++num_interface_vtbls;
|
||||
}
|
||||
|
@ -122,83 +114,10 @@ IrTypeClass *IrTypeClass::get(ClassDeclaration *cd) {
|
|||
return t;
|
||||
}
|
||||
|
||||
std::vector<llvm::Type *>
|
||||
IrTypeClass::buildVtblType(Type *first, FuncDeclarations *vtbl_array) {
|
||||
IF_LOG Logger::println("Building vtbl type for class %s",
|
||||
cd->toPrettyChars());
|
||||
LOG_SCOPE;
|
||||
|
||||
std::vector<llvm::Type *> types;
|
||||
types.reserve(vtbl_array->dim);
|
||||
|
||||
auto I = vtbl_array->begin();
|
||||
// first comes the classinfo for D interfaces
|
||||
if (first) {
|
||||
types.push_back(DtoType(first));
|
||||
++I;
|
||||
}
|
||||
|
||||
// then come the functions
|
||||
for (auto E = vtbl_array->end(); I != E; ++I) {
|
||||
FuncDeclaration *fd = *I;
|
||||
if (fd == nullptr) {
|
||||
// FIXME: This stems from the ancient D1 days – can it still happen?
|
||||
types.push_back(getVoidPtrType());
|
||||
continue;
|
||||
}
|
||||
|
||||
IF_LOG Logger::println("Adding type of %s", fd->toPrettyChars());
|
||||
|
||||
// If inferring return type and semantic3 has not been run, do it now.
|
||||
// This pops up in some other places in the frontend as well, however
|
||||
// it is probably a bug that it still occurs that late.
|
||||
if (!fd->type->nextOf() && fd->inferRetType) {
|
||||
Logger::println("Running late functionSemantic to infer return type.");
|
||||
TemplateInstance *spec = fd->isSpeculative();
|
||||
unsigned int olderrs = global.errors;
|
||||
fd->functionSemantic();
|
||||
if (spec && global.errors != olderrs) {
|
||||
spec->errors = global.errors - olderrs;
|
||||
}
|
||||
}
|
||||
|
||||
if (!fd->type->nextOf()) {
|
||||
// Return type of the function has not been inferred. This seems to
|
||||
// happen with virtual functions and is probably a frontend bug.
|
||||
IF_LOG Logger::println("Broken function type, semanticRun: %d",
|
||||
fd->semanticRun);
|
||||
types.push_back(getVoidPtrType());
|
||||
continue;
|
||||
}
|
||||
|
||||
types.push_back(getPtrToType(DtoFunctionType(fd)));
|
||||
}
|
||||
|
||||
return types;
|
||||
}
|
||||
|
||||
llvm::Type *IrTypeClass::getLLType() { return llvm::PointerType::get(type, 0); }
|
||||
|
||||
llvm::Type *IrTypeClass::getMemoryLLType() { return type; }
|
||||
|
||||
llvm::StructType *IrTypeClass::getVtblType(bool notOpaque) {
|
||||
if (notOpaque && vtbl_type->isOpaque()) {
|
||||
FuncDeclarations vtbl;
|
||||
vtbl.reserve(cd->vtbl.dim);
|
||||
if (!cd->isCPPclass())
|
||||
vtbl.push(nullptr);
|
||||
for (size_t i = cd->vtblOffset(); i < cd->vtbl.dim; ++i) {
|
||||
FuncDeclaration *fd = cd->vtbl[i]->isFuncDeclaration();
|
||||
assert(fd);
|
||||
vtbl.push(fd);
|
||||
}
|
||||
Type* first = cd->isCPPclass() ? nullptr : Type::typeinfoclass->type;
|
||||
vtbl_type->setBody(buildVtblType(first, &vtbl));
|
||||
}
|
||||
|
||||
return vtbl_type;
|
||||
}
|
||||
|
||||
size_t IrTypeClass::getInterfaceIndex(ClassDeclaration *inter) {
|
||||
auto it = interfaceMap.find(inter);
|
||||
if (it == interfaceMap.end()) {
|
||||
|
|
|
@ -37,16 +37,13 @@ public:
|
|||
llvm::Type *getMemoryLLType();
|
||||
|
||||
/// Returns the vtable type for this class.
|
||||
llvm::StructType *getVtblType(bool notOpaque);
|
||||
llvm::ArrayType *getVtblType() { return vtbl_type; }
|
||||
|
||||
/// Get index to interface implementation.
|
||||
/// Returns the index of a specific interface implementation in this
|
||||
/// class or ~0 if not found.
|
||||
size_t getInterfaceIndex(ClassDeclaration *inter);
|
||||
|
||||
/// Returns the total number of pointers in the vtable.
|
||||
unsigned getVtblSize() { return vtbl_size; }
|
||||
|
||||
/// Returns the number of interface implementations (vtables) in this
|
||||
/// class.
|
||||
unsigned getNumInterfaceVtbls() { return num_interface_vtbls; }
|
||||
|
@ -61,10 +58,7 @@ protected:
|
|||
TypeClass *tc = nullptr;
|
||||
|
||||
/// Vtable type.
|
||||
llvm::StructType *vtbl_type = nullptr;
|
||||
|
||||
/// Number of pointers in vtable.
|
||||
unsigned vtbl_size = 0;
|
||||
llvm::ArrayType *vtbl_type = nullptr;
|
||||
|
||||
/// Number of interface implementations (vtables) in this class.
|
||||
unsigned num_interface_vtbls = 0;
|
||||
|
@ -78,13 +72,6 @@ protected:
|
|||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Builds a vtable type given the type of the first entry and an array
|
||||
/// of all entries.
|
||||
/// If first is nullptr for C++ interfaces, the vtbl_array will be added
|
||||
/// as is without replacing the first entry.
|
||||
std::vector<llvm::Type *> buildVtblType(Type *first,
|
||||
FuncDeclarations *vtbl_array);
|
||||
|
||||
/// Adds the data members for the given class to the type builder, including
|
||||
/// those inherited from base classes/interfaces.
|
||||
void addClassData(AggrTypeBuilder &builder, ClassDeclaration *currCd);
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// Tests in-place construction of structs returned by inline assembly (issue #1823).
|
||||
|
||||
// Target Win64 for simplicity (e.g., 4x32-bit struct not returned in memory for non-Windows x64).
|
||||
// REQUIRES: target_X86
|
||||
// RUN: %ldc -mtriple=x86_64-pc-windows-msvc -c -output-ll -of=%t.ll %s && FileCheck %s < %t.ll
|
||||
|
||||
import ldc.llvmasm;
|
||||
|
|
13
tests/compilable/gh1741.d
Normal file
13
tests/compilable/gh1741.d
Normal file
|
@ -0,0 +1,13 @@
|
|||
// Explicitly target Linux x86_64.
|
||||
// REQUIRES: target_X86
|
||||
// RUN: %ldc -mtriple=x86_64-pc-linux-gnu -c %s %S/inputs/gh1741b.d
|
||||
|
||||
struct S
|
||||
{
|
||||
C c;
|
||||
}
|
||||
|
||||
class C
|
||||
{
|
||||
@property s() { return S(); }
|
||||
}
|
3
tests/compilable/inputs/gh1741b.d
Normal file
3
tests/compilable/inputs/gh1741b.d
Normal file
|
@ -0,0 +1,3 @@
|
|||
import gh1741;
|
||||
|
||||
S s;
|
Loading…
Add table
Add a link
Reference in a new issue