📄 analyzeradapter.java
字号:
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2005 INRIA, France Telecom
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.objectweb.asm.commons;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodAdapter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
/**
* A {@link MethodAdapter} that keeps track of stack map frame changes between
* {@link #visitFrame(int, int, Object[], int, Object[]) visitFrame} calls. This
* adapter must be used with the
* {@link org.objectweb.asm.ClassReader#EXPAND_FRAMES} option. Each visit<i>XXX</i>
* instruction delegates to the next visitor in the chain, if any, and then
* simulates the effect of this instruction on the stack map frame, represented
* by {@link #locals} and {@link #stack}. The next visitor in the chain can get
* the state of the stack map frame <i>before</i> each instruction by reading
* the value of these fields in its visit<i>XXX</i> methods (this requires a
* reference to the AnalyzerAdapter that is before it in the chain).
*
* @author Eric Bruneton
*/
public class AnalyzerAdapter extends MethodAdapter {
/**
* <code>List</code> of the local variable slots for current execution
* frame. Primitive types are represented by {@link Opcodes#TOP},
* {@link Opcodes#INTEGER}, {@link Opcodes#FLOAT}, {@link Opcodes#LONG},
* {@link Opcodes#DOUBLE},{@link Opcodes#NULL} or
* {@link Opcodes#UNINITIALIZED_THIS} (long and double are represented by a
* two elements, the second one being TOP). Reference types are represented
* by String objects (representing internal names, or type descriptors for
* array types), and uninitialized types by Label objects (this label
* designates the NEW instruction that created this uninitialized value).
* This field is <tt>null</tt> for unreacheable instructions.
*/
public List locals;
/**
* <code>List</code> of the operand stack slots for current execution
* frame. Primitive types are represented by {@link Opcodes#TOP},
* {@link Opcodes#INTEGER}, {@link Opcodes#FLOAT}, {@link Opcodes#LONG},
* {@link Opcodes#DOUBLE},{@link Opcodes#NULL} or
* {@link Opcodes#UNINITIALIZED_THIS} (long and double are represented by a
* two elements, the second one being TOP). Reference types are represented
* by String objects (representing internal names, or type descriptors for
* array types), and uninitialized types by Label objects (this label
* designates the NEW instruction that created this uninitialized value).
* This field is <tt>null</tt> for unreacheable instructions.
*/
public List stack;
/**
* The labels that designate the next instruction to be visited. May be
* <tt>null</tt>.
*/
private List labels;
/**
* Information about uninitialized types in the current execution frame.
* This map associates internal names to Label objects. Each label
* designates a NEW instruction that created the currently uninitialized
* types, and the associated internal name represents the NEW operand, i.e.
* the final, initialized type value.
*/
private Map uninitializedTypes;
/**
* The maximum stack size of this method.
*/
private int maxStack;
/**
* The maximum number of local variables of this method.
*/
private int maxLocals;
/**
* Creates a new {@link AnalyzerAdapter}.
*
* @param owner the owner's class name.
* @param access the method's access flags (see {@link Opcodes}).
* @param name the method's name.
* @param desc the method's descriptor (see {@link Type Type}).
* @param mv the method visitor to which this adapter delegates calls. May
* be <tt>null</tt>.
*/
public AnalyzerAdapter(
final String owner,
final int access,
final String name,
final String desc,
final MethodVisitor mv)
{
super(mv);
locals = new ArrayList();
stack = new ArrayList();
uninitializedTypes = new HashMap();
if ((access & Opcodes.ACC_STATIC) == 0) {
if (name.equals("<init>")) {
locals.add(Opcodes.UNINITIALIZED_THIS);
} else {
locals.add(owner);
}
}
Type[] types = Type.getArgumentTypes(desc);
for (int i = 0; i < types.length; ++i) {
Type type = types[i];
switch (type.getSort()) {
case Type.BOOLEAN:
case Type.CHAR:
case Type.BYTE:
case Type.SHORT:
case Type.INT:
locals.add(Opcodes.INTEGER);
break;
case Type.FLOAT:
locals.add(Opcodes.FLOAT);
break;
case Type.LONG:
locals.add(Opcodes.LONG);
locals.add(Opcodes.TOP);
break;
case Type.DOUBLE:
locals.add(Opcodes.DOUBLE);
locals.add(Opcodes.TOP);
break;
case Type.ARRAY:
locals.add(types[i].getDescriptor());
break;
// case Type.OBJECT:
default:
locals.add(types[i].getInternalName());
}
}
}
public void visitFrame(
final int type,
final int nLocal,
final Object[] local,
final int nStack,
final Object[] stack)
{
if (type != Opcodes.F_NEW) { // uncompressed frame
throw new IllegalStateException("ClassReader.accept() should be called with EXPAND_FRAMES flag");
}
if (mv != null) {
mv.visitFrame(type, nLocal, local, nStack, stack);
}
if (this.locals != null) {
this.locals.clear();
this.stack.clear();
} else {
this.locals = new ArrayList();
this.stack = new ArrayList();
}
visitFrameTypes(nLocal, local, this.locals);
visitFrameTypes(nStack, stack, this.stack);
maxStack = Math.max(maxStack, this.stack.size());
}
private void visitFrameTypes(
final int n,
final Object[] types,
final List result)
{
for (int i = 0; i < n; ++i) {
Object type = types[i];
result.add(type);
if (type == Opcodes.LONG || type == Opcodes.DOUBLE) {
result.add(Opcodes.TOP);
}
}
}
public void visitInsn(final int opcode) {
if (mv != null) {
mv.visitInsn(opcode);
}
execute(opcode, 0, null);
if ((opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN)
|| opcode == Opcodes.ATHROW)
{
this.locals = null;
this.stack = null;
}
}
public void visitIntInsn(final int opcode, final int operand) {
if (mv != null) {
mv.visitIntInsn(opcode, operand);
}
execute(opcode, operand, null);
}
public void visitVarInsn(final int opcode, final int var) {
if (mv != null) {
mv.visitVarInsn(opcode, var);
}
execute(opcode, var, null);
}
public void visitTypeInsn(final int opcode, final String desc) {
if (opcode == Opcodes.NEW) {
if (labels == null) {
Label l = new Label();
labels = new ArrayList(3);
labels.add(l);
if (mv != null) {
mv.visitLabel(l);
}
}
for (int i = 0; i < labels.size(); ++i) {
uninitializedTypes.put(labels.get(i), desc);
}
}
if (mv != null) {
mv.visitTypeInsn(opcode, desc);
}
execute(opcode, 0, desc);
}
public void visitFieldInsn(
final int opcode,
final String owner,
final String name,
final String desc)
{
if (mv != null) {
mv.visitFieldInsn(opcode, owner, name, desc);
}
execute(opcode, 0, desc);
}
public void visitMethodInsn(
final int opcode,
final String owner,
final String name,
final String desc)
{
if (mv != null) {
mv.visitMethodInsn(opcode, owner, name, desc);
}
pop(desc);
if (opcode != Opcodes.INVOKESTATIC) {
Object t = pop();
if (opcode == Opcodes.INVOKESPECIAL && name.charAt(0) == '<') {
Object u;
if (t == Opcodes.UNINITIALIZED_THIS) {
u = owner;
} else {
u = uninitializedTypes.get(t);
}
for (int i = 0; i < locals.size(); ++i) {
if (locals.get(i) == t) {
locals.set(i, u);
}
}
for (int i = 0; i < stack.size(); ++i) {
if (stack.get(i) == t) {
stack.set(i, u);
}
}
}
}
pushDesc(desc);
labels = null;
}
public void visitJumpInsn(final int opcode, final Label label) {
if (mv != null) {
mv.visitJumpInsn(opcode, label);
}
execute(opcode, 0, null);
if (opcode == Opcodes.GOTO) {
this.locals = null;
this.stack = null;
}
}
public void visitLabel(final Label label) {
if (mv != null) {
mv.visitLabel(label);
}
if (labels == null) {
labels = new ArrayList(3);
}
labels.add(label);
}
public void visitLdcInsn(final Object cst) {
if (mv != null) {
mv.visitLdcInsn(cst);
}
if (cst instanceof Integer) {
push(Opcodes.INTEGER);
} else if (cst instanceof Long) {
push(Opcodes.LONG);
push(Opcodes.TOP);
} else if (cst instanceof Float) {
push(Opcodes.FLOAT);
} else if (cst instanceof Double) {
push(Opcodes.DOUBLE);
push(Opcodes.TOP);
} else if (cst instanceof String) {
push("java/lang/String");
} else if (cst instanceof Type) {
push("java/lang/Class");
} else {
throw new IllegalArgumentException();
}
labels = null;
}
public void visitIincInsn(final int var, final int increment) {
if (mv != null) {
mv.visitIincInsn(var, increment);
}
execute(Opcodes.IINC, var, null);
}
public void visitTableSwitchInsn(
final int min,
final int max,
final Label dflt,
final Label labels[])
{
if (mv != null) {
mv.visitTableSwitchInsn(min, max, dflt, labels);
}
execute(Opcodes.TABLESWITCH, 0, null);
this.locals = null;
this.stack = null;
}
public void visitLookupSwitchInsn(
final Label dflt,
final int keys[],
final Label labels[])
{
if (mv != null) {
mv.visitLookupSwitchInsn(dflt, keys, labels);
}
execute(Opcodes.LOOKUPSWITCH, 0, null);
this.locals = null;
this.stack = null;
}
public void visitMultiANewArrayInsn(final String desc, final int dims) {
if (mv != null) {
mv.visitMultiANewArrayInsn(desc, dims);
}
execute(Opcodes.MULTIANEWARRAY, dims, desc);
}
public void visitMaxs(final int maxStack, final int maxLocals) {
if (mv != null) {
this.maxStack = Math.max(this.maxStack, maxStack);
this.maxLocals = Math.max(this.maxLocals, maxLocals);
mv.visitMaxs(this.maxStack, this.maxLocals);
}
}
// ------------------------------------------------------------------------
private Object get(final int local) {
maxLocals = Math.max(maxLocals, local);
return local < locals.size() ? locals.get(local) : Opcodes.TOP;
}
private void set(final int local, final Object type) {
maxLocals = Math.max(maxLocals, local);
while (local >= locals.size()) {
locals.add(Opcodes.TOP);
}
locals.set(local, type);
}
private void push(final Object type) {
stack.add(type);
maxStack = Math.max(maxStack, stack.size());
}
private void pushDesc(final String desc) {
int index = desc.charAt(0) == '(' ? desc.indexOf(')') + 1 : 0;
switch (desc.charAt(index)) {
case 'V':
return;
case 'Z':
case 'C':
case 'B':
case 'S':
case 'I':
push(Opcodes.INTEGER);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -