001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: * The Original Software is NetBeans. The Initial Developer of the Original
026: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
027: * Microsystems, Inc. All Rights Reserved.
028: *
029: * If you wish your version of this file to be governed by only the CDDL
030: * or only the GPL Version 2, indicate your decision by adding
031: * "[Contributor] elects to include this software in this distribution
032: * under the [CDDL or GPL Version 2] license." If you do not indicate a
033: * single choice of license, a recipient has the option to distribute
034: * your version of this file under either the CDDL, the GPL Version 2 or
035: * to extend the choice of license to its licensees as provided above.
036: * However, if you add GPL Version 2 code and therefore, elected the GPL
037: * Version 2 license, then the option applies only if the new code is
038: * made subject to such option by the copyright holder.
039: */
040:
041: package org.netbeans.lib.profiler.instrumentation;
042:
043: import org.netbeans.lib.profiler.classfile.*;
044: import org.netbeans.lib.profiler.client.RuntimeProfilingPoint;
045: import org.netbeans.lib.profiler.global.CommonConstants;
046: import org.netbeans.lib.profiler.global.ProfilingSessionStatus;
047: import org.netbeans.lib.profiler.utils.MiscUtils;
048: import java.io.IOException;
049: import java.util.*;
050:
051: /**
052: * Basic utility methods used by all scaner classes.
053: *
054: * @author Tomas Hurka
055: * @author Misha Dmitriev
056: */
057: public class ClassManager implements JavaClassConstants,
058: CommonConstants {
059: //~ Static fields/initializers -----------------------------------------------------------------------------------------------
060:
061: private static final RuntimeProfilingPoint[] EMPTY_PROFILEPOINT_ARRAY = new RuntimeProfilingPoint[0];
062:
063: /**
064: * Sorts profiling points by bytecode index so that injector can insert them sequentaly.
065: */
066: private static Comparator ByBciComparator = new Comparator() {
067: public int compare(Object aa, Object bb) {
068: RuntimeProfilingPoint a = (RuntimeProfilingPoint) aa;
069: RuntimeProfilingPoint b = (RuntimeProfilingPoint) bb;
070:
071: return a.getBci() - b.getBci();
072: }
073: };
074:
075: //~ Instance fields ----------------------------------------------------------------------------------------------------------
076:
077: protected ProfilingSessionStatus status;
078:
079: //~ Constructors -------------------------------------------------------------------------------------------------------------
080:
081: protected ClassManager(ProfilingSessionStatus status) {
082: this .status = status;
083: }
084:
085: //~ Methods ------------------------------------------------------------------------------------------------------------------
086:
087: /**
088: * Filters profiling points for given class.
089: *
090: * @param points profiling points to scan
091: * @param classInfo searches for points in this class
092: * @return RuntimeProfilingPoint[] array of profiling points inside the specified method
093: */
094: protected static RuntimeProfilingPoint[] getRuntimeProfilingPoints(
095: RuntimeProfilingPoint[] points, ClassInfo classInfo) {
096: List newPoints = null;
097:
098: String className = classInfo.getName().replace('/', '.'); // NOI18N
099:
100: for (int i = 0; i < points.length; i++) {
101: RuntimeProfilingPoint point = points[i];
102:
103: if (className.equals(point.getClassName())
104: && point.resolve(classInfo)) {
105: if (newPoints == null) {
106: newPoints = new ArrayList(2);
107: }
108:
109: newPoints.add(point);
110: }
111: }
112:
113: if (newPoints == null) {
114: return EMPTY_PROFILEPOINT_ARRAY;
115: }
116:
117: return (RuntimeProfilingPoint[]) newPoints
118: .toArray(new RuntimeProfilingPoint[newPoints.size()]);
119: }
120:
121: /**
122: * Filters profiling points for given method.
123: *
124: * @param points profiling points to scan
125: * @param methodIdx method index in the given class
126: * @return RuntimeProfilingPoint[] array of profiling points inside the specified method
127: */
128: protected static RuntimeProfilingPoint[] getRuntimeProfilingPoints(
129: RuntimeProfilingPoint[] points, int methodIdx) {
130: List newPoints = null;
131:
132: for (int i = 0; i < points.length; i++) {
133: RuntimeProfilingPoint point = points[i];
134:
135: if (point.getMethodIdx() == methodIdx) {
136: if (newPoints == null) {
137: newPoints = new ArrayList(2);
138: }
139:
140: newPoints.add(point);
141: }
142: }
143:
144: if (newPoints == null) {
145: return EMPTY_PROFILEPOINT_ARRAY;
146: } else if (newPoints.size() > 1) {
147: Collections.sort(newPoints, ByBciComparator);
148: }
149:
150: return (RuntimeProfilingPoint[]) newPoints
151: .toArray(new RuntimeProfilingPoint[newPoints.size()]);
152: }
153:
154: /**
155: * Filters profiling points for given class and method.
156: *
157: * @param points profiling points to scan
158: * @param classInfo searches for points in this class
159: * @param methodIdx method index in the given class
160: * @return RuntimeProfilingPoint[] array of profiling points inside the specified method
161: */
162: protected static RuntimeProfilingPoint[] getRuntimeProfilingPoints(
163: RuntimeProfilingPoint[] points, ClassInfo classInfo,
164: int methodIdx) {
165: List newPoints = null;
166: String className = classInfo.getName().replace('/', '.'); // NOI18N
167: className = className.replace('$', '.'); // NOI18N
168:
169: for (int i = 0; i < points.length; i++) {
170: RuntimeProfilingPoint point = points[i];
171:
172: if (className.equals(point.getClassName())) {
173: if (point.resolve(classInfo)) {
174: if (point.getMethodIdx() == methodIdx) {
175: if (newPoints == null) {
176: newPoints = new ArrayList(2);
177: }
178:
179: newPoints.add(point);
180: }
181: }
182: }
183: }
184:
185: if (newPoints == null) {
186: return EMPTY_PROFILEPOINT_ARRAY;
187: } else if (newPoints.size() > 1) {
188: Collections.sort(newPoints, ByBciComparator);
189: }
190:
191: return (RuntimeProfilingPoint[]) newPoints
192: .toArray(new RuntimeProfilingPoint[newPoints.size()]);
193: }
194:
195: /**
196: * Returns a ClassInfo for a given non-array class name. If actualCPLength >= 0 is provided, the constant
197: * pool length in the returned ClassInfo is set to that value. Otherwise it is not touched, i.e. remains
198: * the same as for the .class file on the CLASSPATH.
199: */
200: protected static DynamicClassInfo javaClassForName(
201: String className, int classLoaderId) {
202: try {
203: return ClassRepository
204: .lookupClass(className, classLoaderId);
205: } catch (IOException ex2) {
206: MiscUtils.printWarningMessage("Error reading class "
207: + className); // NOI18N
208: MiscUtils.printWarningMessage(ex2.getMessage());
209: } catch (ClassFormatError er) {
210: MiscUtils.printWarningMessage(er.getMessage());
211: }
212:
213: return null;
214: }
215:
216: protected static BaseClassInfo javaClassForObjectArrayType(
217: String elementTypeName) {
218: BaseClassInfo clazz = ClassRepository.lookupSpecialClass("["
219: + elementTypeName); // NOI18N
220:
221: return clazz;
222: }
223:
224: protected static BaseClassInfo javaClassForPrimitiveArrayType(
225: int arrayTypeId) {
226: BaseClassInfo clazz = ClassRepository
227: .lookupSpecialClass(PRIMITIVE_ARRAY_TYPE_NAMES[arrayTypeId]);
228:
229: return clazz;
230: }
231:
232: /** This is currently used only in memory profiling */
233: protected static BaseClassInfo javaClassOrPlaceholderForName(
234: String className, int classLoaderId) {
235: return ClassRepository.lookupClassOrCreatePlaceholder(
236: className, classLoaderId);
237: }
238:
239: protected static BaseClassInfo loadedJavaClassOrExistingPlaceholderForName(
240: String className, int classLoaderId) {
241: return ClassRepository.lookupLoadedClass(className,
242: classLoaderId, true);
243: }
244:
245: protected static void registerPlaceholder(PlaceholderClassInfo pci) {
246: ClassRepository.addPlaceholder(pci);
247: }
248:
249: protected static void resetLoadedClassData() {
250: ClassRepository.clearCache();
251: }
252:
253: /**
254: * Given a list of classes (normally all classes currently loaded by the JVM), deterime those that are loaded using
255: * custom classloaders, get their cached bytecodes from the JVM, and put them into ClassRepository.
256: */
257: protected static void storeClassFileBytesForCustomLoaderClasses(
258: String[] loadedClasses, int[] loadedClassLoaderIds,
259: byte[][] cachedClassFileBytes) {
260: int nClasses = loadedClasses.length;
261:
262: for (int i = 0; i < nClasses; i++) {
263: if (cachedClassFileBytes[i] != null) {
264: ClassRepository.addVMSuppliedClassFile(
265: loadedClasses[i], loadedClassLoaderIds[i],
266: cachedClassFileBytes[i]);
267: }
268: }
269: }
270: }
|