FileDocCategorySizeDatePackage
InstrClassLoadHook.javaAPI DocAndroid 1.5 API5530Wed May 06 22:41:16 BST 2009com.vladium.emma.rt

InstrClassLoadHook

public final class InstrClassLoadHook extends Object implements IClassLoadHook
MT-safety ensured by the containing loader
author
Vlad Roubtsov, (C) 2003

Fields Summary
private final com.vladium.emma.filter.IInclExclFilter
m_filter
private final com.vladium.emma.data.IMetaData
m_metadata
private final com.vladium.emma.instr.InstrVisitor
m_classDefProcessor
private final InstrVisitor.InstrResult
m_instrResult
Constructors Summary
public InstrClassLoadHook(com.vladium.emma.filter.IInclExclFilter filter, com.vladium.emma.data.IMetaData mdata)

param
filter [can be null]

        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 ();
    
Methods Summary
public booleanprocessClassDef(java.lang.String className, byte[] bytes, int length, com.vladium.util.ByteArrayOStream out)

        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;