InstrClassLoadHookpublic final class InstrClassLoadHook extends Object implements IClassLoadHookMT-safety ensured by the containing loader |
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)
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 boolean | processClassDef(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;
|
|