1/* Copyright (C) 2003 Vladimir Roubtsov. All rights reserved. 2 * 3 * This program and the accompanying materials are made available under 4 * the terms of the Common Public License v1.0 which accompanies this distribution, 5 * and is available at http://www.eclipse.org/legal/cpl-v10.html 6 * 7 * $Id: InstrClassLoadHook.java,v 1.1.1.1 2004/05/09 16:57:44 vlad_r Exp $ 8 */ 9package com.vladium.emma.rt; 10 11import java.io.IOException; 12 13import com.vladium.jcd.cls.ClassDef; 14import com.vladium.jcd.compiler.ClassWriter; 15import com.vladium.jcd.parser.ClassDefParser; 16import com.vladium.util.ByteArrayOStream; 17import com.vladium.util.Descriptors; 18import com.vladium.util.asserts.$assert; 19import com.vladium.emma.filter.IInclExclFilter; 20import com.vladium.emma.instr.InstrVisitor; 21import com.vladium.emma.data.CoverageOptions; 22import com.vladium.emma.data.IMetaData; 23 24// ---------------------------------------------------------------------------- 25/** 26 * MT-safety ensured by the containing loader 27 * 28 * @author Vlad Roubtsov, (C) 2003 29 */ 30public 31final class InstrClassLoadHook implements IClassLoadHook 32{ 33 // public: ................................................................ 34 35 /** 36 * @param filter [can be null] 37 */ 38 public InstrClassLoadHook (final IInclExclFilter filter, final IMetaData mdata) 39 { 40 if (mdata == null) throw new IllegalArgumentException ("null input: mdata"); 41 42 m_filter = filter; // can be null 43 m_metadata = mdata; 44 45 // important to use the same options as the metadata may have been populated earlier: 46 final CoverageOptions options = mdata.getOptions (); 47 m_classDefProcessor = new InstrVisitor (options); 48 49 m_instrResult = new InstrVisitor.InstrResult (); 50 } 51 52 53 public boolean processClassDef (final String className, 54 final byte [] bytes, final int length, 55 ByteArrayOStream out) 56 throws IOException 57 { 58 if ($assert.ENABLED) 59 { 60 $assert.ASSERT (className != null, "className is null"); 61 $assert.ASSERT (bytes != null, "bytes is null"); 62 $assert.ASSERT (bytes != null, "out is null"); 63 } 64 65 final IInclExclFilter filter = m_filter; 66 if ((filter == null) || filter.included (className)) 67 { 68 final ClassDef clsDef = ClassDefParser.parseClass (bytes, length); 69 final String classVMName = Descriptors.javaNameToVMName (className); 70 71 final Object lock = m_metadata.lock (); 72 73 final boolean metadataExists; 74 synchronized (lock) 75 { 76 metadataExists = m_metadata.hasDescriptor (classVMName); 77 } 78 79 // since this is the first [and only] time the parent loader is 80 // loading the class in question, if metadata for 'className' exists 81 // it means it was created during the app runner's classpath scan -- 82 // do not overwrite it (the class def should be the same) 83 84 // [this picture breaks down if the design changes so that the same 85 // metadata instance could be associated with more than one app loader] 86 87 m_classDefProcessor.process (clsDef, false, true, ! metadataExists, m_instrResult); 88 89 boolean useOurs = m_instrResult.m_instrumented; 90 91 if (m_instrResult.m_descriptor != null) // null means either the metadata existed already or the class is an interface 92 { 93 // try to update metadata [this supports the "no initial full cp 94 // scan mode" in the app runner and also ensures that we pick up 95 // any dynamically generated classes to support (hacky) apps that 96 // do dynamic source generation/compilation]: 97 98 synchronized (lock) 99 { 100 // do not force overwrites of existing descriptors to support 101 // correct handling of race conditions: if another thread 102 // updates the metadata first, discard our version of the class def 103 104 // [actually, this guard is redundant here because 105 // right now the hook can only have a single classloader parent 106 // and the parent's loadClass() is a critical section] 107 108 if (! m_metadata.add (m_instrResult.m_descriptor, false)) 109 useOurs = false; 110 } 111 } 112 113 if (useOurs) 114 { 115 ClassWriter.writeClassTable (clsDef, out); 116 return true; 117 } 118 } 119 120 return false; 121 } 122 123 // protected: ............................................................. 124 125 // package: ............................................................... 126 127 // private: ............................................................... 128 129 130 private final IInclExclFilter m_filter; // can be null [equivalent to no filtering] 131 private final IMetaData m_metadata; // never null 132 private final InstrVisitor m_classDefProcessor; // never null 133 private final InstrVisitor.InstrResult m_instrResult; 134 135} // end of class 136// ----------------------------------------------------------------------------