Work-in-progess rewrite of thunks: move thunk generation outside of vtable
generation, and make sure we generate thunks when the function is defined
rather than when the vtable is defined.

llvm-svn: 90722
diff --git a/clang/lib/CodeGen/CGVtable.cpp b/clang/lib/CodeGen/CGVtable.cpp
index 65c412e..857e661 100644
--- a/clang/lib/CodeGen/CGVtable.cpp
+++ b/clang/lib/CodeGen/CGVtable.cpp
@@ -73,6 +73,7 @@
     /// Methods - The methods, in vtable order.
     typedef llvm::SmallVector<GlobalDecl, 16> MethodsVectorTy;
     MethodsVectorTy Methods;
+    MethodsVectorTy OrigMethods;
 
   public:
     /// AddMethod - Add a method to the vtable methods.
@@ -82,6 +83,7 @@
       
       MethodToIndexMap[GD] = Methods.size();
       Methods.push_back(GD);
+      OrigMethods.push_back(GD);
     }
     
     /// OverrideMethod - Replace a method with another.
@@ -113,6 +115,10 @@
       return true;
     }
 
+    GlobalDecl getOrigMethod(uint64_t Index) const {
+      return OrigMethods[Index];
+    }
+
     MethodsVectorTy::size_type size() const {
       return Methods.size();
     }
@@ -120,6 +126,7 @@
     void clear() {
       MethodToIndexMap.clear();
       Methods.clear();
+      OrigMethods.clear();
     }
     
     GlobalDecl operator[](uint64_t Index) const {
@@ -135,6 +142,10 @@
   typedef llvm::DenseMap<uint64_t, ThunkAdjustment> ThisAdjustmentsMapTy;
   ThisAdjustmentsMapTy ThisAdjustments;
 
+  typedef std::vector<std::pair<std::pair<GlobalDecl, GlobalDecl>,
+                                ThunkAdjustment> > SavedThisAdjustmentsVectorTy;
+  SavedThisAdjustmentsVectorTy SavedThisAdjustments;
+
   /// BaseReturnTypes - Contains the base return types of methods who have been
   /// overridden with methods whose return types require adjustment. Used for
   /// generating covariant thunk information.
@@ -202,6 +213,9 @@
   llvm::DenseMap<const CXXRecordDecl *, Index_t> &getVBIndex()
     { return VBIndex; }
 
+  SavedThisAdjustmentsVectorTy &getSavedThisAdjustments()
+    { return SavedThisAdjustments; }
+
   llvm::Constant *wrap(Index_t i) {
     llvm::Constant *m;
     m = llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), i);
@@ -762,11 +776,17 @@
     else
       OGD = OMD;
 
-    // FIXME: Explain why this is necessary!
+    // Check whether this is the method being overridden in this section of
+    // the vtable.
     uint64_t Index;
     if (!Methods.getIndex(OGD, Index))
       continue;
 
+    // Get the original method, which we should be computing thunks, etc,
+    // against.
+    OGD = Methods.getOrigMethod(Index);
+    OMD = cast<CXXMethodDecl>(OGD.getDecl());
+
     QualType ReturnType = 
       MD->getType()->getAs<FunctionType>()->getResultType();
     QualType OverriddenReturnType = 
@@ -777,10 +797,6 @@
                                           OverriddenReturnType)) {
       CanQualType &BaseReturnType = BaseReturnTypes[Index];
 
-      // Get the canonical return type.
-      CanQualType CanReturnType = 
-        CGM.getContext().getCanonicalType(ReturnType);
-
       // Insert the base return type.
       if (BaseReturnType.isNull())
         BaseReturnType =
@@ -820,8 +836,12 @@
       ThunkAdjustment ThisAdjustment(NonVirtualAdjustment,
                                       VirtualAdjustment);
 
-      if (!isPure && !ThisAdjustment.isEmpty())
+      if (!isPure && !ThisAdjustment.isEmpty()) {
         ThisAdjustments[Index] = ThisAdjustment;
+        // FIXME: Might this end up inserting some false adjustments?
+        SavedThisAdjustments.push_back(std::make_pair(std::make_pair(GD, OGD),
+                                                      ThisAdjustment));
+      }
       return true;
     }
 
@@ -882,10 +902,10 @@
     if (!ReturnAdjustment.isEmpty()) {
       // Build a covariant thunk.
       CovariantThunkAdjustment Adjustment(ThisAdjustment, ReturnAdjustment);
-      Method = CGM.BuildCovariantThunk(MD, Extern, Adjustment);
+      Method = wrap(CGM.GetAddrOfCovariantThunk(GD, Adjustment));
     } else if (!ThisAdjustment.isEmpty()) {
       // Build a "regular" thunk.
-      Method = CGM.BuildThunk(GD, Extern, ThisAdjustment);
+      Method = wrap(CGM.GetAddrOfThunk(GD, ThisAdjustment));
     } else if (MD->isPure()) {
       // We have a pure virtual method.
       Method = getPureVirtualFn();
@@ -1048,6 +1068,32 @@
   return I->second;
 }
 
+ThunkAdjustment CGVtableInfo::getThisAdjustment(GlobalDecl GD,
+                                                GlobalDecl OGD) {
+  SavedThisAdjustmentsTy::iterator I =
+    SavedThisAdjustments.find(std::make_pair(GD, OGD));
+  if (I != SavedThisAdjustments.end())
+    return I->second;
+
+  const CXXRecordDecl *RD = cast<CXXRecordDecl>(GD.getDecl()->getDeclContext());
+  if (!SavedThisAdjustmentRecords.insert(RD).second)
+    return ThunkAdjustment();
+
+  VtableBuilder b(RD, RD, 0, CGM, false);
+  D1(printf("vtable %s\n", RD->getNameAsCString()));
+  b.GenerateVtableForBase(RD);
+  b.GenerateVtableForVBases(RD);
+  
+  SavedThisAdjustments.insert(b.getSavedThisAdjustments().begin(),
+                              b.getSavedThisAdjustments().end());
+
+  I = SavedThisAdjustments.find(std::make_pair(GD, OGD));
+  if (I != SavedThisAdjustments.end())
+    return I->second;
+
+  return ThunkAdjustment();
+}
+
 int64_t CGVtableInfo::getVirtualBaseOffsetIndex(const CXXRecordDecl *RD, 
                                                 const CXXRecordDecl *VBase) {
   ClassPairTy ClassPair(RD, VBase);
@@ -1416,5 +1462,17 @@
   
   // Emit the data.
   GenerateClassData(Linkage, RD);
+
+  for (CXXRecordDecl::method_iterator i = RD->method_begin(),
+       e = RD->method_end(); i != e; ++i) {
+    if ((*i)->isVirtual() && (*i)->hasInlineBody()) {
+      if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(*i)) {
+        CGM.BuildThunksForVirtual(GlobalDecl(DD, Dtor_Complete));
+        CGM.BuildThunksForVirtual(GlobalDecl(DD, Dtor_Deleting));
+      } else {
+        CGM.BuildThunksForVirtual(GlobalDecl(*i));
+      }
+    }
+  }
 }