/*
 * Javassist, a Java-bytecode translator toolkit.
 * Copyright (C) 1999- 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,
 * or the Apache License Version 2.0.
 *
 * 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 java.util.LinkedList;
import java.util.List;

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;

Expression.
/** * 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.
/** * 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
/** * 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.
/** * 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.
/** * 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.
/** * 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(); List<CtClass> list = new LinkedList<CtClass>(); 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 list.toArray(new CtClass[list.size()]); } private static void addClass(List<CtClass> list, CtClass c) { if (list.contains(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.
/** * 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.
Returns:-1 if this information is not available.
/** * 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.
Returns:null if this information is not available.
/** * 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; 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; 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.
Params:
  • statement – a Java statement except try-catch.
/** * Replaces this expression with the bytecode derived from * the given source text. * * @param statement a Java statement except try-catch. */
public abstract void replace(String statement) throws CannotCompileException;
Replaces this expression with the bytecode derived from the given source text and ExprEditor.
Params:
  • statement – a Java statement except try-catch.
  • recursive – if not null, the substituted bytecode is recursively processed by the given ExprEditor.
Since:3.1
/** * Replaces this expression with the bytecode derived from * the given source text and <code>ExprEditor</code>. * * @param statement a Java statement except try-catch. * @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) pos = iterator.insertGapAt(pos, gap, false).position; 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; } }