Limitation w/Multiple Static Initialization

Developers
2011-12-24
2013-05-09
  • Boyd Bischke

    Boyd Bischke - 2011-12-24

    Greeting,

    I'm a big fan of EMMA.  I did find one issue that's causing be problems.

    My application is using Spring.  When Spring is using CGLib subclassing for AOP, it's causing static initialization multiple times.  However, the consequence is that only coverage for the most recent initialization is getting captured.  This is causing coverage data to come up missing.

    I hacked together a solution that seems to fix my problems, but I was hoping this could be integrated as a supported solution in a way that is consistent with the EMMA code.

    Here's what I did:
    -Change ICoverageData$DataHolder.m_coverage to a three dimensional array to support data for multiple initializations.
    -Change CoverageData.addClass to first check if the class already exists, and if so add another array to ICoverageData$DataHolder.m_coverage.
    -Change CoverageData.reset to reset the entire three dimensional array.
    -Add a new method to ICoverageData$DataHolder to provide a deep copy of a "combined" result that is 2 dimensional.
    -Change all "read" references from ICoverageData$DataHolder.m_coverage to ICoverageData$DataHolder.<new method>.

    Thanks.

    Boyd

     
  • Marc R. Hoffmann

    Hi,

    this is one of the problems that leads me to develop a new code coverage library (JaCoCo) based on the great ideas of EMMA. We followed a slightly different approach: The static initializer does not create its own probe array but requests an instance from the runtime. This allows to share the same probe instance for all "reincarnations" of the same class.

    -marc (another big EMMA fan)

     
  • Boyd Bischke

    Boyd Bischke - 2011-12-26

    I'll check it out, thanks.

    Following are the changes I made.  Not implying it's the "best" approach, more like the least invasive.

    *** emma_orig/core/java12/com/vladium/emma/data/CoverageData.java 2011-12-25 23:43:02.117521000 -0700
    -- emma/core/java12/com/vladium/emma/data/CoverageData.java 2011-12-25 22:41:22.052558800 -0700
    ***************
    *** 76,82 ****
         
          public void addClass (final boolean  coverage, final String classVMName, final long stamp)
          {
    !         m_coverageMap.put (classVMName, new DataHolder (coverage, stamp));
          }
         
          public void reset ()
    -- 76,89 ---
         
          public void addClass (final boolean  coverage, final String classVMName, final long stamp)
          {
    !     DataHolder h = (DataHolder)m_coverageMap.get(classVMName);
    !     if(h == null) {
    !     h = new DataHolder (coverage, stamp);
    !             m_coverageMap.put (classVMName, h);
    !     } else {
    !     h.add(coverage);
    !     }
    !    
          }
         
          public void reset ()
    ***************
    *** 85,100 ****
              {
                  final DataHolder data = (DataHolder) entries.next ();
                 
    !             final boolean  coverage = data.m_coverage;
    !             for (int m = 0, mLimit = coverage.length; m < mLimit; ++ m)
                  {
    !                 final boolean  mcoverage = coverage ;
    !                 if (mcoverage == null) continue;
    !                
    !                 for (int b = 0, bLimit = mcoverage.length; b < bLimit; ++ b)
    !                 {
    !                     mcoverage ** = false;
    !                 }
                  }
              }
          }
    -- 92,111 ---
              {
                  final DataHolder data = (DataHolder) entries.next ();
                 
    !             final boolean  coverage = data.m_coverage;
    !             for (int o = 0, oLimit = coverage.length; o < oLimit; ++ o)
                  {
    !             final boolean  ocoverage = coverage ;
    !             for (int m = 0, mLimit = ocoverage.length; m < mLimit; ++ m)
    !             {
    !                 final boolean  mcoverage = ocoverage ;
    !                 if (mcoverage == null) continue;
    !                
    !                 for (int b = 0, bLimit = mcoverage.length; b < bLimit; ++ b)
    !                 {
    !                     mcoverage  = false;
    !                 }
    !             }
                  }
              }
          }
    ***************
    *** 139,146 ****
                              m_coverageMap.put (classVMName, rhsdata);
                          else // merge two runtime profiles
                          {
    !                         final boolean  rhscoverage = rhsdata.m_coverage;
    !                         final boolean  coverage = data.m_coverage;
                             
                              //
                         
    -- 150,157 ---
                              m_coverageMap.put (classVMName, rhsdata);
                          else // merge two runtime profiles
                          {
    !                         final boolean  rhscoverage = rhsdata.combined();
    !                         final boolean  coverage = data.combined();
                             
                              //
                         
    ***************
    *** 228,234 ****
                  final String classVMName = (String) entry.getKey ();
                  final DataHolder data = (DataHolder) entry.getValue ();
                 
    !             final boolean  coverage = data.m_coverage;
                 
                  out.writeUTF (classVMName);
                  out.writeLong (data.m_stamp);
    -- 239,245 ---
                  final String classVMName = (String) entry.getKey ();
                  final DataHolder data = (DataHolder) entry.getValue ();
                 
    !             final boolean  coverage = data.combined();
                 
                  out.writeUTF (classVMName);
                  out.writeLong (data.m_stamp);
    *** emma_orig/core/java12/com/vladium/emma/data/ICoverageData.java 2011-12-25 23:43:02.177581000 -0700
    -- emma/core/java12/com/vladium/emma/data/ICoverageData.java 2011-12-25 22:50:40.544033700 -0700
    ***************
    *** 8,13 ****
    -- 8,14 ---
       */
      package com.vladium.emma.data;
     
    +
      // ---------------------------------------------------
      /**
       * @author Vlad Roubtsov, (C) 2003
    ***************
    *** 21,33 ****
          {
              public DataHolder (final boolean  coverage, final long stamp)
              {
    !             m_coverage = coverage;
                  m_stamp = stamp;
              }
             
    !         public final boolean  m_coverage;
              public final long m_stamp;
             
          } // end of nested class
         
          Object lock ();
    -- 22,76 ---
          {
              public DataHolder (final boolean  coverage, final long stamp)
              {
    !             m_coverage = new boolean {coverage};
                  m_stamp = stamp;
              }
             
    !         public boolean  m_coverage;
              public final long m_stamp;
             
    +         public void add(boolean  coverage) {
    +         boolean  n = new boolean ;
    +         for(int i = 0; i < m_coverage.length; i++) {
    +         n_ = m_coverage;
    +         }
    +         n = coverage;
    +         m_coverage = n;
    +         }
    +        
    +         public boolean  combined() {
    +         flatten();
    +         return m_coverage;
    +         }
    +        
    +         private void flatten() {
    +         if(m_coverage != null && m_coverage.length > 0) {
    +         // merge 1-n up to 0
    +         for(int i = 1; i < m_coverage.length; i++) {
    +         for(int j = 0; j < m_coverage.length; j++) {
    +         if(m_coverage != null) {
    +         for(int k = 0; k < m_coverage.length; k++) {
    +         m_coverage = m_coverage || m_coverage;
    +                 }
    +         }
    +             }
    +         }
    +         // merge 0 to all others
    +             for(int i = 1; i < m_coverage.length; i++) {
    +         for(int j = 0; j < m_coverage.length; j++) {
    +         if(m_coverage != null) {
    +         if(m_coverage == null) {
    +         m_coverage = new boolean[m_coverage.length];
    +         }
    +             for(int k = 0; k < m_coverage.length; k++) {
    +             m_coverage = m_coverage;
    +                     }
    +         }
    +             }
    +         }
    +         }
    +         }
    +        
          } // end of nested class
         
          Object lock ();
    *** emma_orig/core/java12/com/vladium/emma/report/ReportDataModel.java 2011-12-25 23:43:04.010412000 -0700
    -- emma/core/java12/com/vladium/emma/report/ReportDataModel.java 2011-12-25 22:41:22.165081300 -0700
    ***************
    *** 96,102 ****
                                                              new Object  { Descriptors.vmNameToJavaName (cls.getClassVMName ()) });
                      }
                     
    !                 final boolean  coverage = data != null ? data.m_coverage : null;
                     
                      if ($assert.ENABLED) $assert.ASSERT (! srcView || srcfileItem != null, "null srcfileItem");
                     
    -- 96,102 ---
                                                              new Object  { Descriptors.vmNameToJavaName (cls.getClassVMName ()) });
                      }
                     
    !                 final boolean  coverage = data != null ? data.combined() : null;
                     
                      if ($assert.ENABLED) $assert.ASSERT (! srcView || srcfileItem != null, "null srcfileItem");
                     

    _**

     

Log in to post a comment.