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.ClassInfo;
044: import org.netbeans.lib.profiler.classfile.ClassRepository;
045: import org.netbeans.lib.profiler.classfile.ClassRepository.CodeRegionBCI;
046: import org.netbeans.lib.profiler.classfile.DynamicClassInfo;
047: import org.netbeans.lib.profiler.client.ClientUtils;
048: import org.netbeans.lib.profiler.client.ClientUtils.SourceCodeSelection;
049: import org.netbeans.lib.profiler.global.ProfilingSessionStatus;
050: import org.netbeans.lib.profiler.utils.MiscUtils;
051: import java.io.IOException;
052: import java.util.ArrayList;
053:
054: /**
055: * High-level access to functionality that instruments a (so far single) code region in a (single again) TA method.
056: *
057: * @author Tomas Hurka
058: * @author Misha Dmitriev
059: * @author Ian Formanek
060: */
061: public class CodeRegionMethodInstrumentor extends ClassManager {
062: //~ Instance fields ----------------------------------------------------------------------------------------------------------
063:
064: private ClientUtils.SourceCodeSelection sourceCodeSelection;
065: private ArrayList instrClasses;
066: private String className;
067: private int methodIdx;
068: private int nInstrClasses;
069:
070: //~ Constructors -------------------------------------------------------------------------------------------------------------
071:
072: public CodeRegionMethodInstrumentor(ProfilingSessionStatus status,
073: SourceCodeSelection codeSelection) {
074: super (status);
075: sourceCodeSelection = codeSelection;
076: className = sourceCodeSelection.getClassName()
077: .replace('.', '/').intern(); // NOI18N
078: instrClasses = new ArrayList();
079: }
080:
081: //~ Methods ------------------------------------------------------------------------------------------------------------------
082:
083: public Object[] getFollowUpInstrumentCodeRegionResponse(
084: int classLoaderId) {
085: DynamicClassInfo clazz = javaClassForName(className,
086: classLoaderId);
087:
088: instrClasses.clear();
089: instrClasses.add(clazz);
090: nInstrClasses = 1;
091:
092: return createInstrumentedMethodPack();
093: }
094:
095: protected Object[] createInstrumentedMethodPack() {
096: if (nInstrClasses == 0) {
097: return null;
098: }
099:
100: if (status.targetJDKVersionString.equals(JDK_15_STRING)) {
101: return createInstrumentedMethodPack15();
102: } else if (status.targetJDKVersionString.equals(JDK_16_STRING)) {
103: // for both 1.5 and 1.6 we use 15-style instrumentation
104: return createInstrumentedMethodPack15();
105: } else if (status.targetJDKVersionString.equals(JDK_17_STRING)) {
106: // for 1.7 we use 15-style instrumentation
107: return createInstrumentedMethodPack15();
108: } else {
109: throw new InternalError("Unsupported JDK version"); // NOI18N
110: }
111: }
112:
113: Object[] getInitialInstrumentCodeRegionResponse(
114: String[] loadedClasses, int[] loadedClassLoaderIds) {
115: DynamicClassInfo clazz = null;
116:
117: // We may have more than one version of the class with the given name, hence this search and instrClasses array
118: for (int i = 0; i < loadedClasses.length; i++) {
119: String loadedClassName = loadedClasses[i].replace('.', '/')
120: .intern(); // NOI18N
121:
122: if (className == loadedClassName) {
123: clazz = javaClassForName(loadedClasses[i],
124: loadedClassLoaderIds[i]);
125:
126: if (clazz != null) {
127: CodeRegionBCI instrLocation = computeCodeRegionFromSourceCodeSelection(clazz);
128:
129: if (instrLocation != null) {
130: int mIdx = clazz.getMethodIndex(
131: instrLocation.methodName,
132: instrLocation.methodSignature);
133:
134: if (mIdx != -1) { // Not all class versions may have this method
135: clazz.setLoaded(true);
136: instrClasses.add(clazz);
137: }
138: }
139: }
140: }
141: }
142:
143: nInstrClasses = instrClasses.size();
144:
145: return createInstrumentedMethodPack();
146: }
147:
148: private CodeRegionBCI computeCodeRegionFromSourceCodeSelection(
149: ClassInfo clazz) {
150: try {
151: if (sourceCodeSelection.definedViaSourceLines()) {
152: int startLine = sourceCodeSelection.getStartLine();
153: int endLine = sourceCodeSelection.getEndLine();
154: CodeRegionBCI loc = ClassRepository
155: .getMethodForSourceRegion(clazz, startLine,
156: endLine);
157:
158: status.beginTrans(true);
159:
160: try {
161: status
162: .setInstrMethodNames(new String[] { loc.methodName });
163: status
164: .setInstrMethodSignatures(new String[] { loc.methodSignature });
165: } finally {
166: status.endTrans();
167: }
168:
169: return loc;
170: } else if (sourceCodeSelection.definedViaMethodName()) {
171: String methodName = sourceCodeSelection.getMethodName();
172: String methodSignature = sourceCodeSelection
173: .getMethodSignature();
174:
175: return ClassRepository.getMethodMinAndMaxBCI(clazz,
176: methodName, methodSignature);
177: }
178: } catch (IOException ex) {
179: MiscUtils.printErrorMessage(ex.getMessage());
180: } catch (BadLocationException ex) {
181: MiscUtils.printErrorMessage(ex.getMessage());
182: } catch (ClassNotFoundException ex) {
183: MiscUtils.printErrorMessage(ex.getMessage());
184: }
185:
186: return null;
187: }
188:
189: /** Creates the 1.5-style array of instrumented class files. */
190: private Object[] createInstrumentedMethodPack15() {
191: String[] instrMethodClasses = new String[nInstrClasses];
192: int[] instrClassLoaderIds = new int[nInstrClasses];
193: byte[][] replacementClassFileBytes = new byte[nInstrClasses][];
194:
195: for (int j = 0; j < nInstrClasses; j++) {
196: DynamicClassInfo clazz = (DynamicClassInfo) instrClasses
197: .get(j);
198: instrMethodClasses[j] = clazz.getName().replace('/', '.'); // NOI18N
199: instrClassLoaderIds[j] = clazz.getLoaderId();
200:
201: CodeRegionBCI instrLocation = computeCodeRegionFromSourceCodeSelection(clazz);
202: int mIdx = clazz.getMethodIndex(instrLocation.methodName,
203: instrLocation.methodSignature); // TODO CHECK: local variable hides member variable
204: clazz.setMethodInstrumented(mIdx);
205:
206: DynamicConstantPoolExtension ecp = DynamicConstantPoolExtension
207: .getCPFragment(clazz, INJ_CODE_REGION);
208: byte[] newMethodInfo = InstrumentationFactory
209: .instrumentCodeRegion(clazz, mIdx,
210: instrLocation.bci0, instrLocation.bci1);
211:
212: int nMethods = clazz.getMethodNames().length;
213: byte[][] replacementMethodInfos = new byte[nMethods][];
214:
215: for (int i = 0; i < nMethods; i++) {
216: replacementMethodInfos[i] = clazz.getMethodInfo(i);
217: }
218:
219: replacementMethodInfos[mIdx] = newMethodInfo;
220:
221: int nAddedCPEntries = ecp.getNEntries();
222: byte[] addedCPContents = ecp.getContents();
223: replacementClassFileBytes[j] = ClassRewriter
224: .rewriteClassFile(clazz, replacementMethodInfos,
225: nAddedCPEntries, addedCPContents);
226: }
227:
228: return new Object[] { instrMethodClasses, instrClassLoaderIds,
229: replacementClassFileBytes };
230: }
231: }
|