diff --git a/ir/irclass.cpp b/ir/irclass.cpp index 5ab16a3a..060dbe84 100644 --- a/ir/irclass.cpp +++ b/ir/irclass.cpp @@ -91,7 +91,7 @@ LLGlobalVariable * IrStruct::getInterfaceArraySymbol() // create Interface[N] const llvm::ArrayType* array_type = llvm::ArrayType::get( InterfaceTy, - cd->vtblInterfaces->dim); + type->irtype->isClass()->getNumInterfaceVtbls()); // put it in a global std::string name("_D"); @@ -222,12 +222,18 @@ void IrStruct::addBaseClassInits( // false when it's not okay to use functions from super classes bool newinsts = (base == aggrdecl->isClassDeclaration()); + size_t inter_idx = interfacesWithVtbls.size(); + ArrayIter it2(*base->vtblInterfaces); for (; !it2.done(); it2.next()) { BaseClass* b = it2.get(); - constants.push_back(getInterfaceVtbl(b, newinsts)); + constants.push_back(getInterfaceVtbl(b, newinsts, inter_idx)); offset += PTRSIZE; + + // add to the interface list + interfacesWithVtbls.push_back(b); + inter_idx++; } } @@ -279,12 +285,9 @@ LLConstant * IrStruct::createClassDefaultInitializer() ////////////////////////////////////////////////////////////////////////////// -llvm::GlobalVariable * IrStruct::getInterfaceVtbl(BaseClass * b, bool new_instance) +llvm::GlobalVariable * IrStruct::getInterfaceVtbl(BaseClass * b, bool new_instance, size_t interfaces_index) { - ClassDeclaration* cd = aggrdecl->isClassDeclaration(); - assert(cd && "not a class aggregate"); - - ClassGlobalMap::iterator it = interfaceVtblMap.find(cd); + ClassGlobalMap::iterator it = interfaceVtblMap.find(b->base); if (it != interfaceVtblMap.end()) return it->second; @@ -292,6 +295,9 @@ llvm::GlobalVariable * IrStruct::getInterfaceVtbl(BaseClass * b, bool new_instan b->base->toPrettyChars(), aggrdecl->toPrettyChars()); LOG_SCOPE; + ClassDeclaration* cd = aggrdecl->isClassDeclaration(); + assert(cd && "not a class aggregate"); + Array vtbl_array; b->fillVtbl(cd, &vtbl_array, new_instance); @@ -299,7 +305,18 @@ llvm::GlobalVariable * IrStruct::getInterfaceVtbl(BaseClass * b, bool new_instan constants.reserve(vtbl_array.dim); // start with the interface info - llvm::Constant* c = getNullValue(DtoType(Type::tvoid->pointerTo())); + VarDeclarationIter interfaces_idx(ClassDeclaration::classinfo->fields, 3); + Type* first = interfaces_idx->type->next->pointerTo(); + + // index into the interfaces array + llvm::Constant* idxs[2] = { + DtoConstSize_t(0), + DtoConstSize_t(interfaces_index) + }; + + llvm::Constant* c = llvm::ConstantExpr::getGetElementPtr( + getInterfaceArraySymbol(), idxs, 2); + constants.push_back(c); // add virtual function pointers @@ -342,6 +359,7 @@ llvm::GlobalVariable * IrStruct::getInterfaceVtbl(BaseClass * b, bool new_instan gIR->module ); + // insert into the vtbl map interfaceVtblMap.insert(std::make_pair(b->base, GV)); return GV; @@ -357,7 +375,11 @@ LLConstant * IrStruct::getClassInfoInterfaces() ClassDeclaration* cd = aggrdecl->isClassDeclaration(); assert(cd); - if (!cd->vtblInterfaces || cd->vtblInterfaces->dim == 0) + size_t n = interfacesWithVtbls.size(); + assert(type->irtype->isClass()->getNumInterfaceVtbls() == n && + "inconsistent number of interface vtables in this class"); + + if (n == 0) { VarDeclarationIter idx(ClassDeclaration::classinfo->fields, 3); return getNullValue(DtoType(idx->type)); @@ -381,9 +403,10 @@ LLConstant * IrStruct::getClassInfoInterfaces() const LLType* our_type = type->irtype->isClass()->getPA().get(); - ArrayIter it(*cd->vtblInterfaces); - while (it.more()) + 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; @@ -409,15 +432,12 @@ LLConstant * IrStruct::getClassInfoInterfaces() LLConstant* inits[3] = { ci, vtb, off }; LLConstant* entry = llvm::ConstantStruct::get(inits, 3); constants.push_back(entry); - - // next - it.next(); } // create Interface[N] const llvm::ArrayType* array_type = llvm::ArrayType::get( constants[0]->getType(), - cd->vtblInterfaces->dim); + n); LLConstant* arr = llvm::ConstantArray::get( array_type, @@ -429,12 +449,14 @@ LLConstant * IrStruct::getClassInfoInterfaces() LLConstant* idxs[2] = { DtoConstSize_t(0), - DtoConstSize_t(0) + // only the interface explicitly implemented by this class + // (not super classes) should show in ClassInfo + DtoConstSize_t(n - cd->vtblInterfaces->dim) }; // return as a slice return DtoConstSlice( - DtoConstSize_t(cd->vtblInterfaces->dim), + DtoConstSize_t(n), llvm::ConstantExpr::getGetElementPtr(classInterfacesArray, idxs, 2)); } diff --git a/ir/irstruct.h b/ir/irstruct.h index 46a0fad2..5c2e2b26 100644 --- a/ir/irstruct.h +++ b/ir/irstruct.h @@ -84,6 +84,14 @@ protected: /// Basically: static object.Interface[num_interfaces] llvm::GlobalVariable* classInterfacesArray; + /// std::vector of BaseClass* + typedef std::vector BaseClassVector; + + /// Array of all interface vtbl implementations - in order - implemented + /// by this class. + /// Corresponds to the Interface instances needed to be output. + BaseClassVector interfacesWithVtbls; + ////////////////////////////////////////////////////////////////////////// /// Create static default initializer for struct. @@ -93,7 +101,10 @@ protected: LLConstant* createClassDefaultInitializer(); /// Returns vtbl for interface implementation, creates it if not already built. - llvm::GlobalVariable* getInterfaceVtbl(BaseClass* b, bool new_inst); + llvm::GlobalVariable* getInterfaceVtbl( + BaseClass* b, + bool new_inst, + size_t interfaces_index); /// Add base class data to initializer list. /// Also creates the IrField instance for each data field. diff --git a/ir/irtypeclass.cpp b/ir/irtypeclass.cpp index fec752cf..50a3339b 100644 --- a/ir/irtypeclass.cpp +++ b/ir/irtypeclass.cpp @@ -24,6 +24,7 @@ IrTypeClass::IrTypeClass(ClassDeclaration* cd) vtbl_pa(llvm::OpaqueType::get()) { vtbl_size = cd->vtbl.dim; + num_interface_vtbls = 0; } ////////////////////////////////////////////////////////////////////////////// @@ -91,6 +92,9 @@ void IrTypeClass::addBaseClassData( ArrayIter it2(*base->vtblInterfaces); + VarDeclarationIter interfaces_idx(ClassDeclaration::classinfo->fields, 3); + Type* first = interfaces_idx->type->next->pointerTo(); + for (; !it2.done(); it2.next()) { BaseClass* b = it2.get(); @@ -99,15 +103,19 @@ void IrTypeClass::addBaseClassData( Array arr; b->fillVtbl(cd, &arr, new_instances); - const llvm::Type* ivtbl_type = buildVtblType(Type::tvoid->pointerTo(), &arr); + const llvm::Type* ivtbl_type = buildVtblType(first, &arr); defaultTypes.push_back(llvm::PointerType::get(ivtbl_type, 0)); offset += PTRSIZE; // add to the interface map + // FIXME: and all it's baseinterfaces if (interfaceMap.find(b->base) == interfaceMap.end()) interfaceMap.insert(std::make_pair(b->base, field_index)); field_index++; + + // inc count + num_interface_vtbls++; } } diff --git a/ir/irtypeclass.h b/ir/irtypeclass.h index 9dcf5a3c..d82ec971 100644 --- a/ir/irtypeclass.h +++ b/ir/irtypeclass.h @@ -16,12 +16,12 @@ public: /// const llvm::Type* buildType(); - /// - const llvm::Type* getVtbl() { return vtbl_pa.get(); } - /// const llvm::Type* get(); + /// Returns the vtable type for this class. + const llvm::Type* getVtbl() { return vtbl_pa.get(); } + /// Get index to interface implementation. /// Returns the index of a specific interface implementation in this /// class or ~0 if not found. @@ -30,28 +30,36 @@ public: /// Returns the total number of pointers in the vtable. unsigned getVtblSize() { return vtbl_size; } + /// Returns the number of interface implementations (vtables) in this + /// class. + unsigned getNumInterfaceVtbls() { return num_interface_vtbls; } + protected: /// ClassDeclaration* cd; /// TypeClass* tc; - /// + /// Type holder for the vtable type. llvm::PATypeHolder vtbl_pa; /// Number of pointers in vtable. unsigned vtbl_size; + /// Number of interface implementations (vtables) in this class. + unsigned num_interface_vtbls; + /// std::map type mapping ClassDeclaration* to size_t. typedef std::map ClassIndexMap; /// Map for mapping the index of a specific interface implementation - /// in this class to it's ClassDeclaration*. + /// in this class to its ClassDeclaration. ClassIndexMap interfaceMap; ////////////////////////////////////////////////////////////////////////// - /// + /// Builds a vtable type given the type of the first entry and an array + /// of all entries. const llvm::Type* buildVtblType(Type* first, Array* vtbl_array); ///