void visit(ClassDeclaration *decl) override { IF_LOG Logger::println("ClassDeclaration::codegen: '%s'", decl->toPrettyChars()); LOG_SCOPE assert(!irs->dcomputetarget); if (decl->ir->isDefined()) { return; } if (decl->type->ty == Terror) { error(decl->loc, "had semantic errors when compiling"); decl->ir->setDefined(); return; } if (decl->members && decl->symtab) { DtoResolveClass(decl); decl->ir->setDefined(); for (auto m : *decl->members) { m->accept(this); } IrAggr *ir = getIrAggr(decl); const auto lwc = DtoLinkage(decl); auto &initZ = ir->getInitSymbol(); auto initGlobal = llvm::cast<LLGlobalVariable>(initZ); initZ = irs->setGlobalVarInitializer(initGlobal, ir->getDefaultInit()); setLinkage(lwc, initGlobal); llvm::GlobalVariable *vtbl = ir->getVtblSymbol(); vtbl->setInitializer(ir->getVtblInit()); setLinkage(lwc, vtbl); llvm::GlobalVariable *classZ = ir->getClassInfoSymbol(); if (!isSpeculativeType(decl->type)) { classZ->setInitializer(ir->getClassInfoInit()); setLinkage(lwc, classZ); } } }
void visit(InterfaceDeclaration *decl) override { IF_LOG Logger::println("InterfaceDeclaration::codegen: '%s'", decl->toPrettyChars()); LOG_SCOPE assert(!irs->dcomputetarget); if (decl->ir->isDefined()) { return; } if (decl->type->ty == Terror) { error(decl->loc, "had semantic errors when compiling"); decl->ir->setDefined(); return; } if (decl->members && decl->symtab) { DtoResolveClass(decl); decl->ir->setDefined(); // Emit any members (e.g. final functions). for (auto m : *decl->members) { m->accept(this); } // Emit TypeInfo. DtoTypeInfoOf(decl->type, /*base=*/false); // Declare __InterfaceZ. IrAggr *ir = getIrAggr(decl); llvm::GlobalVariable *interfaceZ = ir->getClassInfoSymbol(); // Only define if not speculative. if (!isSpeculativeType(decl->type)) { interfaceZ->setInitializer(ir->getClassInfoInit()); setLinkage(decl, interfaceZ); } } }
LLConstant * IrAggr::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()); IrAggr* irinter = it->base->ir.irAggr; 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 DtoResolveClass(ClassDeclaration* cd) { // make sure the base classes are processed first ArrayIter<BaseClass> base_iter(cd->baseclasses); while (base_iter.more()) { BaseClass* bc = base_iter.get(); if (bc) { bc->base->codegen(Type::sir); } base_iter.next(); } if (cd->ir.resolved) return; cd->ir.resolved = true; Logger::println("DtoResolveClass(%s): %s", cd->toPrettyChars(), cd->loc.toChars()); LOG_SCOPE; // make sure type exists DtoType(cd->type); // create IrAggr assert(cd->ir.irAggr == NULL); IrAggr* irAggr = new IrAggr(cd); cd->ir.irAggr = irAggr; // make sure all fields really get their ir field ArrayIter<VarDeclaration> it(cd->fields); for (; !it.done(); it.next()) { VarDeclaration* vd = it.get(); if (vd->ir.irField == NULL) { new IrField(vd); } else { IF_LOG Logger::println("class field already exists!!!"); } } bool needs_def = mustDefineSymbol(cd); // emit the ClassZ symbol LLGlobalVariable* ClassZ = irAggr->getClassInfoSymbol(); // emit the interfaceInfosZ symbol if necessary if (cd->vtblInterfaces && cd->vtblInterfaces->dim > 0) irAggr->getInterfaceArraySymbol(); // initializer is applied when it's built // interface only emit typeinfo and classinfo if (cd->isInterfaceDeclaration()) { irAggr->initializeInterface(); } else { // emit the initZ symbol LLGlobalVariable* initZ = irAggr->getInitSymbol(); // emit the vtblZ symbol LLGlobalVariable* vtblZ = irAggr->getVtblSymbol(); // perform definition if (needs_def) { // set symbol initializers initZ->setInitializer(irAggr->getDefaultInit()); vtblZ->setInitializer(irAggr->getVtblInit()); } } // emit members if (cd->members) { ArrayIter<Dsymbol> it(*cd->members); while (!it.done()) { Dsymbol* member = it.get(); if (member) member->codegen(Type::sir); it.next(); } } if (needs_def) { // emit typeinfo DtoTypeInfoOf(cd->type); // define classinfo ClassZ->setInitializer(irAggr->getClassInfoInit()); } }