Fix v1.31 regression wrt. unresolved IrAggr (#4312)

And use `IrTypeClass::getVtblType()` to get the vtable LLVM array
type, instead of deriving it from the `IrClass::getVtblSymbol()`
global (invoking that function may define the vtable!).

I've hit some compiler crashes for the Symmetry code base, on
Windows only. I guess the problem surfaced due to
`-link-defaultlib-shared`, which on Windows causes some vtables of
instantiated classes to be defined whenever accessing the vtable
symbol. I don't have a reduced test case unfortunately.
This commit is contained in:
Martin Kinkelin 2023-02-06 17:02:07 +01:00 committed by GitHub
parent 58c4b8bdae
commit 5f46c65ab5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 37 additions and 39 deletions

View file

@ -75,19 +75,20 @@ void DtoResolveClass(ClassDeclaration *cd) {
DValue *DtoNewClass(const Loc &loc, TypeClass *tc, NewExp *newexp) {
// resolve type
DtoResolveClass(tc->sym);
const auto irClass = getIrAggr(tc->sym);
// allocate
LLValue *mem;
bool doInit = true;
if (newexp->onstack) {
mem = DtoRawAlloca(getIrAggr(tc->sym)->getLLStructType(), tc->sym->alignsize,
mem = DtoRawAlloca(irClass->getLLStructType(), tc->sym->alignsize,
".newclass_alloca");
} else {
const bool useEHAlloc = global.params.ehnogc && newexp->thrownew;
llvm::Function *fn = getRuntimeFunction(
loc, gIR->module, useEHAlloc ? "_d_newThrowable" : "_d_allocclass");
LLConstant *ci = DtoBitCast(getIrAggr(tc->sym)->getClassInfoSymbol(),
DtoType(getClassInfoType()));
LLConstant *ci =
DtoBitCast(irClass->getClassInfoSymbol(), DtoType(getClassInfoType()));
mem = gIR->CreateCallOrInvoke(
fn, ci, useEHAlloc ? ".newthrowable_alloc" : ".newclass_gc_alloc");
mem = DtoBitCast(mem, DtoType(tc),
@ -105,7 +106,7 @@ DValue *DtoNewClass(const Loc &loc, TypeClass *tc, NewExp *newexp) {
LOG_SCOPE;
unsigned idx = getFieldGEPIndex(tc->sym, tc->sym->vthis);
LLValue *src = DtoRVal(newexp->thisexp);
LLValue *dst = DtoGEP(getIrAggr(tc->sym)->getLLStructType(), mem, 0, idx);
LLValue *dst = DtoGEP(irClass->getLLStructType(), mem, 0, idx);
IF_LOG Logger::cout() << "dst: " << *dst << "\nsrc: " << *src << '\n';
DtoStore(src, DtoBitCast(dst, getPtrToType(src->getType())));
}
@ -152,7 +153,7 @@ void DtoInitClass(TypeClass *tc, LLValue *dst) {
const bool isCPPclass = tc->sym->isCPPclass() ? true : false;
if (!isCPPclass) {
tmp = DtoGEP(st, dst, 0, 1, "monitor");
val = LLConstant::getNullValue(getVoidPtrType());
val = LLConstant::getNullValue(st->getElementType(1));
DtoStore(val, tmp);
}
@ -197,9 +198,9 @@ void DtoFinalizeScopeClass(const Loc &loc, DValue *dval,
}
bool hasDtor = false;
auto cd = dval->type->toBasetype()->isTypeClass()->sym;
for (; cd; cd = cd->baseClass) {
if (cd->dtor) {
const auto cd = dval->type->toBasetype()->isTypeClass()->sym;
for (auto cd2 = cd; cd2; cd2 = cd2->baseClass) {
if (cd2->dtor) {
hasDtor = true;
break;
}
@ -216,7 +217,7 @@ void DtoFinalizeScopeClass(const Loc &loc, DValue *dval,
llvm::BasicBlock *endbb = gIR->insertBBAfter(ifbb, "endif");
llvm::StructType *st =
getIrAggr(static_cast<TypeClass *>(dval->type)->sym)->getLLStructType();
isaStruct(getIrType(cd->type, true)->isClass()->getMemoryLLType());
const auto monitor =
DtoLoad(st->getElementType(1), DtoGEP(st, inst, 0, 1), ".monitor");
const auto hasMonitor =
@ -425,7 +426,7 @@ LLValue *DtoVirtualFunctionPointer(DValue *inst, FuncDeclaration *fdecl) {
// sanity checks
assert(fdecl->isVirtual());
assert(!fdecl->isFinalFunc());
TypeClass * tc = inst->type->toBasetype()->isTypeClass();
TypeClass *tc = inst->type->toBasetype()->isTypeClass();
assert(tc);
// slot 0 is always ClassInfo/Interface* unless it is a CPP class
assert(fdecl->vtblIndex > 0 ||
@ -436,20 +437,20 @@ LLValue *DtoVirtualFunctionPointer(DValue *inst, FuncDeclaration *fdecl) {
LLValue *vthis = DtoRVal(inst);
IF_LOG Logger::cout() << "vthis: " << *vthis << '\n';
IrClass * irc = getIrAggr(tc->sym, true);
const auto irtc = getIrType(tc->sym->type, true)->isClass();
const auto vtblType = irtc->getVtblType();
LLValue *funcval = vthis;
// get the vtbl for objects
llvm::GlobalVariable* vtblsym = irc->getVtblSymbol();
funcval = DtoGEP(irc->getLLStructType(), funcval, 0u, 0);
funcval = DtoGEP(irtc->getMemoryLLType(), funcval, 0u, 0);
// load vtbl ptr
funcval = DtoLoad(vtblsym->getType(), funcval);
funcval = DtoLoad(vtblType->getPointerTo(), funcval);
// index vtbl
const std::string name = fdecl->toChars();
const auto vtblname = name + "@vtbl";
funcval = DtoGEP(vtblsym->getValueType(),
funcval, 0, fdecl->vtblIndex, vtblname.c_str());
funcval = DtoGEP(vtblType, funcval, 0, fdecl->vtblIndex, vtblname.c_str());
// load opaque pointer
funcval = DtoAlignedLoad(getVoidPtrType(), funcval);
funcval = DtoAlignedLoad(vtblType->getElementType(), funcval);
IF_LOG Logger::cout() << "funcval: " << *funcval << '\n';

View file

@ -39,6 +39,7 @@
#include "ir/irfunction.h"
#include "ir/irmodule.h"
#include "ir/irtypeaggr.h"
#include "ir/irtypeclass.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/ManagedStatic.h"
@ -1895,16 +1896,12 @@ DLValue *DtoIndexAggregate(LLValue *src, AggregateDeclaration *ad,
// Cast the pointer we got to the canonical struct type the indices are
// based on.
LLType *st = nullptr;
LLType *pst = nullptr;
if (ad->isClassDeclaration()) {
st = getIrAggr(ad)->getLLStructType();
pst = DtoType(ad->type);
if (auto irtc = irTypeAggr->isClass()) {
st = irtc->getMemoryLLType();
} else {
st = irTypeAggr->getLLType();
}
else {
st = DtoType(ad->type);
pst = getPtrToType(st);
}
ptr = DtoBitCast(ptr, pst);
ptr = DtoBitCast(ptr, st->getPointerTo());
ptr = DtoGEP(st, ptr, 0, off);
ty = isaStruct(st)->getElementType(off);
}

View file

@ -46,7 +46,8 @@ LLValue *loadThisPtr(AggregateDeclaration *ad, IrFunction &irfunc) {
}
LLValue *indexVThis(AggregateDeclaration *ad, LLValue* val) {
llvm::StructType *st = getIrAggr(ad, true)->getLLStructType();
DtoResolveDsymbol(ad);
llvm::StructType *st = getIrAggr(ad)->getLLStructType();
unsigned idx = getVthisIdx(ad);
return DtoLoad(st->getElementType(idx),
DtoGEP(st, val, 0, idx, ".vthis"));
@ -226,7 +227,7 @@ void DtoResolveNestedContext(const Loc &loc, AggregateDeclaration *decl,
DtoResolveDsymbol(decl);
unsigned idx = getVthisIdx(decl);
llvm::StructType *st = getIrAggr(decl, true)->getLLStructType();
llvm::StructType *st = getIrAggr(decl)->getLLStructType();
LLValue *gep = DtoGEP(st, value, 0, idx, ".vthis");
DtoStore(DtoBitCast(nest, st->getElementType(idx)), gep);
}

View file

@ -2757,22 +2757,22 @@ public:
return;
}
if (Expression *ex = isExpression(e->obj)) {
Type *t = ex->type->toBasetype();
assert(t->ty == TY::Tclass);
const auto tc = ex->type->toBasetype()->isTypeClass();
assert(tc);
ClassDeclaration *sym = static_cast<TypeClass *>(t)->sym;
IrClass *irc = getIrAggr(sym, true);
const auto irtc = getIrType(tc->sym->type, true)->isClass();
const auto vtblType = irtc->getVtblType();
LLValue *val = DtoRVal(ex);
// Get and load vtbl pointer.
llvm::GlobalVariable* vtblsym = irc->getVtblSymbol();
llvm::Value *vtbl = DtoLoad(vtblsym->getType(), DtoGEP(irc->getLLStructType(), val, 0u, 0));
llvm::Value *vtbl = DtoLoad(vtblType->getPointerTo(),
DtoGEP(irtc->getMemoryLLType(), val, 0u, 0));
// TypeInfo ptr is first vtbl entry.
llvm::Value *typinf = DtoGEP(vtblsym->getValueType(), vtbl, 0u, 0);
llvm::Value *typinf = DtoGEP(vtblType, vtbl, 0u, 0);
Type *resultType;
if (sym->isInterfaceDeclaration()) {
if (tc->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
// member, so we have to add an extra layer of indirection.

View file

@ -441,9 +441,8 @@ void buildTypeInfo(TypeInfoDeclaration *decl) {
assert(isBuiltin && "existing global expected to be the init symbol of a "
"built-in TypeInfo");
} else {
DtoType(decl->type);
TypeClass *tclass = decl->type->isTypeClass();
LLType *type = getIrType(tclass)->isClass()->getMemoryLLType();
TypeClass *tc = decl->type->isTypeClass();
LLType *type = getIrType(tc->sym->type, true)->isClass()->getMemoryLLType();
// We need to keep the symbol mutable as the type is not declared as
// immutable on the D side, and e.g. synchronized() can be used on the
// implicit monitor.