#include #include "gen/llvm.h" #include "mtype.h" #include "aggregate.h" #include "init.h" #include "declaration.h" #include "gen/irstate.h" #include "gen/tollvm.h" #include "gen/arrays.h" #include "gen/logger.h" #include "gen/classes.h" #include "gen/functions.h" #include "gen/runtime.h" #include "gen/dvalue.h" ////////////////////////////////////////////////////////////////////////////////////////// static void LLVM_AddBaseClassData(BaseClasses* bcs) { // add base class data members first for (int j=0; jdim; j++) { BaseClass* bc = (BaseClass*)(bcs->data[j]); assert(bc); if (bc->base->isInterfaceDeclaration()) continue; // interfaces only has methods LLVM_AddBaseClassData(&bc->base->baseclasses); Logger::println("Adding base class members of %s", bc->base->toChars()); LOG_SCOPE; for (int k=0; k < bc->base->members->dim; k++) { Dsymbol* dsym = (Dsymbol*)(bc->base->members->data[k]); if (dsym->isVarDeclaration()) { dsym->toObjFile(); } } } } ////////////////////////////////////////////////////////////////////////////////////////// void DtoResolveClass(ClassDeclaration* cd) { if (cd->llvmResolved) return; cd->llvmResolved = true; // first resolve the base class if (cd->baseClass) { DtoResolveClass(cd->baseClass); } // resolve interfaces if (cd->vtblInterfaces) { for (int i=0; i < cd->vtblInterfaces->dim; i++) { BaseClass *b = (BaseClass *)cd->vtblInterfaces->data[i]; ClassDeclaration *id = b->base; DtoResolveClass(id); // Fill in vtbl[] b->fillVtbl(cd, &b->vtbl, 1); } } Logger::println("DtoResolveClass(%s)", cd->toPrettyChars()); LOG_SCOPE; assert(cd->type->ty == Tclass); TypeClass* ts = (TypeClass*)cd->type; assert(!cd->llvmIRStruct); IRStruct* irstruct = new IRStruct(ts); cd->llvmIRStruct = irstruct; gIR->structs.push_back(irstruct); gIR->classes.push_back(cd); // add vtable ts->llvmVtblType = new llvm::PATypeHolder(llvm::OpaqueType::get()); const llvm::Type* vtabty = llvm::PointerType::get(ts->llvmVtblType->get()); std::vector fieldtypes; fieldtypes.push_back(vtabty); // add monitor fieldtypes.push_back(llvm::PointerType::get(llvm::Type::Int8Ty)); // add interface vtables if (cd->vtblInterfaces) for (size_t i = 0; i < cd->vtblInterfaces->dim; i++) { BaseClass *b = (BaseClass *)cd->vtblInterfaces->data[i]; ClassDeclaration *id = b->base; assert(id->type->ty == Tclass); TypeClass* itc = (TypeClass*)id->type; const llvm::Type* ivtblTy = llvm::PointerType::get(itc->llvmVtblType->get()); fieldtypes.push_back(ivtblTy); // add this interface to the map IRInterface* iri = new IRInterface(b, isaStruct(itc->llvmVtblType->get())); irstruct->interfaces.insert(std::make_pair(id, iri)); } // base classes first LLVM_AddBaseClassData(&cd->baseclasses); // then add own members for (int k=0; k < cd->members->dim; k++) { Dsymbol* dsym = (Dsymbol*)(cd->members->data[k]); dsym->toObjFile(); } // add field types for (IRStruct::OffsetMap::iterator i=irstruct->offsets.begin(); i!=irstruct->offsets.end(); ++i) { fieldtypes.push_back(i->second.type); } const llvm::StructType* structtype = llvm::StructType::get(fieldtypes); // refine abstract types for stuff like: class C {C next;} assert(irstruct->recty != 0); llvm::PATypeHolder& spa = irstruct->recty; llvm::cast(spa.get())->refineAbstractTypeTo(structtype); structtype = isaStruct(spa.get()); if (!ts->llvmType) ts->llvmType = new llvm::PATypeHolder(structtype); else *ts->llvmType = structtype; if (cd->isNested()) { assert(0 && "nested classes not implemented"); } else { gIR->module->addTypeName(cd->mangle(), ts->llvmType->get()); } // build interface info type std::vector infoTypes; // ClassInfo classinfo ClassDeclaration* cinfod = ClassDeclaration::classinfo; DtoResolveClass(cinfod); infoTypes.push_back(llvm::PointerType::get(cinfod->type->llvmType->get())); // void*[] vtbl std::vector infoVtbltypes; infoVtbltypes.push_back(DtoSize_t()); const llvm::Type* byteptrptrty = llvm::PointerType::get(llvm::PointerType::get(llvm::Type::Int8Ty)); infoVtbltypes.push_back(byteptrptrty); infoTypes.push_back(llvm::StructType::get(infoVtbltypes)); // int offset infoTypes.push_back(llvm::Type::Int32Ty); // create type const llvm::StructType* infoTy = llvm::StructType::get(infoTypes); // create vtable type llvm::GlobalVariable* svtblVar = 0; std::vector sinits_ty; for (int k=0; k < cd->vtbl.dim; k++) { Dsymbol* dsym = (Dsymbol*)cd->vtbl.data[k]; assert(dsym); //Logger::cout() << "vtblsym: " << dsym->toChars() << '\n'; if (FuncDeclaration* fd = dsym->isFuncDeclaration()) { DtoResolveFunction(fd); //assert(fd->type->ty == Tfunction); //TypeFunction* tf = (TypeFunction*)fd->type; //const llvm::Type* fpty = llvm::PointerType::get(tf->llvmType->get()); const llvm::FunctionType* vfty = DtoBaseFunctionType(fd); const llvm::Type* vfpty = llvm::PointerType::get(vfty); sinits_ty.push_back(vfpty); } else if (ClassDeclaration* cd2 = dsym->isClassDeclaration()) { Logger::println("*** ClassDeclaration in vtable: %s", cd2->toChars()); const llvm::Type* cinfoty; if (cd->isInterfaceDeclaration()) { cinfoty = infoTy; } else if (cd != cinfod) { DtoResolveClass(cinfod); cinfoty = cinfod->type->llvmType->get(); } else { // this is the ClassInfo class, the type is this type cinfoty = ts->llvmType->get(); } const llvm::Type* cty = llvm::PointerType::get(cinfoty); sinits_ty.push_back(cty); } else assert(0); } assert(!sinits_ty.empty()); const llvm::StructType* svtbl_ty = llvm::StructType::get(sinits_ty); std::string styname(cd->mangle()); styname.append("__vtblType"); gIR->module->addTypeName(styname, svtbl_ty); // refine for final vtable type llvm::cast(ts->llvmVtblType->get())->refineAbstractTypeTo(svtbl_ty); gIR->classes.pop_back(); gIR->structs.pop_back(); gIR->declareList.push_back(cd); } ////////////////////////////////////////////////////////////////////////////////////////// void DtoDeclareClass(ClassDeclaration* cd) { if (cd->llvmDeclared) return; cd->llvmDeclared = true; Logger::println("DtoDeclareClass(%s)", cd->toPrettyChars()); LOG_SCOPE; assert(cd->type->ty == Tclass); TypeClass* ts = (TypeClass*)cd->type; assert(cd->llvmIRStruct); IRStruct* irstruct = cd->llvmIRStruct; gIR->structs.push_back(irstruct); gIR->classes.push_back(cd); bool needs_definition = false; if (cd->parent->isModule()) { needs_definition = (cd->getModule() == gIR->dmodule); } // interface vtables are emitted by the class implementing them // also interfaces have no static initializer if (!cd->isInterfaceDeclaration()) { // vtable std::string varname("_D"); varname.append(cd->mangle()); varname.append("6__vtblZ"); llvm::GlobalValue::LinkageTypes _linkage = llvm::GlobalValue::ExternalLinkage; const llvm::StructType* svtbl_ty = isaStruct(ts->llvmVtblType->get()); cd->llvmVtbl = new llvm::GlobalVariable(svtbl_ty, true, _linkage, 0, varname, gIR->module); // build interface info type std::vector types; // ClassInfo classinfo ClassDeclaration* cd2 = ClassDeclaration::classinfo; DtoResolveClass(cd2); types.push_back(llvm::PointerType::get(cd2->type->llvmType->get())); // void*[] vtbl std::vector vtbltypes; vtbltypes.push_back(DtoSize_t()); const llvm::Type* byteptrptrty = llvm::PointerType::get(llvm::PointerType::get(llvm::Type::Int8Ty)); vtbltypes.push_back(byteptrptrty); types.push_back(llvm::StructType::get(vtbltypes)); // int offset types.push_back(llvm::Type::Int32Ty); // create type const llvm::StructType* infoTy = llvm::StructType::get(types); // interface info array if (needs_definition && cd->vtblInterfaces->dim > 0) { // symbol name std::string nam = "_D"; nam.append(cd->mangle()); nam.append("16__interfaceInfosZ"); // resolve array type const llvm::ArrayType* arrTy = llvm::ArrayType::get(infoTy, cd->vtblInterfaces->dim); // declare global irstruct->interfaceInfosTy = arrTy; irstruct->interfaceInfos = new llvm::GlobalVariable(arrTy, true, llvm::GlobalValue::InternalLinkage, 0, nam, gIR->module); } // interface vtables unsigned idx = 0; for (IRStruct::InterfaceIter i=irstruct->interfaces.begin(); i!=irstruct->interfaces.end(); ++i) { ClassDeclaration* id = i->first; IRInterface* iri = i->second; std::string nam("_D"); nam.append(cd->mangle()); nam.append("11__interface"); nam.append(id->mangle()); nam.append("6__vtblZ"); assert(iri->vtblTy); iri->vtbl = new llvm::GlobalVariable(iri->vtblTy, true, _linkage, 0, nam, gIR->module); iri->infoTy = infoTy; llvm::Constant* idxs[2] = {DtoConstUint(0), DtoConstUint(idx)}; iri->info = llvm::ConstantExpr::getGetElementPtr(irstruct->interfaceInfos, idxs, 2); idx++; } // init std::string initname("_D"); initname.append(cd->mangle()); initname.append("6__initZ"); llvm::GlobalVariable* initvar = new llvm::GlobalVariable(ts->llvmType->get(), true, _linkage, NULL, initname, gIR->module); ts->llvmInit = initvar; } gIR->classes.pop_back(); gIR->structs.pop_back(); gIR->constInitList.push_back(cd); if (needs_definition) gIR->defineList.push_back(cd); // classinfo DtoDeclareClassInfo(cd); // typeinfo if (cd->parent->isModule() && cd->getModule() == gIR->dmodule) cd->type->getTypeInfo(NULL); } ////////////////////////////////////////////////////////////////////////////////////////// void DtoConstInitClass(ClassDeclaration* cd) { if (cd->llvmInitialized) return; cd->llvmInitialized = true; if (cd->isInterfaceDeclaration()) return; // nothing to do Logger::println("DtoConstInitClass(%s)", cd->toPrettyChars()); LOG_SCOPE; IRStruct* irstruct = cd->llvmIRStruct; gIR->structs.push_back(irstruct); gIR->classes.push_back(cd); // make sure each offset knows its default initializer for (IRStruct::OffsetMap::iterator i=irstruct->offsets.begin(); i!=irstruct->offsets.end(); ++i) { IRStruct::Offset* so = &i->second; llvm::Constant* finit = DtoConstFieldInitializer(so->var->type, so->var->init); so->init = finit; so->var->llvmConstInit = finit; } // fill out fieldtypes/inits std::vector fieldinits; // first field is always the vtable assert(cd->llvmVtbl != 0); fieldinits.push_back(cd->llvmVtbl); // then comes monitor fieldinits.push_back(llvm::ConstantPointerNull::get(llvm::PointerType::get(llvm::Type::Int8Ty))); // next comes interface vtables for (IRStruct::InterfaceIter i=irstruct->interfaces.begin(); i!=irstruct->interfaces.end(); ++i) { IRInterface* iri = i->second; assert(iri->vtbl); fieldinits.push_back(iri->vtbl); } // rest for (IRStruct::OffsetMap::iterator i=irstruct->offsets.begin(); i!=irstruct->offsets.end(); ++i) { Logger::println("adding fieldinit for: %s", i->second.var->toChars()); fieldinits.push_back(i->second.init); } // get the struct (class) type assert(cd->type->ty == Tclass); TypeClass* ts = (TypeClass*)cd->type; const llvm::StructType* structtype = isaStruct(ts->llvmType->get()); const llvm::StructType* vtbltype = isaStruct(ts->llvmVtblType->get()); // generate initializer #if 0 Logger::cout() << cd->toPrettyChars() << " | " << *structtype << '\n'; for(size_t i=0; igetNumElements(); ++i) { Logger::cout() << "s#" << i << " = " << *structtype->getElementType(i) << '\n'; } for(size_t i=0; itoChars() << '\n'; if (FuncDeclaration* fd = dsym->isFuncDeclaration()) { DtoForceDeclareDsymbol(fd); assert(fd->llvmValue); llvm::Constant* c = llvm::cast(fd->llvmValue); // cast if necessary (overridden method) if (c->getType() != vtbltype->getElementType(k)) c = llvm::ConstantExpr::getBitCast(c, vtbltype->getElementType(k)); sinits.push_back(c); } else if (ClassDeclaration* cd2 = dsym->isClassDeclaration()) { assert(cd->llvmClass); llvm::Constant* c = cd->llvmClass; sinits.push_back(c); } else assert(0); } const llvm::StructType* svtbl_ty = isaStruct(ts->llvmVtblType->get()); #if 0 for (size_t i=0; i< sinits.size(); ++i) { Logger::cout() << "field[" << i << "] = " << *svtbl_ty->getElementType(i) << '\n'; Logger::cout() << "init [" << i << "] = " << *sinits[i]->getType() << '\n'; assert(svtbl_ty->getElementType(i) == sinits[i]->getType()); } #endif llvm::Constant* cvtblInit = llvm::ConstantStruct::get(svtbl_ty, sinits); cd->llvmConstVtbl = llvm::cast(cvtblInit); // create interface vtable const initalizers int idx = 2; int idxScale = PTRSIZE; for (IRStruct::InterfaceIter i=irstruct->interfaces.begin(); i!=irstruct->interfaces.end(); ++i) { ClassDeclaration* id = i->first; assert(id->type->ty == Tclass); TypeClass* its = (TypeClass*)id->type; IRInterface* iri = i->second; BaseClass* b = iri->base; const llvm::StructType* ivtbl_ty = isaStruct(its->llvmVtblType->get()); // generate interface info initializer std::vector infoInits; // classinfo assert(id->llvmClass); llvm::Constant* c = id->llvmClass; infoInits.push_back(c); // vtbl const llvm::Type* byteptrptrty = llvm::PointerType::get(llvm::PointerType::get(llvm::Type::Int8Ty)); c = llvm::ConstantExpr::getBitCast(iri->vtbl, byteptrptrty); c = DtoConstSlice(DtoConstSize_t(b->vtbl.dim), c); infoInits.push_back(c); // offset infoInits.push_back(DtoConstInt(idx*idxScale)); // create interface info initializer constant iri->infoInit = llvm::cast(llvm::ConstantStruct::get(iri->infoTy, infoInits)); // generate vtable initializer std::vector iinits; // add interface info iinits.push_back(iri->info); for (int k=1; k < b->vtbl.dim; k++) { Logger::println("interface vtbl const init nr. %d", k); Dsymbol* dsym = (Dsymbol*)b->vtbl.data[k]; FuncDeclaration* fd = dsym->isFuncDeclaration(); assert(fd); DtoForceDeclareDsymbol(fd); assert(fd->llvmValue); llvm::Constant* c = llvm::cast(fd->llvmValue); // we have to bitcast, as the type created in ResolveClass expects a different this type c = llvm::ConstantExpr::getBitCast(c, iri->vtblTy->getContainedType(k)); iinits.push_back(c); } #if 1 for (size_t x=0; x< iinits.size(); ++x) { Logger::cout() << "field[" << x << "] = " << *ivtbl_ty->getElementType(x) << "\n\n"; Logger::cout() << "init [" << x << "] = " << *iinits[x] << "\n\n"; assert(ivtbl_ty->getElementType(x) == iinits[x]->getType()); } #endif llvm::Constant* civtblInit = llvm::ConstantStruct::get(ivtbl_ty, iinits); iri->vtblInit = llvm::cast(civtblInit); idx++; } gIR->classes.pop_back(); gIR->structs.pop_back(); } ////////////////////////////////////////////////////////////////////////////////////////// void DtoDefineClass(ClassDeclaration* cd) { if (cd->llvmDefined) return; cd->llvmDefined = true; Logger::println("DtoDefineClass(%s)", cd->toPrettyChars()); LOG_SCOPE; // get the struct (class) type assert(cd->type->ty == Tclass); TypeClass* ts = (TypeClass*)cd->type; bool def = false; if (cd->parent->isModule() && cd->getModule() == gIR->dmodule) { // interfaces don't have initializers if (!cd->isInterfaceDeclaration()) { ts->llvmInit->setInitializer(cd->llvmInitZ); cd->llvmVtbl->setInitializer(cd->llvmConstVtbl); // initialize interface vtables IRStruct* irstruct = cd->llvmIRStruct; std::vector infoInits; for (IRStruct::InterfaceIter i=irstruct->interfaces.begin(); i!=irstruct->interfaces.end(); ++i) { IRInterface* iri = i->second; iri->vtbl->setInitializer(iri->vtblInit); infoInits.push_back(iri->infoInit); } // initialize interface info array if (!infoInits.empty()) { llvm::Constant* arrInit = llvm::ConstantArray::get(irstruct->interfaceInfosTy, infoInits); irstruct->interfaceInfos->setInitializer(arrInit); } } def = true; } // generate classinfo if (def) DtoDefineClassInfo(cd); } ////////////////////////////////////////////////////////////////////////////////////////// void DtoCallClassDtors(TypeClass* tc, llvm::Value* instance) { Array* arr = &tc->sym->dtors; for (size_t i=0; idim; i++) { FuncDeclaration* fd = (FuncDeclaration*)arr->data[i]; assert(fd->llvmValue); new llvm::CallInst(fd->llvmValue, instance, "", gIR->scopebb()); } } ////////////////////////////////////////////////////////////////////////////////////////// void DtoInitClass(TypeClass* tc, llvm::Value* dst) { assert(gIR); assert(tc->llvmType); uint64_t size_t_size = gTargetData->getTypeSize(DtoSize_t()); uint64_t n = gTargetData->getTypeSize(tc->llvmType->get()) - size_t_size; // set vtable field llvm::Value* vtblvar = DtoGEPi(dst,0,0,"tmp",gIR->scopebb()); assert(tc->sym->llvmVtbl); new llvm::StoreInst(tc->sym->llvmVtbl, vtblvar, gIR->scopebb()); // copy the static initializer if (n > 0) { assert(tc->llvmInit); assert(dst->getType() == tc->llvmInit->getType()); llvm::Type* arrty = llvm::PointerType::get(llvm::Type::Int8Ty); llvm::Value* dstarr = new llvm::BitCastInst(dst,arrty,"tmp",gIR->scopebb()); dstarr = DtoGEPi(dstarr,size_t_size,"tmp",gIR->scopebb()); llvm::Value* srcarr = new llvm::BitCastInst(tc->llvmInit,arrty,"tmp",gIR->scopebb()); srcarr = DtoGEPi(srcarr,size_t_size,"tmp",gIR->scopebb()); llvm::Function* fn = LLVM_DeclareMemCpy32(); std::vector llargs; llargs.resize(4); llargs[0] = dstarr; llargs[1] = srcarr; llargs[2] = llvm::ConstantInt::get(llvm::Type::Int32Ty, n, false); llargs[3] = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false); new llvm::CallInst(fn, llargs.begin(), llargs.end(), "", gIR->scopebb()); } } ////////////////////////////////////////////////////////////////////////////////////////// DValue* DtoCastClass(DValue* val, Type* _to) { Type* to = DtoDType(_to); if (to->ty == Tpointer) { const llvm::Type* tolltype = DtoType(_to); llvm::Value* rval = DtoBitCast(val->getRVal(), tolltype); return new DImValue(_to, rval); } assert(to->ty == Tclass); TypeClass* tc = (TypeClass*)to; Type* from = DtoDType(val->getType()); TypeClass* fc = (TypeClass*)from; if (tc->sym->isInterfaceDeclaration()) { assert(!fc->sym->isInterfaceDeclaration()); return DtoDynamicCastObject(val, _to); } else { int poffset; if (fc->sym->isInterfaceDeclaration()) { return DtoCastInterfaceToObject(val, _to); } else if (tc->sym->isBaseOf(fc->sym,NULL)) { const llvm::Type* tolltype = DtoType(_to); llvm::Value* rval = DtoBitCast(val->getRVal(), tolltype); return new DImValue(_to, rval); } else { return DtoDynamicCastObject(val, _to); } } } ////////////////////////////////////////////////////////////////////////////////////////// DValue* DtoDynamicCastObject(DValue* val, Type* _to) { // call: // Object _d_dynamic_cast(Object o, ClassInfo c) DtoForceDeclareDsymbol(ClassDeclaration::object); DtoForceDeclareDsymbol(ClassDeclaration::classinfo); llvm::Function* func = LLVM_D_GetRuntimeFunction(gIR->module, "_d_dynamic_cast"); const llvm::FunctionType* funcTy = func->getFunctionType(); std::vector args; // Object o llvm::Value* tmp = val->getRVal(); tmp = DtoBitCast(tmp, funcTy->getParamType(0)); args.push_back(tmp); assert(funcTy->getParamType(0) == tmp->getType()); // ClassInfo c TypeClass* to = (TypeClass*)DtoDType(_to); DtoForceDeclareDsymbol(to->sym); assert(to->sym->llvmClass); tmp = to->sym->llvmClass; // unfortunately this is needed as the implementation of object differs somehow from the declaration // this could happen in user code as well :/ tmp = DtoBitCast(tmp, funcTy->getParamType(1)); args.push_back(tmp); assert(funcTy->getParamType(1) == tmp->getType()); // call it llvm::Value* ret = gIR->ir->CreateCall(func, args.begin(), args.end(), "tmp"); // cast return value ret = DtoBitCast(ret, DtoType(_to)); return new DImValue(_to, ret); } ////////////////////////////////////////////////////////////////////////////////////////// DValue* DtoCastInterfaceToObject(DValue* val, Type* to) { // call: // Object _d_toObject(void* p) llvm::Function* func = LLVM_D_GetRuntimeFunction(gIR->module, "_d_toObject"); const llvm::FunctionType* funcTy = func->getFunctionType(); // void* p llvm::Value* tmp = val->getRVal(); tmp = DtoBitCast(tmp, funcTy->getParamType(0)); // call it llvm::Value* ret = gIR->ir->CreateCall(func, tmp, "tmp"); // cast return value if (to != NULL) ret = DtoBitCast(ret, DtoType(to)); else to = ClassDeclaration::object->type; return new DImValue(to, ret); } ////////////////////////////////////////////////////////////////////////////////////////// void DtoDeclareClassInfo(ClassDeclaration* cd) { if (cd->llvmClassDeclared) return; cd->llvmClassDeclared = true; Logger::println("DtoDeclareClassInfo(%s)", cd->toChars()); LOG_SCOPE; ClassDeclaration* cinfo = ClassDeclaration::classinfo; DtoResolveClass(cinfo); std::string gname("_D"); gname.append(cd->mangle()); if (!cd->isInterfaceDeclaration()) gname.append("7__ClassZ"); else gname.append("11__InterfaceZ"); const llvm::Type* st = cinfo->type->llvmType->get(); cd->llvmClass = new llvm::GlobalVariable(st, true, llvm::GlobalValue::ExternalLinkage, NULL, gname, gIR->module); } static llvm::Constant* build_offti_entry(VarDeclaration* vd) { std::vector types; std::vector inits; types.push_back(DtoSize_t()); size_t offset = vd->offset; // TODO might not be the true offset // dmd only accounts for the vtable, not classinfo or monitor if (global.params.is64bit) offset += 8; else offset += 4; inits.push_back(DtoConstSize_t(offset)); vd->type->getTypeInfo(NULL); assert(vd->type->vtinfo); DtoForceDeclareDsymbol(vd->type->vtinfo); llvm::Constant* c = isaConstant(vd->type->vtinfo->llvmValue); const llvm::Type* tiTy = llvm::PointerType::get(Type::typeinfo->type->llvmType->get()); Logger::cout() << "tiTy = " << *tiTy << '\n'; types.push_back(tiTy); inits.push_back(llvm::ConstantExpr::getBitCast(c, tiTy)); const llvm::StructType* sTy = llvm::StructType::get(types); return llvm::ConstantStruct::get(sTy, inits); } static llvm::Constant* build_offti_array(ClassDeclaration* cd, llvm::Constant* init) { const llvm::StructType* initTy = isaStruct(init->getType()); assert(initTy); std::vector arrayInits; for (ClassDeclaration *cd2 = cd; cd2; cd2 = cd2->baseClass) { if (cd2->members) { for (size_t i = 0; i < cd2->members->dim; i++) { Dsymbol *sm = (Dsymbol *)cd2->members->data[i]; if (VarDeclaration* vd = sm->isVarDeclaration()) // is this enough? { llvm::Constant* c = build_offti_entry(vd); assert(c); arrayInits.push_back(c); } } } } size_t ninits = arrayInits.size(); llvm::Constant* size = DtoConstSize_t(ninits); llvm::Constant* ptr; if (ninits > 0) { // OffsetTypeInfo type std::vector elemtypes; elemtypes.push_back(DtoSize_t()); const llvm::Type* tiTy = llvm::PointerType::get(Type::typeinfo->type->llvmType->get()); elemtypes.push_back(tiTy); const llvm::StructType* sTy = llvm::StructType::get(elemtypes); // array type const llvm::ArrayType* arrTy = llvm::ArrayType::get(sTy, ninits); llvm::Constant* arrInit = llvm::ConstantArray::get(arrTy, arrayInits); std::string name(cd->type->vtinfo->toChars()); name.append("__OffsetTypeInfos"); llvm::GlobalVariable* gvar = new llvm::GlobalVariable(arrTy,true,llvm::GlobalValue::InternalLinkage,arrInit,name,gIR->module); ptr = llvm::ConstantExpr::getBitCast(gvar, llvm::PointerType::get(sTy)); } else { ptr = llvm::ConstantPointerNull::get(isaPointer(initTy->getElementType(1))); } return DtoConstSlice(size, ptr); } static llvm::Constant* build_class_dtor(ClassDeclaration* cd) { // construct the function std::vector paramTypes; paramTypes.push_back(llvm::PointerType::get(cd->type->llvmType->get())); const llvm::FunctionType* fnTy = llvm::FunctionType::get(llvm::Type::VoidTy, paramTypes, false); if (cd->dtors.dim == 0) { return llvm::ConstantPointerNull::get(llvm::PointerType::get(llvm::Type::Int8Ty)); } else if (cd->dtors.dim == 1) { DtorDeclaration *d = (DtorDeclaration *)cd->dtors.data[0]; DtoForceDeclareDsymbol(d); assert(d->llvmValue); return llvm::ConstantExpr::getBitCast(isaConstant(d->llvmValue), llvm::PointerType::get(llvm::Type::Int8Ty)); } std::string gname("_D"); gname.append(cd->mangle()); gname.append("12__destructorMFZv"); llvm::Function* func = new llvm::Function(fnTy, llvm::GlobalValue::InternalLinkage, gname, gIR->module); llvm::Value* thisptr = func->arg_begin(); thisptr->setName("this"); llvm::BasicBlock* bb = new llvm::BasicBlock("entry", func); LLVMBuilder builder(bb); for (size_t i = 0; i < cd->dtors.dim; i++) { DtorDeclaration *d = (DtorDeclaration *)cd->dtors.data[i]; DtoForceDeclareDsymbol(d); assert(d->llvmValue); builder.CreateCall(d->llvmValue, thisptr); } builder.CreateRetVoid(); return llvm::ConstantExpr::getBitCast(func, llvm::PointerType::get(llvm::Type::Int8Ty)); } static uint build_classinfo_flags(ClassDeclaration* cd) { // adapted from original dmd code uint flags = 0; //flags |= isCOMclass(); // IUnknown bool hasOffTi = false; if (cd->ctor) flags |= 8; for (ClassDeclaration *cd2 = cd; cd2; cd2 = cd2->baseClass) { if (cd2->members) { for (size_t i = 0; i < cd2->members->dim; i++) { Dsymbol *sm = (Dsymbol *)cd2->members->data[i]; if (sm->isVarDeclaration()) // is this enough? hasOffTi = true; //printf("sm = %s %s\n", sm->kind(), sm->toChars()); if (sm->hasPointers()) goto L2; } } } flags |= 2; // no pointers L2: if (hasOffTi) flags |= 4; return flags; } void DtoDefineClassInfo(ClassDeclaration* cd) { // The layout is: // { // void **vptr; // monitor_t monitor; // byte[] initializer; // static initialization data // char[] name; // class name // void *[] vtbl; // Interface[] interfaces; // ClassInfo *base; // base class // void *destructor; // void *invariant; // class invariant // uint flags; // void *deallocator; // OffsetTypeInfo[] offTi; // void *defaultConstructor; // } if (cd->llvmClassDefined) return; cd->llvmClassDefined = true; Logger::println("DtoDefineClassInfo(%s)", cd->toChars()); LOG_SCOPE; assert(cd->type->ty == Tclass); assert(cd->llvmClass); TypeClass* cdty = (TypeClass*)cd->type; if (!cd->isInterfaceDeclaration()) { assert(cd->llvmInitZ); assert(cd->llvmVtbl); assert(cd->llvmConstVtbl); assert(cdty->llvmInit); } // holds the list of initializers for llvm std::vector inits; ClassDeclaration* cinfo = ClassDeclaration::classinfo; DtoForceConstInitDsymbol(cinfo); assert(cinfo->llvmInitZ); llvm::Constant* c; // own vtable c = cinfo->llvmInitZ->getOperand(0); assert(c); inits.push_back(c); // monitor c = cinfo->llvmInitZ->getOperand(1); inits.push_back(c); // byte[] init const llvm::Type* byteptrty = llvm::PointerType::get(llvm::Type::Int8Ty); if (cd->isInterfaceDeclaration()) { c = cinfo->llvmInitZ->getOperand(2); } else { c = llvm::ConstantExpr::getBitCast(cdty->llvmInit, byteptrty); assert(!cd->llvmInitZ->getType()->isAbstract()); size_t initsz = gTargetData->getTypeSize(cd->llvmInitZ->getType()); c = DtoConstSlice(DtoConstSize_t(initsz), c); } inits.push_back(c); // class name // from dmd char *name = cd->ident->toChars(); size_t namelen = strlen(name); if (!(namelen > 9 && memcmp(name, "TypeInfo_", 9) == 0)) { name = cd->toPrettyChars(); namelen = strlen(name); } c = DtoConstString(name); inits.push_back(c); // vtbl array if (cd->isInterfaceDeclaration()) { c = cinfo->llvmInitZ->getOperand(4); } else { const llvm::Type* byteptrptrty = llvm::PointerType::get(byteptrty); assert(!cd->llvmVtbl->getType()->isAbstract()); c = llvm::ConstantExpr::getBitCast(cd->llvmVtbl, byteptrptrty); assert(!cd->llvmConstVtbl->getType()->isAbstract()); size_t vtblsz = cd->llvmConstVtbl->getType()->getNumElements(); c = DtoConstSlice(DtoConstSize_t(vtblsz), c); } inits.push_back(c); // interfaces array IRStruct* irstruct = cd->llvmIRStruct; if (cd->isInterfaceDeclaration() || !irstruct->interfaceInfos) { c = cinfo->llvmInitZ->getOperand(5); } else { const llvm::Type* t = cinfo->llvmInitZ->getOperand(5)->getType()->getContainedType(1); c = llvm::ConstantExpr::getBitCast(irstruct->interfaceInfos, t); size_t iisz = irstruct->interfaceInfosTy->getNumElements(); c = DtoConstSlice(DtoConstSize_t(iisz), c); } inits.push_back(c); // base classinfo if (cd->baseClass && !cd->isInterfaceDeclaration()) { DtoDeclareClassInfo(cd->baseClass); c = cd->baseClass->llvmClass; assert(c); inits.push_back(c); } else { // null c = cinfo->llvmInitZ->getOperand(6); inits.push_back(c); } // destructor if (cd->isInterfaceDeclaration()) { c = cinfo->llvmInitZ->getOperand(7); } else { c = build_class_dtor(cd); } inits.push_back(c); // invariant // TODO c = cinfo->llvmInitZ->getOperand(8); inits.push_back(c); // uint flags if (cd->isInterfaceDeclaration()) { c = cinfo->llvmInitZ->getOperand(9); } else { uint flags = build_classinfo_flags(cd); c = DtoConstUint(flags); } inits.push_back(c); // allocator // TODO c = cinfo->llvmInitZ->getOperand(10); inits.push_back(c); // offset typeinfo if (cd->isInterfaceDeclaration()) { c = cinfo->llvmInitZ->getOperand(11); } else { c = build_offti_array(cd, cinfo->llvmInitZ->getOperand(11)); } inits.push_back(c); // default constructor if (cd->defaultCtor && !cd->isInterfaceDeclaration()) { DtoForceDeclareDsymbol(cd->defaultCtor); c = isaConstant(cd->defaultCtor->llvmValue); const llvm::Type* toTy = cinfo->llvmInitZ->getOperand(12)->getType(); c = llvm::ConstantExpr::getBitCast(c, toTy); } else { c = cinfo->llvmInitZ->getOperand(12); } inits.push_back(c); /*size_t n = inits.size(); for (size_t i=0; illvmInitZ->getType()); llvm::Constant* finalinit = llvm::ConstantStruct::get(st, inits); //Logger::cout() << "built the classinfo initializer:\n" << *finalinit <<'\n'; cd->llvmClassZ = finalinit; cd->llvmClass->setInitializer(finalinit); }