[cfe-commits] r129896 - in /cfe/trunk: include/clang/AST/Expr.h lib/AST/Expr.cpp lib/AST/ExprConstant.cpp lib/CodeGen/CGExprAgg.cpp lib/CodeGen/CGExprConstant.cpp lib/Sema/SemaInit.cpp lib/Serialization/ASTReaderStmt.cpp lib/Serialization/ASTWriterStmt.cpp test/Index/initializer-memory.cpp

Argyrios Kyrtzidis akyrtzi at gmail.com
Wed Apr 20 17:27:41 PDT 2011


Author: akirtzidis
Date: Wed Apr 20 19:27:41 2011
New Revision: 129896

URL: http://llvm.org/viewvc/llvm-project?rev=129896&view=rev
Log:
For

double data[20000000] = {0};

we would blow out the memory by creating 20M Exprs to fill out the initializer.

To fix this, if the initializer list initializes an array with more elements than
there are initializers in the list, have InitListExpr store a single 'ArrayFiller' expression
that specifies an expression to be used for value initialization of the rest of the elements.

Fixes rdar://9275920.

Added:
    cfe/trunk/test/Index/initializer-memory.cpp
Modified:
    cfe/trunk/include/clang/AST/Expr.h
    cfe/trunk/lib/AST/Expr.cpp
    cfe/trunk/lib/AST/ExprConstant.cpp
    cfe/trunk/lib/CodeGen/CGExprAgg.cpp
    cfe/trunk/lib/CodeGen/CGExprConstant.cpp
    cfe/trunk/lib/Sema/SemaInit.cpp
    cfe/trunk/lib/Serialization/ASTReaderStmt.cpp
    cfe/trunk/lib/Serialization/ASTWriterStmt.cpp

Modified: cfe/trunk/include/clang/AST/Expr.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Expr.h?rev=129896&r1=129895&r2=129896&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Expr.h (original)
+++ cfe/trunk/include/clang/AST/Expr.h Wed Apr 20 19:27:41 2011
@@ -3178,9 +3178,14 @@
   /// written in the source code.
   InitListExpr *SyntacticForm;
 
-  /// If this initializer list initializes a union, specifies which
-  /// field within the union will be initialized.
-  FieldDecl *UnionFieldInit;
+  /// \brief Either:
+  ///  If this initializer list initializes an array with more elements than
+  ///  there are initializers in the list, specifies an expression to be used
+  ///  for value initialization of the rest of the elements.
+  /// Or
+  ///  If this initializer list initializes a union, specifies which
+  ///  field within the union will be initialized.
+  llvm::PointerUnion<Expr *, FieldDecl *> ArrayFillerOrUnionFieldInit;
 
   /// Whether this initializer list originally had a GNU array-range
   /// designator in it. This is a temporary marker used by CodeGen.
@@ -3235,14 +3240,28 @@
   /// accommodate the new entry.
   Expr *updateInit(ASTContext &C, unsigned Init, Expr *expr);
 
+  /// \brief If this initializer list initializes an array with more elements
+  /// than there are initializers in the list, specifies an expression to be
+  /// used for value initialization of the rest of the elements.
+  Expr *getArrayFiller() {
+    return ArrayFillerOrUnionFieldInit.dyn_cast<Expr *>();
+  }
+  void setArrayFiller(Expr *filler) {
+    ArrayFillerOrUnionFieldInit = filler;
+  }
+
   /// \brief If this initializes a union, specifies which field in the
   /// union to initialize.
   ///
   /// Typically, this field is the first named field within the
   /// union. However, a designated initializer can specify the
   /// initialization of a different field within the union.
-  FieldDecl *getInitializedFieldInUnion() { return UnionFieldInit; }
-  void setInitializedFieldInUnion(FieldDecl *FD) { UnionFieldInit = FD; }
+  FieldDecl *getInitializedFieldInUnion() {
+    return ArrayFillerOrUnionFieldInit.dyn_cast<FieldDecl *>();
+  }
+  void setInitializedFieldInUnion(FieldDecl *FD) {
+    ArrayFillerOrUnionFieldInit = FD;
+  }
 
   // Explicit InitListExpr's originate from source code (and have valid source
   // locations). Implicit InitListExpr's are created by the semantic analyzer.
@@ -3293,6 +3312,9 @@
   const_reverse_iterator rbegin() const { return InitExprs.rbegin(); }
   reverse_iterator rend() { return InitExprs.rend(); }
   const_reverse_iterator rend() const { return InitExprs.rend(); }
+
+  friend class ASTStmtReader;
+  friend class ASTStmtWriter;
 };
 
 /// @brief Represents a C99 designated initializer expression.

Modified: cfe/trunk/lib/AST/Expr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Expr.cpp?rev=129896&r1=129895&r2=129896&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Expr.cpp (original)
+++ cfe/trunk/lib/AST/Expr.cpp Wed Apr 20 19:27:41 2011
@@ -1254,7 +1254,7 @@
          false),
     InitExprs(C, numInits),
     LBraceLoc(lbraceloc), RBraceLoc(rbraceloc), SyntacticForm(0),
-    UnionFieldInit(0), HadArrayRangeDesignator(false) 
+    HadArrayRangeDesignator(false) 
 {      
   for (unsigned I = 0; I != numInits; ++I) {
     if (initExprs[I]->isTypeDependent())

Modified: cfe/trunk/lib/AST/ExprConstant.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=129896&r1=129895&r2=129896&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprConstant.cpp (original)
+++ cfe/trunk/lib/AST/ExprConstant.cpp Wed Apr 20 19:27:41 2011
@@ -319,6 +319,8 @@
   bool VisitInitListExpr(InitListExpr *E) {
     for (unsigned i = 0, e = E->getNumInits(); i != e; ++i)
       if (Visit(E->getInit(i))) return true;
+    if (Expr *filler = E->getArrayFiller())
+      return Visit(filler);
     return false;
   }
     

Modified: cfe/trunk/lib/CodeGen/CGExprAgg.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprAgg.cpp?rev=129896&r1=129895&r2=129896&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprAgg.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprAgg.cpp Wed Apr 20 19:27:41 2011
@@ -641,6 +641,8 @@
       
       if (i < NumInitElements)
         EmitInitializationToLValue(E->getInit(i), LV, ElementType);
+      else if (Expr *filler = E->getArrayFiller())
+        EmitInitializationToLValue(filler, LV, ElementType);
       else
         EmitNullInitializationToLValue(LV, ElementType);
       

Modified: cfe/trunk/lib/CodeGen/CGExprConstant.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprConstant.cpp?rev=129896&r1=129895&r2=129896&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprConstant.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprConstant.cpp Wed Apr 20 19:27:41 2011
@@ -667,8 +667,16 @@
 
     // Initialize remaining array elements.
     // FIXME: This doesn't handle member pointers correctly!
+    llvm::Constant *fillC;
+    if (Expr *filler = ILE->getArrayFiller())
+      fillC = CGM.EmitConstantExpr(filler, filler->getType(), CGF);
+    else
+      fillC = llvm::Constant::getNullValue(ElemTy);
+    if (!fillC)
+      return 0;
+    RewriteType |= (fillC->getType() != ElemTy);
     for (; i < NumElements; ++i)
-      Elts.push_back(llvm::Constant::getNullValue(ElemTy));
+      Elts.push_back(fillC);
 
     if (RewriteType) {
       // FIXME: Try to avoid packing the array

Modified: cfe/trunk/lib/Sema/SemaInit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=129896&r1=129895&r2=129896&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaInit.cpp (original)
+++ cfe/trunk/lib/Sema/SemaInit.cpp Wed Apr 20 19:27:41 2011
@@ -405,14 +405,23 @@
         // Do nothing
       } else if (Init < NumInits) {
         ILE->setInit(Init, ElementInit.takeAs<Expr>());
-      } else if (InitSeq.getKind()
+      } else {
+        // For arrays, just set the expression used for value-initialization
+        // of the rest of elements and exit.
+        if (ElementEntity.getKind() == InitializedEntity::EK_ArrayElement) {
+          ILE->setArrayFiller(ElementInit.takeAs<Expr>());
+          return;
+        }
+
+        if (InitSeq.getKind()
                    == InitializationSequence::ConstructorInitialization) {
-        // Value-initialization requires a constructor call, so
-        // extend the initializer list to include the constructor
-        // call and make a note that we'll need to take another pass
-        // through the initializer list.
-        ILE->updateInit(SemaRef.Context, Init, ElementInit.takeAs<Expr>());
-        RequiresSecondPass = true;
+          // Value-initialization requires a constructor call, so
+          // extend the initializer list to include the constructor
+          // call and make a note that we'll need to take another pass
+          // through the initializer list.
+          ILE->updateInit(SemaRef.Context, Init, ElementInit.takeAs<Expr>());
+          RequiresSecondPass = true;
+        }
       }
     } else if (InitListExpr *InnerILE
                  = dyn_cast<InitListExpr>(ILE->getInit(Init)))

Modified: cfe/trunk/lib/Serialization/ASTReaderStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderStmt.cpp?rev=129896&r1=129895&r2=129896&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReaderStmt.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReaderStmt.cpp Wed Apr 20 19:27:41 2011
@@ -690,8 +690,11 @@
   E->setSyntacticForm(cast_or_null<InitListExpr>(Reader.ReadSubStmt()));
   E->setLBraceLoc(ReadSourceLocation(Record, Idx));
   E->setRBraceLoc(ReadSourceLocation(Record, Idx));
-  E->setInitializedFieldInUnion(
-                      cast_or_null<FieldDecl>(Reader.GetDecl(Record[Idx++])));
+  if (Record[Idx++]) // isArrayFiller
+    E->ArrayFillerOrUnionFieldInit = Reader.ReadSubExpr();
+  else
+    E->ArrayFillerOrUnionFieldInit
+        = cast_or_null<FieldDecl>(Reader.GetDecl(Record[Idx++]));
   E->sawArrayRangeDesignator(Record[Idx++]);
 }
 

Modified: cfe/trunk/lib/Serialization/ASTWriterStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriterStmt.cpp?rev=129896&r1=129895&r2=129896&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTWriterStmt.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTWriterStmt.cpp Wed Apr 20 19:27:41 2011
@@ -673,7 +673,12 @@
   Writer.AddStmt(E->getSyntacticForm());
   Writer.AddSourceLocation(E->getLBraceLoc(), Record);
   Writer.AddSourceLocation(E->getRBraceLoc(), Record);
-  Writer.AddDeclRef(E->getInitializedFieldInUnion(), Record);
+  bool isArrayFiller = E->ArrayFillerOrUnionFieldInit.is<Expr*>();
+  Record.push_back(isArrayFiller);
+  if (isArrayFiller)
+    Writer.AddStmt(E->getArrayFiller());
+  else
+    Writer.AddDeclRef(E->getInitializedFieldInUnion(), Record);
   Record.push_back(E->hadArrayRangeDesignator());
   Code = serialization::EXPR_INIT_LIST;
 }

Added: cfe/trunk/test/Index/initializer-memory.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Index/initializer-memory.cpp?rev=129896&view=auto
==============================================================================
--- cfe/trunk/test/Index/initializer-memory.cpp (added)
+++ cfe/trunk/test/Index/initializer-memory.cpp Wed Apr 20 19:27:41 2011
@@ -0,0 +1,14 @@
+// RUN: c-index-test -test-load-source-memory-usage none %s 2>&1 | FileCheck %s
+
+// rdar://9275920 - We would create millions of Exprs to fill out the initializer.
+
+double data[1000000] = {0};
+
+struct S {
+ S(int);
+ S();
+};
+
+S data2[1000000] = {0};
+
+// CHECK: TOTAL = {{.*}} (0.{{.*}} MBytes)





More information about the cfe-commits mailing list