changeset 1230:e67c85d6e680

Completed interface implementation. Hopefully that's it for now..
author Tomas Lindquist Olsen <tomas.l.olsen gmail.com>
date Thu, 16 Apr 2009 13:18:56 +0200
parents fafe7c8d6734
children 212ec2d9d176
files ir/irclass.cpp ir/irstruct.h ir/irtypeclass.cpp ir/irtypeclass.h
diffstat 4 files changed, 74 insertions(+), 25 deletions(-) [+]
line wrap: on
line diff
--- a/ir/irclass.cpp	Thu Apr 16 11:01:49 2009 +0200
+++ b/ir/irclass.cpp	Thu Apr 16 13:18:56 2009 +0200
@@ -91,7 +91,7 @@
     // 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 @@
         // false when it's not okay to use functions from super classes
         bool newinsts = (base == aggrdecl->isClassDeclaration());
 
+        size_t inter_idx = interfacesWithVtbls.size();
+
         ArrayIter<BaseClass> 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 @@
 
 //////////////////////////////////////////////////////////////////////////////
 
-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 @@
         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 @@
     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 @@
         gIR->module
     );
 
+    // insert into the vtbl map
     interfaceVtblMap.insert(std::make_pair(b->base, GV));
 
     return GV;
@@ -357,7 +375,11 @@
     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 @@
 
     const LLType* our_type = type->irtype->isClass()->getPA().get();
 
-    ArrayIter<BaseClass> 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* 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* 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));
 }
 
--- a/ir/irstruct.h	Thu Apr 16 11:01:49 2009 +0200
+++ b/ir/irstruct.h	Thu Apr 16 13:18:56 2009 +0200
@@ -84,6 +84,14 @@
     /// Basically: static object.Interface[num_interfaces]
     llvm::GlobalVariable* classInterfacesArray;
 
+    /// std::vector of BaseClass*
+    typedef std::vector<BaseClass*> 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 @@
     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.
--- a/ir/irtypeclass.cpp	Thu Apr 16 11:01:49 2009 +0200
+++ b/ir/irtypeclass.cpp	Thu Apr 16 13:18:56 2009 +0200
@@ -24,6 +24,7 @@
     vtbl_pa(llvm::OpaqueType::get())
 {
     vtbl_size = cd->vtbl.dim;
+    num_interface_vtbls = 0;
 }
 
 //////////////////////////////////////////////////////////////////////////////
@@ -91,6 +92,9 @@
 
         ArrayIter<BaseClass> 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 @@
             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++;
         }
     }
 
--- a/ir/irtypeclass.h	Thu Apr 16 11:01:49 2009 +0200
+++ b/ir/irtypeclass.h	Thu Apr 16 13:18:56 2009 +0200
@@ -17,10 +17,10 @@
     const llvm::Type* buildType();
 
     ///
-    const llvm::Type* getVtbl()         { return vtbl_pa.get(); }
+    const llvm::Type* 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
@@ -30,28 +30,36 @@
     /// 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<ClassDeclaration*, size_t> 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);
 
     ///