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.global.CommonConstants;
045:
046: /**
047: * Specialized subclass of Injector, that provides injection of our standard Code Region instrumentation -
048: * codeRegionEntry() and codeRegionExit() calls - in appropriate places.
049: *
050: * @author Misha Dmitriev
051: */
052: class CodeRegionEntryExitCallsInjector extends Injector implements
053: CommonConstants {
054: //~ Static fields/initializers -----------------------------------------------------------------------------------------------
055:
056: // Stuff used for codeRegionEntry() and codeRegionExit() injection
057: protected static byte[] injectedCode;
058: protected static int injectedCodeLen;
059: protected static int injectedCodeMethodIdxPos;
060:
061: static {
062: initializeInjectedCode();
063: }
064:
065: //~ Instance fields ----------------------------------------------------------------------------------------------------------
066:
067: protected int bci0; // Original code region bounds
068: protected int bci1; // Original code region bounds
069:
070: //~ Constructors -------------------------------------------------------------------------------------------------------------
071:
072: CodeRegionEntryExitCallsInjector(ClassInfo clazz,
073: int baseCPoolCount, int methodIdx, int bci0, int bci1) {
074: super (clazz, methodIdx);
075: this .baseCPoolCount = baseCPoolCount;
076: this .bci0 = bci0;
077: this .bci1 = bci1;
078: }
079:
080: //~ Methods ------------------------------------------------------------------------------------------------------------------
081:
082: public byte[] instrumentMethod() {
083: // Determine the index (among return instructions) of first return within the given code region, total number of returns between
084: // bci = 0 and bci1, and the original index of the last instruction within this region.
085: int firstRetIdx = -1;
086: int totalReturns = 0;
087: int lastInstrIdx = -1;
088: int bci = 0;
089:
090: while (bci <= bci1) {
091: int bc = bytecodes[bci] & 0xFF;
092: lastInstrIdx++;
093:
094: if ((bc >= opc_ireturn) && (bc <= opc_return)) {
095: if ((bci >= bci0) && (firstRetIdx == -1)) {
096: firstRetIdx = totalReturns;
097: }
098:
099: totalReturns++;
100: }
101:
102: bci += opcodeLength(bci);
103: }
104:
105: injectCodeRegionEntry();
106: lastInstrIdx += 2; // Since we added two opcodes in the above operation
107: injectCodeRegionExits(firstRetIdx, totalReturns, lastInstrIdx);
108:
109: return createPackedMethodInfo();
110: }
111:
112: private static void initializeInjectedCode() {
113: // Code packet for codeRegionEntry()/codeRegionExit()
114: injectedCodeLen = 4;
115: injectedCode = new byte[injectedCodeLen];
116: injectedCode[0] = (byte) opc_invokestatic;
117: // Positions 1, 2 are occupied by method index
118: injectedCodeMethodIdxPos = 1;
119: injectedCode[3] = (byte) opc_nop;
120: }
121:
122: private void injectCodeRegionEntry() {
123: int targetMethodIdx = CPExtensionsRepository.codeRegionContents_CodeRegionEntryMethodIdx
124: + baseCPoolCount;
125: putU2(injectedCode, injectedCodeMethodIdxPos, targetMethodIdx);
126:
127: injectCodeAndRewrite(injectedCode, injectedCodeLen, bci0, true);
128: }
129:
130: private void injectCodeRegionExits(int firstRetIdx,
131: int totalReturns, int lastInstrIdx) {
132: // Prepare the codeRegionExit() code packet
133: int targetMethodIdx = CPExtensionsRepository.codeRegionContents_CodeRegionExitMethodIdx
134: + baseCPoolCount;
135: putU2(injectedCode, injectedCodeMethodIdxPos, targetMethodIdx);
136:
137: int curInstrIdx = -1;
138:
139: if (firstRetIdx != -1) { // There is a corner case when a method has no returns at all - e.g. when it contains just a "while (true)" loop
140: // Inject codeRegionExit() before each return inside the selected fragment
141:
142: for (int inFragmentRetIndex = firstRetIdx; inFragmentRetIndex < totalReturns; inFragmentRetIndex++) {
143: int curRetIdx = -1;
144: curInstrIdx = -1;
145:
146: int bci = 0;
147:
148: while (bci < bytecodesLength) {
149: curInstrIdx++;
150:
151: int bc = bytecodes[bci] & 0xFF;
152:
153: if ((bc >= opc_ireturn) && (bc <= opc_return)) {
154: curRetIdx++;
155:
156: if (curRetIdx == inFragmentRetIndex) {
157: injectCodeAndRewrite(injectedCode,
158: injectedCodeLen, bci, true);
159: lastInstrIdx += 2;
160:
161: break;
162: }
163: }
164:
165: bci += opcodeLength(bci);
166: }
167: }
168: }
169:
170: // Inject the call at the last bytecode, which may be anything
171: if (curInstrIdx == lastInstrIdx) {
172: return;
173: }
174:
175: curInstrIdx = -1;
176:
177: int bci = 0;
178:
179: while (bci < bytecodesLength) {
180: curInstrIdx++;
181:
182: if (curInstrIdx >= lastInstrIdx) {
183: injectCodeAndRewrite(injectedCode, injectedCodeLen,
184: bci, true);
185:
186: break;
187: }
188:
189: bci += opcodeLength(bci);
190: }
191: }
192: }
|