All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.feilong.lib.javassist.expr.Expr Maven / Gradle / Ivy

Go to download

feilong is a suite of core and expanded libraries that include utility classes, http, excel,cvs, io classes, and much much more.

There is a newer version: 4.0.8
Show newest version
/*
 * 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 com.feilong.lib.javassist.expr;

import java.util.LinkedList;
import java.util.List;

import com.feilong.lib.javassist.CannotCompileException;
import com.feilong.lib.javassist.ClassPool;
import com.feilong.lib.javassist.CtBehavior;
import com.feilong.lib.javassist.CtClass;
import com.feilong.lib.javassist.CtConstructor;
import com.feilong.lib.javassist.CtPrimitiveType;
import com.feilong.lib.javassist.NotFoundException;
import com.feilong.lib.javassist.bytecode.AccessFlag;
import com.feilong.lib.javassist.bytecode.BadBytecode;
import com.feilong.lib.javassist.bytecode.Bytecode;
import com.feilong.lib.javassist.bytecode.ClassFile;
import com.feilong.lib.javassist.bytecode.CodeAttribute;
import com.feilong.lib.javassist.bytecode.CodeIterator;
import com.feilong.lib.javassist.bytecode.ConstPool;
import com.feilong.lib.javassist.bytecode.ExceptionTable;
import com.feilong.lib.javassist.bytecode.ExceptionsAttribute;
import com.feilong.lib.javassist.bytecode.MethodInfo;
import com.feilong.lib.javassist.bytecode.Opcode;
import com.feilong.lib.javassist.compiler.Javac;

/**
 * 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();
        List 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 list.toArray(new CtClass[list.size()]);
    }

    private static void addClass(List 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.
     */
    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;
        }
        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.
     *
     * @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.
     *
     * @param statement
     *            a Java statement except try-catch.
     * @param recursive
     *            if not null, the substituted bytecode
     *            is recursively processed by the given
     *            ExprEditor.
     * @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;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy