123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329 |
- /*
- * Javassist, a Java-bytecode translator toolkit.
- * Copyright (C) 1999-2007 Shigeru Chiba. All Rights Reserved.
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. Alternatively, the contents of this file may be used under
- * the terms of the GNU Lesser General Public License Version 2.1 or later.
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- */
-
- package javassist.expr;
-
- import javassist.CannotCompileException;
- import javassist.ClassPool;
- import javassist.CtBehavior;
- import javassist.CtClass;
- import javassist.CtConstructor;
- import javassist.CtPrimitiveType;
- import javassist.NotFoundException;
- import javassist.bytecode.AccessFlag;
- import javassist.bytecode.BadBytecode;
- import javassist.bytecode.Bytecode;
- import javassist.bytecode.ClassFile;
- import javassist.bytecode.CodeAttribute;
- import javassist.bytecode.CodeIterator;
- import javassist.bytecode.ConstPool;
- import javassist.bytecode.ExceptionTable;
- import javassist.bytecode.ExceptionsAttribute;
- import javassist.bytecode.MethodInfo;
- import javassist.bytecode.Opcode;
- import javassist.compiler.Javac;
-
- import java.util.Iterator;
- import java.util.LinkedList;
-
- /**
- * Expression.
- */
- public abstract class Expr implements Opcode {
- int currentPos;
- CodeIterator iterator;
- CtClass thisClass;
- MethodInfo thisMethod;
- boolean edited;
- int maxLocals, maxStack;
-
- static final String javaLangObject = "java.lang.Object";
-
- /**
- * Undocumented constructor. Do not use; internal-use only.
- */
- protected Expr(int pos, CodeIterator i, CtClass declaring, MethodInfo m) {
- currentPos = pos;
- iterator = i;
- thisClass = declaring;
- thisMethod = m;
- }
-
- /**
- * Returns the class that declares the method enclosing
- * this expression.
- *
- * @since 3.7
- */
- public CtClass getEnclosingClass() { return thisClass; }
-
- protected final ConstPool getConstPool() {
- return thisMethod.getConstPool();
- }
-
- protected final boolean edited() {
- return edited;
- }
-
- protected final int locals() {
- return maxLocals;
- }
-
- protected final int stack() {
- return maxStack;
- }
-
- /**
- * Returns true if this method is static.
- */
- protected final boolean withinStatic() {
- return (thisMethod.getAccessFlags() & AccessFlag.STATIC) != 0;
- }
-
- /**
- * Returns the constructor or method containing the expression.
- */
- public CtBehavior where() {
- MethodInfo mi = thisMethod;
- CtBehavior[] cb = thisClass.getDeclaredBehaviors();
- for (int i = cb.length - 1; i >= 0; --i)
- if (cb[i].getMethodInfo2() == mi)
- return cb[i];
-
- CtConstructor init = thisClass.getClassInitializer();
- if (init != null && init.getMethodInfo2() == mi)
- return init;
-
- /* getDeclaredBehaviors() returns a list of methods/constructors.
- * Although the list is cached in a CtClass object, it might be
- * recreated for some reason. Thus, the member name and the signature
- * must be also checked.
- */
- for (int i = cb.length - 1; i >= 0; --i) {
- if (thisMethod.getName().equals(cb[i].getMethodInfo2().getName())
- && thisMethod.getDescriptor()
- .equals(cb[i].getMethodInfo2().getDescriptor())) {
- return cb[i];
- }
- }
-
- throw new RuntimeException("fatal: not found");
- }
-
- /**
- * Returns the list of exceptions that the expression may throw. This list
- * includes both the exceptions that the try-catch statements including the
- * expression can catch and the exceptions that the throws declaration
- * allows the method to throw.
- */
- public CtClass[] mayThrow() {
- ClassPool pool = thisClass.getClassPool();
- ConstPool cp = thisMethod.getConstPool();
- LinkedList list = new LinkedList();
- try {
- CodeAttribute ca = thisMethod.getCodeAttribute();
- ExceptionTable et = ca.getExceptionTable();
- int pos = currentPos;
- int n = et.size();
- for (int i = 0; i < n; ++i)
- if (et.startPc(i) <= pos && pos < et.endPc(i)) {
- int t = et.catchType(i);
- if (t > 0)
- try {
- addClass(list, pool.get(cp.getClassInfo(t)));
- }
- catch (NotFoundException e) {
- }
- }
- }
- catch (NullPointerException e) {
- }
-
- ExceptionsAttribute ea = thisMethod.getExceptionsAttribute();
- if (ea != null) {
- String[] exceptions = ea.getExceptions();
- if (exceptions != null) {
- int n = exceptions.length;
- for (int i = 0; i < n; ++i)
- try {
- addClass(list, pool.get(exceptions[i]));
- }
- catch (NotFoundException e) {
- }
- }
- }
-
- return (CtClass[])list.toArray(new CtClass[list.size()]);
- }
-
- private static void addClass(LinkedList list, CtClass c) {
- Iterator it = list.iterator();
- while (it.hasNext())
- if (it.next() == c)
- return;
-
- list.add(c);
- }
-
- /**
- * Returns the index of the bytecode corresponding to the expression. It is
- * the index into the byte array containing the Java bytecode that
- * implements the method.
- */
- public int indexOfBytecode() {
- return currentPos;
- }
-
- /**
- * Returns the line number of the source line containing the expression.
- *
- * @return -1 if this information is not available.
- */
- public int getLineNumber() {
- return thisMethod.getLineNumber(currentPos);
- }
-
- /**
- * Returns the source file containing the expression.
- *
- * @return null if this information is not available.
- */
- public String getFileName() {
- ClassFile cf = thisClass.getClassFile2();
- if (cf == null)
- return null;
- else
- return cf.getSourceFile();
- }
-
- static final boolean checkResultValue(CtClass retType, String prog)
- throws CannotCompileException {
- /*
- * Is $_ included in the source code?
- */
- boolean hasIt = (prog.indexOf(Javac.resultVarName) >= 0);
- if (!hasIt && retType != CtClass.voidType)
- throw new CannotCompileException(
- "the resulting value is not stored in "
- + Javac.resultVarName);
-
- return hasIt;
- }
-
- /*
- * If isStaticCall is true, null is assigned to $0. So $0 must be declared
- * by calling Javac.recordParams().
- *
- * After executing this method, the current stack depth might be less than
- * 0.
- */
- static final void storeStack(CtClass[] params, boolean isStaticCall,
- int regno, Bytecode bytecode) {
- storeStack0(0, params.length, params, regno + 1, bytecode);
- if (isStaticCall)
- bytecode.addOpcode(ACONST_NULL);
-
- bytecode.addAstore(regno);
- }
-
- private static void storeStack0(int i, int n, CtClass[] params, int regno,
- Bytecode bytecode) {
- if (i >= n)
- return;
- else {
- CtClass c = params[i];
- int size;
- if (c instanceof CtPrimitiveType)
- size = ((CtPrimitiveType)c).getDataSize();
- else
- size = 1;
-
- storeStack0(i + 1, n, params, regno + size, bytecode);
- bytecode.addStore(regno, c);
- }
- }
-
- // The implementation of replace() should call thisClass.checkModify()
- // so that isModify() will return true. Otherwise, thisClass.classfile
- // might be released during compilation and the compiler might generate
- // bytecode with a wrong copy of ConstPool.
-
- /**
- * Replaces this expression with the bytecode derived from
- * the given source text.
- *
- * @param statement a Java statement.
- */
- public abstract void replace(String statement) throws CannotCompileException;
-
- /**
- * Replaces this expression with the bytecode derived from
- * the given source text and <code>ExprEditor</code>.
- *
- * @param statement a Java statement.
- * @param recursive if not null, the substituted bytecode
- * is recursively processed by the given
- * <code>ExprEditor</code>.
- * @since 3.1
- */
- public void replace(String statement, ExprEditor recursive)
- throws CannotCompileException
- {
- replace(statement);
- if (recursive != null)
- runEditor(recursive, iterator);
- }
-
- protected void replace0(int pos, Bytecode bytecode, int size)
- throws BadBytecode {
- byte[] code = bytecode.get();
- edited = true;
- int gap = code.length - size;
- for (int i = 0; i < size; ++i)
- iterator.writeByte(NOP, pos + i);
-
- if (gap > 0)
- iterator.insertGap(pos, gap);
-
- iterator.write(code, pos);
- iterator.insert(bytecode.getExceptionTable(), pos);
- maxLocals = bytecode.getMaxLocals();
- maxStack = bytecode.getMaxStack();
- }
-
- protected void runEditor(ExprEditor ed, CodeIterator oldIterator)
- throws CannotCompileException
- {
- CodeAttribute codeAttr = oldIterator.get();
- int orgLocals = codeAttr.getMaxLocals();
- int orgStack = codeAttr.getMaxStack();
- int newLocals = locals();
- codeAttr.setMaxStack(stack());
- codeAttr.setMaxLocals(newLocals);
- ExprEditor.LoopContext context
- = new ExprEditor.LoopContext(newLocals);
- int size = oldIterator.getCodeLength();
- int endPos = oldIterator.lookAhead();
- oldIterator.move(currentPos);
- if (ed.doit(thisClass, thisMethod, context, oldIterator, endPos))
- edited = true;
-
- oldIterator.move(endPos + oldIterator.getCodeLength() - size);
- codeAttr.setMaxLocals(orgLocals);
- codeAttr.setMaxStack(orgStack);
- maxLocals = context.maxLocals;
- maxStack += context.maxStack;
- }
- }
|