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

com.feilong.lib.javassist.bytecode.analysis.SubroutineScanner 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.bytecode.analysis;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import com.feilong.lib.javassist.bytecode.BadBytecode;
import com.feilong.lib.javassist.bytecode.CodeAttribute;
import com.feilong.lib.javassist.bytecode.CodeIterator;
import com.feilong.lib.javassist.bytecode.ExceptionTable;
import com.feilong.lib.javassist.bytecode.MethodInfo;
import com.feilong.lib.javassist.bytecode.Opcode;

/**
 * Discovers the subroutines in a method, and tracks all callers.
 *
 * @author Jason T. Greene
 */
public class SubroutineScanner implements Opcode{

    private Subroutine[]     subroutines;

    Map subTable = new HashMap<>();

    Set             done     = new HashSet<>();

    public Subroutine[] scan(MethodInfo method) throws BadBytecode{
        CodeAttribute code = method.getCodeAttribute();
        CodeIterator iter = code.iterator();

        subroutines = new Subroutine[code.getCodeLength()];
        subTable.clear();
        done.clear();

        scan(0, iter, null);

        ExceptionTable exceptions = code.getExceptionTable();
        for (int i = 0; i < exceptions.size(); i++){
            int handler = exceptions.handlerPc(i);
            // If an exception is thrown in subroutine, the handler
            // is part of the same subroutine.
            scan(handler, iter, subroutines[exceptions.startPc(i)]);
        }

        return subroutines;
    }

    private void scan(int pos,CodeIterator iter,Subroutine sub) throws BadBytecode{
        // Skip already processed blocks
        if (done.contains(pos)){
            return;
        }

        done.add(pos);

        int old = iter.lookAhead();
        iter.move(pos);

        boolean next;
        do{
            pos = iter.next();
            next = scanOp(pos, iter, sub) && iter.hasNext();
        }while (next);

        iter.move(old);
    }

    private boolean scanOp(int pos,CodeIterator iter,Subroutine sub) throws BadBytecode{
        subroutines[pos] = sub;

        int opcode = iter.byteAt(pos);

        if (opcode == TABLESWITCH){
            scanTableSwitch(pos, iter, sub);

            return false;
        }

        if (opcode == LOOKUPSWITCH){
            scanLookupSwitch(pos, iter, sub);

            return false;
        }

        // All forms of return and throw end current code flow
        if (Util.isReturn(opcode) || opcode == RET || opcode == ATHROW){
            return false;
        }

        if (Util.isJumpInstruction(opcode)){
            int target = Util.getJumpTarget(pos, iter);
            if (opcode == JSR || opcode == JSR_W){
                Subroutine s = subTable.get(target);
                if (s == null){
                    s = new Subroutine(target, pos);
                    subTable.put(target, s);
                    scan(target, iter, s);
                }else{
                    s.addCaller(pos);
                }
            }else{
                scan(target, iter, sub);

                // GOTO ends current code flow
                if (Util.isGoto(opcode)){
                    return false;
                }
            }
        }

        return true;
    }

    private void scanLookupSwitch(int pos,CodeIterator iter,Subroutine sub) throws BadBytecode{
        int index = (pos & ~3) + 4;
        // default
        scan(pos + iter.s32bitAt(index), iter, sub);
        int npairs = iter.s32bitAt(index += 4);
        int end = npairs * 8 + (index += 4);

        // skip "match"
        for (index += 4; index < end; index += 8){
            int target = iter.s32bitAt(index) + pos;
            scan(target, iter, sub);
        }
    }

    private void scanTableSwitch(int pos,CodeIterator iter,Subroutine sub) throws BadBytecode{
        // Skip 4 byte alignment padding
        int index = (pos & ~3) + 4;
        // default
        scan(pos + iter.s32bitAt(index), iter, sub);
        int low = iter.s32bitAt(index += 4);
        int high = iter.s32bitAt(index += 4);
        int end = (high - low + 1) * 4 + (index += 4);

        // Offset table
        for (; index < end; index += 4){
            int target = iter.s32bitAt(index) + pos;
            scan(target, iter, sub);
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy