javassist.bytecode.analysis.SubroutineScanner Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ehcache Show documentation
Show all versions of ehcache Show documentation
Ehcache is an open source, standards-based cache used to boost performance,
offload the database and simplify scalability. Ehcache is robust, proven and full-featured and
this has made it the most widely-used Java-based cache.
/*
* 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.bytecode.analysis;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javassist.bytecode.BadBytecode;
import javassist.bytecode.CodeAttribute;
import javassist.bytecode.CodeIterator;
import javassist.bytecode.ExceptionTable;
import javassist.bytecode.MethodInfo;
import 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(new Integer(pos)))
return;
done.add(new Integer(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 = (Subroutine) subTable.get(new Integer(target));
if (s == null) {
s = new Subroutine(target, pos);
subTable.put(new Integer(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);
}
}
}