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

View file

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

View file

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

View file

@ -2757,22 +2757,22 @@ public:
return; return;
} }
if (Expression *ex = isExpression(e->obj)) { if (Expression *ex = isExpression(e->obj)) {
Type *t = ex->type->toBasetype(); const auto tc = ex->type->toBasetype()->isTypeClass();
assert(t->ty == TY::Tclass); assert(tc);
ClassDeclaration *sym = static_cast<TypeClass *>(t)->sym; const auto irtc = getIrType(tc->sym->type, true)->isClass();
IrClass *irc = getIrAggr(sym, true); const auto vtblType = irtc->getVtblType();
LLValue *val = DtoRVal(ex); LLValue *val = DtoRVal(ex);
// Get and load vtbl pointer. // Get and load vtbl pointer.
llvm::GlobalVariable* vtblsym = irc->getVtblSymbol(); llvm::Value *vtbl = DtoLoad(vtblType->getPointerTo(),
llvm::Value *vtbl = DtoLoad(vtblsym->getType(), DtoGEP(irc->getLLStructType(), val, 0u, 0)); DtoGEP(irtc->getMemoryLLType(), val, 0u, 0));
// TypeInfo ptr is first vtbl entry. // 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; Type *resultType;
if (sym->isInterfaceDeclaration()) { if (tc->sym->isInterfaceDeclaration()) {
// For interfaces, the first entry in the vtbl is actually a pointer // For interfaces, the first entry in the vtbl is actually a pointer
// to an Interface instance, which has the type info as its first // to an Interface instance, which has the type info as its first
// member, so we have to add an extra layer of indirection. // 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 " assert(isBuiltin && "existing global expected to be the init symbol of a "
"built-in TypeInfo"); "built-in TypeInfo");
} else { } else {
DtoType(decl->type); TypeClass *tc = decl->type->isTypeClass();
TypeClass *tclass = decl->type->isTypeClass(); LLType *type = getIrType(tc->sym->type, true)->isClass()->getMemoryLLType();
LLType *type = getIrType(tclass)->isClass()->getMemoryLLType();
// We need to keep the symbol mutable as the type is not declared as // 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 // immutable on the D side, and e.g. synchronized() can be used on the
// implicit monitor. // implicit monitor.