diff --git a/gen/metadata.h b/gen/metadata.h index d202789b..551ce5a5 100644 --- a/gen/metadata.h +++ b/gen/metadata.h @@ -25,6 +25,21 @@ enum TypeDataFields { TD_NumFields /// The number of fields in TypeInfo metadata }; + +// *** Metadata for ClassInfo instances *** +#define CD_PREFIX "llvm.ldc.classinfo." + +/// The fields in the metadata node for a ClassInfo instance. +/// (Its name will be CD_PREFIX ~ ) +enum ClassDataFields { + CD_BodyType, /// A value of the LLVM type corresponding to the class body. + CD_Finalize, /// True if this class (or a base class) has a destructor. + CD_CustomDelete,/// True if this class has an overridden delete operator. + + // Must be kept last + CD_NumFields /// The number of fields in ClassInfo metadata +}; + #endif #endif diff --git a/gen/passes/GarbageCollect2Stack.cpp b/gen/passes/GarbageCollect2Stack.cpp index 09239d65..3445509e 100644 --- a/gen/passes/GarbageCollect2Stack.cpp +++ b/gen/passes/GarbageCollect2Stack.cpp @@ -180,6 +180,53 @@ namespace { return alloca; } }; + + // FunctionInfo for _d_allocclass + class AllocClassFI : public FunctionInfo { + public: + virtual bool analyze(CallSite CS, const Analysis& A) { + // This call contains no TypeInfo parameter, so don't call the + // base class implementation here... + if (CS.arg_size() != 1) + return false; + Value* arg = CS.getArgument(0)->stripPointerCasts(); + GlobalVariable* ClassInfo = dyn_cast(arg); + if (!ClassInfo) + return false; + + std::string metaname = CD_PREFIX; + metaname.append(ClassInfo->getNameStart(), ClassInfo->getNameEnd()); + + GlobalVariable* global = A.M.getGlobalVariable(metaname); + if (!global || !global->hasInitializer()) + return false; + + MDNode* node = dyn_cast(global->getInitializer()); + if (!node || node->getNumOperands() != CD_NumFields) + return false; + + // Inserting destructor calls is not implemented yet, so classes + // with destructors are ignored for now. + Constant* hasDestructor = dyn_cast(node->getOperand(CD_Finalize)); + // We can't stack-allocate if the class has a custom deallocator + // (Custom allocators don't get turned into this runtime call, so + // those can be ignored) + Constant* hasCustomDelete = dyn_cast(node->getOperand(CD_CustomDelete)); + if (hasDestructor == NULL || hasCustomDelete == NULL) + return false; + + if (ConstantExpr::getOr(hasDestructor, hasCustomDelete) + != ConstantInt::getFalse()) + return false; + + Ty = node->getOperand(CD_BodyType)->getType(); + return true; + } + + // The default promote() should be fine. + + AllocClassFI() : FunctionInfo(-1, true) {} + }; } @@ -197,6 +244,7 @@ namespace { FunctionInfo AllocMemoryT; ArrayFI NewArrayVT; ArrayFI NewArrayT; + AllocClassFI AllocClass; public: static char ID; // Pass identification @@ -233,6 +281,7 @@ GarbageCollect2Stack::GarbageCollect2Stack() KnownFunctions["_d_allocmemoryT"] = &AllocMemoryT; KnownFunctions["_d_newarrayvT"] = &NewArrayVT; KnownFunctions["_d_newarrayT"] = &NewArrayT; + KnownFunctions["_d_allocclass"] = &AllocClass; } static void RemoveCall(Instruction* Inst) { diff --git a/ir/irclass.cpp b/ir/irclass.cpp index bd3c2b1d..1a6c4be2 100644 --- a/ir/irclass.cpp +++ b/ir/irclass.cpp @@ -11,6 +11,7 @@ #include "gen/llvmhelpers.h" #include "gen/utils.h" #include "gen/arrays.h" +#include "gen/metadata.h" #include "ir/irstruct.h" #include "ir/irtypeclass.h" @@ -70,6 +71,29 @@ LLGlobalVariable * IrStruct::getClassInfoSymbol() classInfo = new llvm::GlobalVariable( tc->getPA().get(), false, _linkage, NULL, initname, gIR->module); +#ifdef USE_METADATA + // Generate some metadata on this ClassInfo if it's for a class. + + ClassDeclaration* classdecl = aggrdecl->isClassDeclaration(); + if (classdecl && !aggrdecl->isInterfaceDeclaration()) { + // Gather information + const LLType* type = DtoType(aggrdecl->type); + const LLType* bodyType = llvm::cast(type)->getElementType(); + bool hasDestructor = (classdecl->dtor != NULL); + bool hasCustomDelete = (classdecl->aggDelete != NULL); + // Construct the fields + LLConstant* mdVals[CD_NumFields]; + mdVals[CD_BodyType] = llvm::UndefValue::get(bodyType); + mdVals[CD_Finalize] = LLConstantInt::get(LLType::Int1Ty, hasDestructor); + mdVals[CD_CustomDelete] = LLConstantInt::get(LLType::Int1Ty, hasCustomDelete); + // Construct the metadata + llvm::MDNode* metadata = llvm::MDNode::get(mdVals, CD_NumFields); + // Insert it into the module + new llvm::GlobalVariable(metadata->getType(), true, + METADATA_LINKAGE_TYPE, metadata, CD_PREFIX + initname, gIR->module); + } +#endif + return classInfo; }