LLGlobalVariable * IrStruct::getInterfaceArraySymbol() { if (classInterfacesArray) return classInterfacesArray; ClassDeclaration* cd = aggrdecl->isClassDeclaration(); size_t n = stripModifiers(type)->irtype->isClass()->getNumInterfaceVtbls(); assert(n > 0 && "getting ClassInfo.interfaces storage symbol, but we " "don't implement any interfaces"); VarDeclarationIter idx(ClassDeclaration::classinfo->fields, 3); LLType* InterfaceTy = DtoType(idx->type->nextOf()); // create Interface[N] LLArrayType* array_type = llvm::ArrayType::get(InterfaceTy,n); // put it in a global std::string name("_D"); name.append(cd->mangle()); name.append("16__interfaceInfosZ"); llvm::GlobalValue::LinkageTypes _linkage = DtoExternalLinkage(aggrdecl); classInterfacesArray = new llvm::GlobalVariable(*gIR->module, array_type, true, _linkage, NULL, name); return classInterfacesArray; }
IrFuncTy &DtoIrTypeFunction(DValue *fnval) { if (DFuncValue *dfnval = fnval->isFunc()) { if (dfnval->func) { return getIrFunc(dfnval->func)->irFty; } } Type *type = stripModifiers(fnval->getType()->toBasetype()); DtoType(type); assert(type->ctype); return type->ctype->getIrFuncTy(); }
LLGlobalVariable * IrStruct::getClassInfoSymbol() { if (classInfo) return classInfo; // create the initZ symbol std::string initname("_D"); initname.append(aggrdecl->mangle()); if (aggrdecl->isInterfaceDeclaration()) initname.append("11__InterfaceZ"); else initname.append("7__ClassZ"); llvm::GlobalValue::LinkageTypes _linkage = DtoExternalLinkage(aggrdecl); ClassDeclaration* cinfo = ClassDeclaration::classinfo; DtoType(cinfo->type); IrTypeClass* tc = stripModifiers(cinfo->type)->irtype->isClass(); assert(tc && "invalid ClassInfo type"); // classinfos cannot be constants since they're used as locks for synchronized classInfo = new llvm::GlobalVariable( *gIR->module, tc->getMemoryLLType(), false, _linkage, NULL, initname); #if USE_METADATA // Generate some metadata on this ClassInfo if it's for a class. ClassDeclaration* classdecl = aggrdecl->isClassDeclaration(); if (classdecl && !aggrdecl->isInterfaceDeclaration()) { // Gather information LLType* type = DtoType(aggrdecl->type); LLType* bodyType = llvm::cast<LLPointerType>(type)->getElementType(); bool hasDestructor = (classdecl->dtor != NULL); bool hasCustomDelete = (classdecl->aggDelete != NULL); // Construct the fields MDNodeField* mdVals[CD_NumFields]; mdVals[CD_BodyType] = llvm::UndefValue::get(bodyType); mdVals[CD_Finalize] = LLConstantInt::get(LLType::getInt1Ty(gIR->context()), hasDestructor); mdVals[CD_CustomDelete] = LLConstantInt::get(LLType::getInt1Ty(gIR->context()), hasCustomDelete); // Construct the metadata and insert it into the module. llvm::SmallString<64> name; llvm::NamedMDNode* node = gIR->module->getOrInsertNamedMetadata( llvm::Twine(CD_PREFIX, initname).toStringRef(name)); node->addOperand(llvm::MDNode::get(gIR->context(), llvm::makeArrayRef(mdVals, CD_NumFields))); } #endif // USE_METADATA return classInfo; }
LLGlobalVariable * IrStruct::getVtblSymbol() { if (vtbl) return vtbl; // create the initZ symbol std::string initname("_D"); initname.append(aggrdecl->mangle()); initname.append("6__vtblZ"); llvm::GlobalValue::LinkageTypes _linkage = DtoExternalLinkage(aggrdecl); LLType* vtblTy = stripModifiers(type)->irtype->isClass()->getVtbl(); vtbl = new llvm::GlobalVariable( *gIR->module, vtblTy, true, _linkage, NULL, initname); return vtbl; }
LLType* DtoType(Type* t) { t = stripModifiers( t ); if (t->ctype) { return t->ctype->getLLType(); } IF_LOG Logger::println("Building type: %s", t->toChars()); LOG_SCOPE; assert(t); switch (t->ty) { // basic types case Tvoid: case Tint8: case Tuns8: case Tint16: case Tuns16: case Tint32: case Tuns32: case Tint64: case Tuns64: case Tint128: case Tuns128: case Tfloat32: case Tfloat64: case Tfloat80: case Timaginary32: case Timaginary64: case Timaginary80: case Tcomplex32: case Tcomplex64: case Tcomplex80: //case Tbit: case Tbool: case Tchar: case Twchar: case Tdchar: { return IrTypeBasic::get(t)->getLLType(); } // pointers case Tnull: case Tpointer: { return IrTypePointer::get(t)->getLLType(); } // arrays case Tarray: { return IrTypeArray::get(t)->getLLType(); } case Tsarray: { return IrTypeSArray::get(t)->getLLType(); } // aggregates case Tstruct: { TypeStruct* ts = static_cast<TypeStruct*>(t); if (ts->sym->type->ctype) { // This should not happen, but the frontend seems to be buggy. Not // sure if this is the best way to handle the situation, but we // certainly don't want to override ts->sym->type->ctype. IF_LOG Logger::cout() << "Struct with multiple Types detected: " << ts->toChars() << " (" << ts->sym->locToChars() << ")" << std::endl; return ts->sym->type->ctype->getLLType(); } return IrTypeStruct::get(ts->sym)->getLLType(); } case Tclass: { TypeClass* tc = static_cast<TypeClass*>(t); if (tc->sym->type->ctype) { // See Tstruct case. IF_LOG Logger::cout() << "Class with multiple Types detected: " << tc->toChars() << " (" << tc->sym->locToChars() << ")" << std::endl; return tc->sym->type->ctype->getLLType(); } return IrTypeClass::get(tc->sym)->getLLType(); } // functions case Tfunction: { return IrTypeFunction::get(t)->getLLType(); } // delegates case Tdelegate: { return IrTypeDelegate::get(t)->getLLType(); } // typedefs // enum // FIXME: maybe just call toBasetype first ? case Tenum: { Type* bt = t->toBasetype(); assert(bt); return DtoType(bt); } // associative arrays case Taarray: return getVoidPtrType(); case Tvector: { return IrTypeVector::get(t)->getLLType(); } /* Not needed atm as VarDecls for tuples are rewritten as a string of VarDecls for the fields (u -> _u_field_0, ...) case Ttuple: { TypeTuple* ttupl = static_cast<TypeTuple*>(t); return DtoStructTypeFromArguments(ttupl->arguments); } */ default: llvm_unreachable("Unknown class of D Type!"); } return 0; }
DValue* DtoCastClass(Loc& loc, DValue* val, Type* _to) { IF_LOG Logger::println("DtoCastClass(%s, %s)", val->getType()->toChars(), _to->toChars()); LOG_SCOPE; Type* to = _to->toBasetype(); // class -> pointer if (to->ty == Tpointer) { IF_LOG Logger::println("to pointer"); LLType* tolltype = DtoType(_to); LLValue* rval = DtoBitCast(val->getRVal(), tolltype); return new DImValue(_to, rval); } // class -> bool else if (to->ty == Tbool) { IF_LOG Logger::println("to bool"); LLValue* llval = val->getRVal(); LLValue* zero = LLConstant::getNullValue(llval->getType()); return new DImValue(_to, gIR->ir->CreateICmpNE(llval, zero)); } // class -> integer else if (to->isintegral()) { IF_LOG Logger::println("to %s", to->toChars()); // get class ptr LLValue* v = val->getRVal(); // cast to size_t v = gIR->ir->CreatePtrToInt(v, DtoSize_t(), ""); // cast to the final int type DImValue im(Type::tsize_t, v); return DtoCastInt(loc, &im, _to); } // must be class/interface assert(to->ty == Tclass); TypeClass* tc = static_cast<TypeClass*>(to); // from type Type* from = val->getType()->toBasetype(); TypeClass* fc = static_cast<TypeClass*>(from); // x -> interface if (InterfaceDeclaration* it = tc->sym->isInterfaceDeclaration()) { Logger::println("to interface"); // interface -> interface if (fc->sym->isInterfaceDeclaration()) { Logger::println("from interface"); return DtoDynamicCastInterface(loc, val, _to); } // class -> interface - static cast else if (it->isBaseOf(fc->sym,NULL)) { Logger::println("static down cast"); // get the from class ClassDeclaration* cd = fc->sym->isClassDeclaration(); DtoResolveClass(cd); // add this IrTypeClass* typeclass = stripModifiers(fc)->ctype->isClass(); // find interface impl size_t i_index = typeclass->getInterfaceIndex(it); assert(i_index != ~0UL && "requesting interface that is not implemented by this class"); // offset pointer LLValue* v = val->getRVal(); LLValue* orig = v; v = DtoGEPi(v, 0, i_index); LLType* ifType = DtoType(_to); IF_LOG { Logger::cout() << "V = " << *v << std::endl; Logger::cout() << "T = " << *ifType << std::endl; } v = DtoBitCast(v, ifType); // Check whether the original value was null, and return null if so. // Sure we could have jumped over the code above in this case, but // it's just a GEP and (maybe) a pointer-to-pointer BitCast, so it // should be pretty cheap and perfectly safe even if the original was null. LLValue* isNull = gIR->ir->CreateICmpEQ(orig, LLConstant::getNullValue(orig->getType()), ".nullcheck"); v = gIR->ir->CreateSelect(isNull, LLConstant::getNullValue(ifType), v, ".interface"); // return r-value return new DImValue(_to, v); }
LLConstant * IrStruct::getClassInfoInterfaces() { IF_LOG Logger::println("Building ClassInfo.interfaces"); LOG_SCOPE; ClassDeclaration* cd = aggrdecl->isClassDeclaration(); assert(cd); size_t n = interfacesWithVtbls.size(); assert(stripModifiers(type)->irtype->isClass()->getNumInterfaceVtbls() == n && "inconsistent number of interface vtables in this class"); VarDeclarationIter interfaces_idx(ClassDeclaration::classinfo->fields, 3); if (n == 0) return getNullValue(DtoType(interfaces_idx->type)); // Build array of: // // struct Interface // { // ClassInfo classinfo; // void*[] vtbl; // ptrdiff_t offset; // } LLSmallVector<LLConstant*, 6> constants; constants.reserve(cd->vtblInterfaces->dim); LLType* classinfo_type = DtoType(ClassDeclaration::classinfo->type); LLType* voidptrptr_type = DtoType( Type::tvoid->pointerTo()->pointerTo()); VarDeclarationIter idx(ClassDeclaration::classinfo->fields, 3); LLStructType* interface_type = isaStruct(DtoType(idx->type->nextOf())); assert(interface_type); for (size_t i = 0; i < n; ++i) { BaseClass* it = interfacesWithVtbls[i]; IF_LOG Logger::println("Adding interface %s", it->base->toPrettyChars()); IrStruct* irinter = it->base->ir.irStruct; assert(irinter && "interface has null IrStruct"); IrTypeClass* itc = stripModifiers(irinter->type)->irtype->isClass(); assert(itc && "null interface IrTypeClass"); // classinfo LLConstant* ci = irinter->getClassInfoSymbol(); ci = DtoBitCast(ci, classinfo_type); // vtbl LLConstant* vtb; // interface get a null if (cd->isInterfaceDeclaration()) { vtb = DtoConstSlice(DtoConstSize_t(0), getNullValue(voidptrptr_type)); } else { ClassGlobalMap::iterator itv = interfaceVtblMap.find(it->base); assert(itv != interfaceVtblMap.end() && "interface vtbl not found"); vtb = itv->second; vtb = DtoBitCast(vtb, voidptrptr_type); vtb = DtoConstSlice(DtoConstSize_t(itc->getVtblSize()), vtb); } // offset LLConstant* off = DtoConstSize_t(it->offset); // create Interface struct LLConstant* inits[3] = { ci, vtb, off }; LLConstant* entry = LLConstantStruct::get(interface_type, llvm::makeArrayRef(inits, 3)); constants.push_back(entry); } // create Interface[N] LLArrayType* array_type = llvm::ArrayType::get(interface_type, n); // create and apply initializer LLConstant* arr = LLConstantArray::get(array_type, constants); classInterfacesArray->setInitializer(arr); // return null, only baseclass provide interfaces if (cd->vtblInterfaces->dim == 0) { return getNullValue(DtoType(interfaces_idx->type)); } // only the interface explicitly implemented by this class // (not super classes) should show in ClassInfo LLConstant* idxs[2] = { DtoConstSize_t(0), DtoConstSize_t(n - cd->vtblInterfaces->dim) }; LLConstant* ptr = llvm::ConstantExpr::getGetElementPtr( classInterfacesArray, idxs, true); // return as a slice return DtoConstSlice( DtoConstSize_t(cd->vtblInterfaces->dim), ptr ); }
void IrStruct::addBaseClassInits( std::vector<llvm::Constant*>& constants, ClassDeclaration* base, size_t& offset, size_t& field_index) { if (base->baseClass) { addBaseClassInits(constants, base->baseClass, offset, field_index); } IrTypeClass* tc = stripModifiers(base->type)->irtype->isClass(); assert(tc); // go through fields IrTypeAggr::iterator it; for (it = tc->def_begin(); it != tc->def_end(); ++it) { VarDeclaration* vd = *it; IF_LOG Logger::println("Adding default field %s %s (+%u)", vd->type->toChars(), vd->toChars(), vd->offset); LOG_SCOPE; assert(vd->offset >= offset && "default fields not sorted by offset"); // get next aligned offset for this type size_t alignedoffset = realignOffset(offset, vd->type); // insert explicit padding? if (alignedoffset < vd->offset) { add_zeros(constants, vd->offset - alignedoffset); } // add default type constants.push_back(get_default_initializer(vd, vd->init)); // advance offset to right past this field offset = vd->offset + vd->type->size(); } // has interface vtbls? if (base->vtblInterfaces && base->vtblInterfaces->dim > 0) { // false when it's not okay to use functions from super classes bool newinsts = (base == aggrdecl->isClassDeclaration()); size_t inter_idx = interfacesWithVtbls.size(); offset = (offset + PTRSIZE - 1) & ~(PTRSIZE - 1); ArrayIter<BaseClass> it2(*base->vtblInterfaces); for (; !it2.done(); it2.next()) { BaseClass* b = it2.get(); constants.push_back(getInterfaceVtbl(b, newinsts, inter_idx)); offset += PTRSIZE; // add to the interface list interfacesWithVtbls.push_back(b); inter_idx++; } } }
LLConstant * IrStruct::getVtblInit() { if (constVtbl) return constVtbl; IF_LOG Logger::println("Building vtbl initializer"); LOG_SCOPE; ClassDeclaration* cd = aggrdecl->isClassDeclaration(); assert(cd && "not class"); std::vector<llvm::Constant*> constants; constants.reserve(cd->vtbl.dim); // start with the classinfo llvm::Constant* c = getClassInfoSymbol(); c = DtoBitCast(c, DtoType(ClassDeclaration::classinfo->type)); constants.push_back(c); // add virtual function pointers size_t n = cd->vtbl.dim; for (size_t i = 1; i < n; i++) { Dsymbol* dsym = static_cast<Dsymbol*>(cd->vtbl.data[i]); assert(dsym && "null vtbl member"); FuncDeclaration* fd = dsym->isFuncDeclaration(); assert(fd && "vtbl entry not a function"); if (cd->isAbstract() || (fd->isAbstract() && !fd->fbody)) { c = getNullValue(DtoType(fd->type->pointerTo())); } else { fd->codegen(Type::sir); assert(fd->ir.irFunc && "invalid vtbl function"); c = fd->ir.irFunc->func; #if DMDV2 if (cd->isFuncHidden(fd)) { /* fd is hidden from the view of this class. * If fd overlaps with any function in the vtbl[], then * issue 'hidden' error. */ for (size_t j = 1; j < n; j++) { if (j == i) continue; FuncDeclaration *fd2 = static_cast<Dsymbol *>(cd->vtbl.data[j])->isFuncDeclaration(); if (!fd2->ident->equals(fd->ident)) continue; if (fd->leastAsSpecialized(fd2) || fd2->leastAsSpecialized(fd)) { if (global.params.warnings) { TypeFunction *tf = static_cast<TypeFunction *>(fd->type); if (tf->ty == Tfunction) error("%s%s is hidden by %s\n", fd->toPrettyChars(), Parameter::argsTypesToChars(tf->parameters, tf->varargs), toChars()); else error("%s is hidden by %s\n", fd->toPrettyChars(), toChars()); } c = DtoBitCast(LLVM_D_GetRuntimeFunction(gIR->module, "_d_hidden_func"), c->getType()); break; } } } #endif } constants.push_back(c); } // build the constant struct LLType* vtblTy = stripModifiers(type)->irtype->isClass()->getVtbl(); constVtbl = LLConstantStruct::get(isaStruct(vtblTy), constants); #if 0 IF_LOG Logger::cout() << "constVtbl type: " << *constVtbl->getType() << std::endl; IF_LOG Logger::cout() << "vtbl type: " << *stripModifiers(type)->irtype->isClass()->getVtbl() << std::endl; #endif #if 0 size_t nc = constants.size(); for (size_t i = 0; i < nc; ++i) { if (constVtbl->getOperand(i)->getType() != vtblTy->getContainedType(i)) { Logger::cout() << "type mismatch for entry # " << i << " in vtbl initializer" << std::endl; constVtbl->getOperand(i)->dump(); vtblTy->getContainedType(i)->dump(); } } #endif assert(constVtbl->getType() == stripModifiers(type)->irtype->isClass()->getVtbl() && "vtbl initializer type mismatch"); return constVtbl; }
LLType *DtoType(Type *t) { t = stripModifiers(t); if (t->ctype) { return t->ctype->getLLType(); } IF_LOG Logger::println("Building type: %s", t->toChars()); LOG_SCOPE; assert(t); switch (t->ty) { // basic types case Tvoid: case Tint8: case Tuns8: case Tint16: case Tuns16: case Tint32: case Tuns32: case Tint64: case Tuns64: case Tint128: case Tuns128: case Tfloat32: case Tfloat64: case Tfloat80: case Timaginary32: case Timaginary64: case Timaginary80: case Tcomplex32: case Tcomplex64: case Tcomplex80: // case Tbit: case Tbool: case Tchar: case Twchar: case Tdchar: { return IrTypeBasic::get(t)->getLLType(); } // pointers case Tnull: case Tpointer: case Treference: { // CALYPSO return IrTypePointer::get(t)->getLLType(); } // arrays case Tarray: { return IrTypeArray::get(t)->getLLType(); } case Tsarray: { return IrTypeSArray::get(t)->getLLType(); } // aggregates case Tstruct: { TypeStruct *ts = static_cast<TypeStruct *>(t); if (ts->sym->type->ctype) { // This should not happen, but the frontend seems to be buggy. Not // sure if this is the best way to handle the situation, but we // certainly don't want to override ts->sym->type->ctype. IF_LOG Logger::cout() << "Struct with multiple Types detected: " << ts->toChars() << " (" << ts->sym->locToChars() << ")" << std::endl; return ts->sym->type->ctype->getLLType(); } return IrTypeStruct::get(ts->sym)->getLLType(); } case Tclass: { TypeClass *tc = static_cast<TypeClass *>(t); if (tc->sym->type->ctype) { // See Tstruct case. IF_LOG Logger::cout() << "Class with multiple Types detected: " << tc->toChars() << " (" << tc->sym->locToChars() << ")" << std::endl; return tc->sym->type->ctype->getLLType(); } return IrTypeClass::get(tc->sym)->getLLType(); } // functions case Tfunction: { return IrTypeFunction::get(t)->getLLType(); } // delegates case Tdelegate: { return IrTypeDelegate::get(t)->getLLType(); } // typedefs // enum // FIXME: maybe just call toBasetype first ? case Tenum: { Type *bt = t->toBasetype(); assert(bt); if (t == bt) { // This is an enum forward reference that is only legal when referenced // through an indirection (e.g. "enum E; void foo(E* p);"). For lack of a // better choice, make the outer indirection a void pointer. return getVoidPtrType()->getContainedType(0); } return DtoType(bt); } // associative arrays case Taarray: return getVoidPtrType(); case Tvector: { return IrTypeVector::get(t)->getLLType(); } default: llvm_unreachable("Unknown class of D Type!"); } return nullptr; }
LLConstant* 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; // version(D_Version2) // const(MemberInfo[]) function(string) xgetMembers; // else // TypeInfo typeinfo; // since dmd 1.045 // } Logger::println("DtoDefineClassInfo(%s)", cd->toChars()); LOG_SCOPE; assert(cd->type->ty == Tclass); TypeClass* cdty = static_cast<TypeClass*>(cd->type); IrStruct* ir = cd->ir.irStruct; assert(ir); ClassDeclaration* cinfo = ClassDeclaration::classinfo; if (cinfo->fields.dim != 12) { error("object.d ClassInfo class is incorrect"); fatal(); } // use the rtti builder RTTIBuilder b(ClassDeclaration::classinfo); LLConstant* c; LLType* voidPtr = getVoidPtrType(); LLType* voidPtrPtr = getPtrToType(voidPtr); // byte[] init if (cd->isInterfaceDeclaration()) { b.push_null_void_array(); } else { LLType* cd_type = stripModifiers(cdty)->irtype->getType(); size_t initsz = getTypePaddedSize(cd_type); b.push_void_array(initsz, ir->getInitSymbol()); } // class name // code from dmd const char *name = cd->ident->toChars(); size_t namelen = strlen(name); if (!(namelen > 9 && memcmp(name, "TypeInfo_", 9) == 0)) { name = cd->toPrettyChars(); namelen = strlen(name); } b.push_string(name); // vtbl array if (cd->isInterfaceDeclaration()) { b.push_array(0, getNullValue(voidPtrPtr)); } else { c = DtoBitCast(ir->getVtblSymbol(), voidPtrPtr); b.push_array(cd->vtbl.dim, c); } // interfaces array b.push(ir->getClassInfoInterfaces()); // base classinfo // interfaces never get a base , just the interfaces[] if (cd->baseClass && !cd->isInterfaceDeclaration()) b.push_classinfo(cd->baseClass); else b.push_null(cinfo->type); // destructor if (cd->isInterfaceDeclaration()) b.push_null_vp(); else b.push(build_class_dtor(cd)); // invariant VarDeclaration* invVar = static_cast<VarDeclaration*>(cinfo->fields.data[6]); b.push_funcptr(cd->inv, invVar->type); // uint flags if (cd->isInterfaceDeclaration()) b.push_uint(4 | cd->isCOMinterface() | 32); else b.push_uint(build_classinfo_flags(cd)); // deallocator b.push_funcptr(cd->aggDelete, Type::tvoid->pointerTo()); // offset typeinfo VarDeclaration* offTiVar = static_cast<VarDeclaration*>(cinfo->fields.data[9]); #if GENERATE_OFFTI if (cd->isInterfaceDeclaration()) b.push_null(offTiVar->type); else b.push(build_offti_array(cd, DtoType(offTiVar->type))); #else // GENERATE_OFFTI b.push_null(offTiVar->type); #endif // GENERATE_OFFTI // default constructor VarDeclaration* defConstructorVar = static_cast<VarDeclaration*>(cinfo->fields.data[10]); b.push_funcptr(cd->defaultCtor, defConstructorVar->type); #if DMDV2 // xgetMembers VarDeclaration* xgetVar = static_cast<VarDeclaration*>(cinfo->fields.data[11]); b.push_funcptr(cd->findGetMembers(), xgetVar->type); #else // typeinfo - since 1.045 b.push_typeinfo(cd->type); #endif /*size_t n = inits.size(); for (size_t i=0; i<n; ++i) { Logger::cout() << "inits[" << i << "]: " << *inits[i] << '\n'; }*/ // build the initializer LLType *initType = ir->classInfo->getType()->getContainedType(0); LLConstant* finalinit = b.get_constant(isaStruct(initType)); //Logger::cout() << "built the classinfo initializer:\n" << *finalinit <<'\n'; ir->constClassInfo = finalinit; // sanity check assert(finalinit->getType() == initType && "__ClassZ initializer does not match the ClassInfo type"); // return initializer return finalinit; }