org.apache.ibatis.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 mybatis Show documentation
Show all versions of mybatis Show documentation
The MyBatis SQL mapper framework makes it easier to use a relational database with object-oriented
applications. MyBatis couples objects with stored procedures or SQL statements using a XML descriptor or
annotations. Simplicity is the biggest advantage of the MyBatis data mapper over object relational mapping
tools.
The 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 org.apache.ibatis.javassist.bytecode.analysis;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.apache.ibatis.javassist.bytecode.BadBytecode;
import org.apache.ibatis.javassist.bytecode.CodeAttribute;
import org.apache.ibatis.javassist.bytecode.CodeIterator;
import org.apache.ibatis.javassist.bytecode.ExceptionTable;
import org.apache.ibatis.javassist.bytecode.MethodInfo;
import org.apache.ibatis.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 - 2025 Weber Informatics LLC | Privacy Policy