File: InstrClassLoadHook.java

package info (click to toggle)
emma-coverage 2.0.5312%2Bdfsg-4
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd, stretch, wheezy
  • size: 2,000 kB
  • ctags: 3,667
  • sloc: java: 23,109; xml: 414; makefile: 22
file content (136 lines) | stat: -rw-r--r-- 5,665 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
/* Copyright (C) 2003 Vladimir Roubtsov. All rights reserved.
 * 
 * This program and the accompanying materials are made available under
 * the terms of the Common Public License v1.0 which accompanies this distribution,
 * and is available at http://www.eclipse.org/legal/cpl-v10.html
 * 
 * $Id: InstrClassLoadHook.java,v 1.1.1.1 2004/05/09 16:57:44 vlad_r Exp $
 */
package com.vladium.emma.rt;

import java.io.IOException;

import com.vladium.jcd.cls.ClassDef;
import com.vladium.jcd.compiler.ClassWriter;
import com.vladium.jcd.parser.ClassDefParser;
import com.vladium.util.ByteArrayOStream;
import com.vladium.util.Descriptors;
import com.vladium.util.asserts.$assert;
import com.vladium.emma.filter.IInclExclFilter;
import com.vladium.emma.instr.InstrVisitor;
import com.vladium.emma.data.CoverageOptions;
import com.vladium.emma.data.IMetaData;

// ----------------------------------------------------------------------------
/**
 * MT-safety ensured by the containing loader
 * 
 * @author Vlad Roubtsov, (C) 2003
 */
public
final class InstrClassLoadHook implements IClassLoadHook
{
    // public: ................................................................
    
    /**
     * @param filter [can be null]
     */
    public InstrClassLoadHook (final IInclExclFilter filter, final IMetaData mdata)
    {
        if (mdata == null) throw new IllegalArgumentException ("null input: mdata");
        
        m_filter = filter; // can be null 
        m_metadata = mdata;
        
        // important to use the same options as the metadata may have been populated earlier:
        final CoverageOptions options = mdata.getOptions ();
        m_classDefProcessor = new InstrVisitor (options);
        
        m_instrResult = new InstrVisitor.InstrResult ();
    }
    
        
    public boolean processClassDef (final String className,
                                    final byte [] bytes, final int length,
                                    ByteArrayOStream out)
        throws IOException
    {
        if ($assert.ENABLED)
        {
            $assert.ASSERT (className != null, "className is null");
            $assert.ASSERT (bytes != null, "bytes is null");
            $assert.ASSERT (bytes != null, "out is null");
        }
        
        final IInclExclFilter filter = m_filter;
        if ((filter == null) || filter.included (className))
        {
            final ClassDef clsDef = ClassDefParser.parseClass (bytes, length);
            final String classVMName = Descriptors.javaNameToVMName (className);
            
            final Object lock = m_metadata.lock ();
            
            final boolean metadataExists;
            synchronized (lock)
            {
                metadataExists = m_metadata.hasDescriptor (classVMName);
            }
            
            // since this is the first [and only] time the parent loader is
            // loading the class in question, if metadata for 'className' exists
            // it means it was created during the app runner's classpath scan --
            // do not overwrite it (the class def should be the same)
            
            // [this picture breaks down if the design changes so that the same
            // metadata instance could be associated with more than one app loader]
            
            m_classDefProcessor.process (clsDef, false, true, ! metadataExists, m_instrResult);
            
            boolean useOurs = m_instrResult.m_instrumented;
            
            if (m_instrResult.m_descriptor != null) // null means either the metadata existed already or the class is an interface
            {
                // try to update metadata [this supports the "no initial full cp
                // scan mode" in the app runner and also ensures that we pick up
                // any dynamically generated classes to support (hacky) apps that
                // do dynamic source generation/compilation]:
                
                synchronized (lock)
                {
                    // do not force overwrites of existing descriptors to support
                    // correct handling of race conditions: if another thread
                    // updates the metadata first, discard our version of the class def
                    
                    // [actually, this guard is redundant here because
                    // right now the hook can only have a single classloader parent
                    // and the parent's loadClass() is a critical section]
                    
                    if (! m_metadata.add (m_instrResult.m_descriptor, false))
                         useOurs = false; 
                }
            }
            
            if (useOurs)
            {                        
                ClassWriter.writeClassTable (clsDef, out);
                return true;
            }
        }

        return false;
    }
    
    // protected: .............................................................

    // package: ...............................................................
    
    // private: ...............................................................
    
    
    private final IInclExclFilter m_filter; // can be null [equivalent to no filtering]
    private final IMetaData m_metadata; // never null
    private final InstrVisitor m_classDefProcessor; // never null
    private final InstrVisitor.InstrResult m_instrResult;

} // end of class
// ----------------------------------------------------------------------------