//===-- irstruct.cpp ------------------------------------------------------===// // // LDC – the LLVM D compiler // // This file is distributed under the BSD-style LDC license. See the LICENSE // file for details. // //===----------------------------------------------------------------------===// #include "dmd/errors.h" #include "dmd/mangle.h" #include "dmd/mtype.h" #include "dmd/template.h" #include "gen/irstate.h" #include "gen/llvmhelpers.h" #include "gen/logger.h" #include "gen/mangling.h" #include "gen/rttibuilder.h" #include "gen/runtime.h" #include "gen/structs.h" #include "gen/tollvm.h" #include "gen/typinf.h" #include "ir/iraggr.h" #include "ir/irtypeclass.h" using namespace dmd; namespace { LLStructType* getTypeInfoStructMemType() { Type *t = getStructTypeInfoType(); IrTypeClass *tc = getIrType(t, true)->isClass(); assert(tc && "invalid TypeInfo_Struct type"); return llvm::cast(tc->getMemoryLLType()); } } LLGlobalVariable* IrStruct::getTypeInfoSymbol(bool define) { if (!typeInfo) { OutBuffer mangledName; mangledName.writestring("TypeInfo_S"); mangleToBuffer(aggrdecl, mangledName); const auto length = mangledName.length(); mangledName.prependstring(("_D" + std::to_string(length)).c_str()); mangledName.writestring("6__initZ"); const auto irMangle = getIRMangledVarName(mangledName.peekChars(), LINK::d); // 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. const bool isConstant = false; // Struct TypeInfos are emitted into each referencing CU. const bool useDLLImport = false; typeInfo = declareGlobal(aggrdecl->loc, gIR->module, getTypeInfoStructMemType(), irMangle, isConstant, false, useDLLImport); emitTypeInfoMetadata(typeInfo, aggrdecl->type); if (!define) define = defineOnDeclare(aggrdecl, /*isFunction=*/false); } if (define) { auto init = getTypeInfoInit(); if (!typeInfo->hasInitializer()) defineGlobal(typeInfo, init, aggrdecl); } return typeInfo; } LLConstant *IrStruct::getTypeInfoInit() { // The upstream implementation is in dmd/todt.d, // TypeInfoDtVisitor.visit(TypeInfoStructDeclaration). if (constTypeInfo) { return constTypeInfo; } auto sd = aggrdecl->isStructDeclaration(); IF_LOG Logger::println("Defining TypeInfo for struct: %s", sd->toChars()); LOG_SCOPE; // we need (dummy) TypeInfos for opaque structs too const bool isOpaque = !sd->members; // make sure xtoHash/xopEquals/xopCmp etc. are semantically analyzed if (!isOpaque && sd->semanticRun < PASS::semantic3done) { Logger::println( "Struct hasn't had semantic3 yet, calling semanticTypeInfoMembers()"); semanticTypeInfoMembers(sd); } TypeStruct *ts = sd->type->isTypeStruct(); // check declaration in object.d const auto structTypeInfoType = getStructTypeInfoType(); const auto structTypeInfoDecl = Type::typeinfostruct; // For x86_64 (except Win64) and AAPCS64 targets, class TypeInfo_Struct // contains 2 additional fields (m_arg1/m_arg2) which are used for the // TypeInfo-based core.stdc.stdarg.va_arg implementations in druntime. const auto &triple = *global.params.targetTriple; const auto arch = triple.getArch(); const bool withArgTypes = (arch == llvm::Triple::x86_64 && !triple.isOSWindows()) || (!triple.isOSDarwin() && // Apple uses a simpler scheme (arch == llvm::Triple::aarch64 || arch == llvm::Triple::aarch64_be)); const unsigned expectedFields = 11 + (withArgTypes ? 2 : 0); const unsigned actualFields = structTypeInfoDecl->fields.length - 1; // union of xdtor/xdtorti counts as 2 overlapping fields if (actualFields != expectedFields) { error(Loc(), "Unexpected number of `object.TypeInfo_Struct` fields; " "druntime version does not match compiler"); fatal(); } RTTIBuilder b(structTypeInfoType); // string mangledName if (isOpaque) { b.push_null_void_array(); } else { b.push_string(ts->deco); } // void[] m_init // The protocol is to write a null pointer for zero-initialized structs. // The length field is always needed for tsize(). if (isOpaque) { b.push_null_void_array(); } else { llvm::Constant *initPtr; if (ts->isZeroInit(Loc())) { initPtr = getNullPtr(); } else { initPtr = getInitSymbol(); } b.push_void_array(sd->size(Loc()), initPtr); } // function xtoHash b.push_funcptr(isOpaque ? nullptr : sd->xhash); // function xopEquals b.push_funcptr(isOpaque ? nullptr : sd->xeq); // function xopCmp b.push_funcptr(isOpaque ? nullptr : sd->xcmp); // function xtoString b.push_funcptr(isOpaque ? nullptr : search_toString(sd)); // StructFlags m_flags b.push_uint(!isOpaque && hasPointers(ts) ? 1 : 0); // function xdtor/xdtorti b.push_funcptr(isOpaque ? nullptr : sd->tidtor); // function xpostblit FuncDeclaration *xpostblit = isOpaque ? nullptr : sd->postblit; if (xpostblit && (xpostblit->storage_class & STCdisable)) { xpostblit = nullptr; } b.push_funcptr(xpostblit); // uint m_align b.push_uint(isOpaque ? 0 : DtoAlignment(ts)); if (withArgTypes) { // TypeInfo m_arg1 // TypeInfo m_arg2 for (unsigned i = 0; i < 2; i++) { if (auto t = isOpaque ? nullptr : sd->argType(i)) { t = merge(t); b.push_typeinfo(t); } else { b.push_null(getTypeInfoType()); } } } // immutable(void)* m_RTInfo if (!isOpaque && sd->getRTInfo) { b.push(toConstElem(sd->getRTInfo, gIR)); } else { b.push_size_as_vp(!isOpaque && hasPointers(ts) ? 1 : 0); } constTypeInfo = b.get_constant(getTypeInfoStructMemType()); return constTypeInfo; }