001: /*
002: * Javassist, a Java-bytecode translator toolkit.
003: * Copyright (C) 1999-2006 Shigeru Chiba. All Rights Reserved.
004: *
005: * The contents of this file are subject to the Mozilla Public License Version
006: * 1.1 (the "License"); you may not use this file except in compliance with
007: * the License. Alternatively, the contents of this file may be used under
008: * the terms of the GNU Lesser General Public License Version 2.1 or later.
009: *
010: * Software distributed under the License is distributed on an "AS IS" basis,
011: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
012: * for the specific language governing rights and limitations under the
013: * License.
014: */
015:
016: package javassist.expr;
017:
018: import javassist.CannotCompileException;
019: import javassist.ClassPool;
020: import javassist.CtBehavior;
021: import javassist.CtClass;
022: import javassist.CtConstructor;
023: import javassist.CtPrimitiveType;
024: import javassist.NotFoundException;
025: import javassist.bytecode.AccessFlag;
026: import javassist.bytecode.BadBytecode;
027: import javassist.bytecode.Bytecode;
028: import javassist.bytecode.ClassFile;
029: import javassist.bytecode.CodeAttribute;
030: import javassist.bytecode.CodeIterator;
031: import javassist.bytecode.ConstPool;
032: import javassist.bytecode.ExceptionTable;
033: import javassist.bytecode.ExceptionsAttribute;
034: import javassist.bytecode.MethodInfo;
035: import javassist.bytecode.Opcode;
036: import javassist.compiler.Javac;
037:
038: import java.util.Iterator;
039: import java.util.LinkedList;
040:
041: /**
042: * Expression.
043: */
044: public abstract class Expr implements Opcode {
045: int currentPos;
046: CodeIterator iterator;
047: CtClass this Class;
048: MethodInfo this Method;
049: boolean edited;
050: int maxLocals, maxStack;
051:
052: static final String javaLangObject = "java.lang.Object";
053:
054: /**
055: * Undocumented constructor. Do not use; internal-use only.
056: */
057: protected Expr(int pos, CodeIterator i, CtClass declaring,
058: MethodInfo m) {
059: currentPos = pos;
060: iterator = i;
061: this Class = declaring;
062: this Method = m;
063: }
064:
065: protected final ConstPool getConstPool() {
066: return this Method.getConstPool();
067: }
068:
069: protected final boolean edited() {
070: return edited;
071: }
072:
073: protected final int locals() {
074: return maxLocals;
075: }
076:
077: protected final int stack() {
078: return maxStack;
079: }
080:
081: /**
082: * Returns true if this method is static.
083: */
084: protected final boolean withinStatic() {
085: return (this Method.getAccessFlags() & AccessFlag.STATIC) != 0;
086: }
087:
088: /**
089: * Returns the constructor or method containing the expression.
090: */
091: public CtBehavior where() {
092: MethodInfo mi = this Method;
093: CtBehavior[] cb = this Class.getDeclaredBehaviors();
094: for (int i = cb.length - 1; i >= 0; --i)
095: if (cb[i].getMethodInfo2() == mi)
096: return cb[i];
097:
098: CtConstructor init = this Class.getClassInitializer();
099: if (init != null && init.getMethodInfo2() == mi)
100: return init;
101:
102: /* getDeclaredBehaviors() returns a list of methods/constructors.
103: * Although the list is cached in a CtClass object, it might be
104: * recreated for some reason. Thus, the member name and the signature
105: * must be also checked.
106: */
107: for (int i = cb.length - 1; i >= 0; --i) {
108: if (this Method.getName().equals(
109: cb[i].getMethodInfo2().getName())
110: && this Method.getDescriptor().equals(
111: cb[i].getMethodInfo2().getDescriptor())) {
112: return cb[i];
113: }
114: }
115:
116: throw new RuntimeException("fatal: not found");
117: }
118:
119: /**
120: * Returns the list of exceptions that the expression may throw. This list
121: * includes both the exceptions that the try-catch statements including the
122: * expression can catch and the exceptions that the throws declaration
123: * allows the method to throw.
124: */
125: public CtClass[] mayThrow() {
126: ClassPool pool = this Class.getClassPool();
127: ConstPool cp = this Method.getConstPool();
128: LinkedList list = new LinkedList();
129: try {
130: CodeAttribute ca = this Method.getCodeAttribute();
131: ExceptionTable et = ca.getExceptionTable();
132: int pos = currentPos;
133: int n = et.size();
134: for (int i = 0; i < n; ++i)
135: if (et.startPc(i) <= pos && pos < et.endPc(i)) {
136: int t = et.catchType(i);
137: if (t > 0)
138: try {
139: addClass(list, pool.get(cp.getClassInfo(t)));
140: } catch (NotFoundException e) {
141: }
142: }
143: } catch (NullPointerException e) {
144: }
145:
146: ExceptionsAttribute ea = this Method.getExceptionsAttribute();
147: if (ea != null) {
148: String[] exceptions = ea.getExceptions();
149: if (exceptions != null) {
150: int n = exceptions.length;
151: for (int i = 0; i < n; ++i)
152: try {
153: addClass(list, pool.get(exceptions[i]));
154: } catch (NotFoundException e) {
155: }
156: }
157: }
158:
159: return (CtClass[]) list.toArray(new CtClass[list.size()]);
160: }
161:
162: private static void addClass(LinkedList list, CtClass c) {
163: Iterator it = list.iterator();
164: while (it.hasNext())
165: if (it.next() == c)
166: return;
167:
168: list.add(c);
169: }
170:
171: /**
172: * Returns the index of the bytecode corresponding to the expression. It is
173: * the index into the byte array containing the Java bytecode that
174: * implements the method.
175: */
176: public int indexOfBytecode() {
177: return currentPos;
178: }
179:
180: /**
181: * Returns the line number of the source line containing the expression.
182: *
183: * @return -1 if this information is not available.
184: */
185: public int getLineNumber() {
186: return this Method.getLineNumber(currentPos);
187: }
188:
189: /**
190: * Returns the source file containing the expression.
191: *
192: * @return null if this information is not available.
193: */
194: public String getFileName() {
195: ClassFile cf = this Class.getClassFile2();
196: if (cf == null)
197: return null;
198: else
199: return cf.getSourceFile();
200: }
201:
202: static final boolean checkResultValue(CtClass retType, String prog)
203: throws CannotCompileException {
204: /*
205: * Is $_ included in the source code?
206: */
207: boolean hasIt = (prog.indexOf(Javac.resultVarName) >= 0);
208: if (!hasIt && retType != CtClass.voidType)
209: throw new CannotCompileException(
210: "the resulting value is not stored in "
211: + Javac.resultVarName);
212:
213: return hasIt;
214: }
215:
216: /*
217: * If isStaticCall is true, null is assigned to $0. So $0 must be declared
218: * by calling Javac.recordParams().
219: *
220: * After executing this method, the current stack depth might be less than
221: * 0.
222: */
223: static final void storeStack(CtClass[] params,
224: boolean isStaticCall, int regno, Bytecode bytecode) {
225: storeStack0(0, params.length, params, regno + 1, bytecode);
226: if (isStaticCall)
227: bytecode.addOpcode(ACONST_NULL);
228:
229: bytecode.addAstore(regno);
230: }
231:
232: private static void storeStack0(int i, int n, CtClass[] params,
233: int regno, Bytecode bytecode) {
234: if (i >= n)
235: return;
236: else {
237: CtClass c = params[i];
238: int size;
239: if (c instanceof CtPrimitiveType)
240: size = ((CtPrimitiveType) c).getDataSize();
241: else
242: size = 1;
243:
244: storeStack0(i + 1, n, params, regno + size, bytecode);
245: bytecode.addStore(regno, c);
246: }
247: }
248:
249: /**
250: * Replaces this expression with the bytecode derived from
251: * the given source text.
252: *
253: * @param statement a Java statement.
254: */
255: public abstract void replace(String statement)
256: throws CannotCompileException;
257:
258: /**
259: * Replaces this expression with the bytecode derived from
260: * the given source text and <code>ExprEditor</code>.
261: *
262: * @param statement a Java statement.
263: * @param recursive if not null, the substituted bytecode
264: * is recursively processed by the given
265: * <code>ExprEditor</code>.
266: * @since 3.1
267: */
268: public void replace(String statement, ExprEditor recursive)
269: throws CannotCompileException {
270: replace(statement);
271: if (recursive != null)
272: runEditor(recursive, iterator);
273: }
274:
275: protected void replace0(int pos, Bytecode bytecode, int size)
276: throws BadBytecode {
277: byte[] code = bytecode.get();
278: edited = true;
279: int gap = code.length - size;
280: for (int i = 0; i < size; ++i)
281: iterator.writeByte(NOP, pos + i);
282:
283: if (gap > 0)
284: iterator.insertGap(pos, gap);
285:
286: iterator.write(code, pos);
287: iterator.insert(bytecode.getExceptionTable(), pos);
288: maxLocals = bytecode.getMaxLocals();
289: maxStack = bytecode.getMaxStack();
290: }
291:
292: protected void runEditor(ExprEditor ed, CodeIterator oldIterator)
293: throws CannotCompileException {
294: CodeAttribute codeAttr = oldIterator.get();
295: int orgLocals = codeAttr.getMaxLocals();
296: int orgStack = codeAttr.getMaxStack();
297: int newLocals = locals();
298: codeAttr.setMaxStack(stack());
299: codeAttr.setMaxLocals(newLocals);
300: ExprEditor.LoopContext context = new ExprEditor.LoopContext(
301: newLocals);
302: int size = oldIterator.getCodeLength();
303: int endPos = oldIterator.lookAhead();
304: oldIterator.move(currentPos);
305: if (ed
306: .doit(this Class, this Method, context, oldIterator,
307: endPos))
308: edited = true;
309:
310: oldIterator.move(endPos + oldIterator.getCodeLength() - size);
311: codeAttr.setMaxLocals(orgLocals);
312: codeAttr.setMaxStack(orgStack);
313: maxLocals = context.maxLocals;
314: maxStack += context.maxStack;
315: }
316: }
|