mirror of
https://github.com/2006-Scape/Parabot.git
synced 2026-07-03 00:37:55 +00:00
Removed useless ASM files (not used by parabot)
This commit is contained in:
@@ -1,48 +0,0 @@
|
||||
<html>
|
||||
<!--
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 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.
|
||||
-->
|
||||
<body>
|
||||
Provides an implementation for optional class, field and method attributes.
|
||||
|
||||
<p>
|
||||
|
||||
By default ASM strips optional attributes, in order to keep them in
|
||||
the bytecode that is being readed you should pass an array of required attribute
|
||||
instances to {@link org.objectweb.asm.ClassReader#accept(org.objectweb.asm.ClassVisitor, org.objectweb.asm.Attribute[], boolean) ClassReader.accept()} method.
|
||||
In order to add custom attributes to the manually constructed bytecode concrete
|
||||
subclasses of the {@link org.objectweb.asm.Attribute Attribute} can be passed to
|
||||
the visitAttribute methods of the
|
||||
{@link org.objectweb.asm.ClassVisitor ClassVisitor},
|
||||
{@link org.objectweb.asm.FieldVisitor FieldVisitor} and
|
||||
{@link org.objectweb.asm.MethodVisitor MethodVisitor} interfaces.
|
||||
|
||||
@since ASM 1.4.1
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,625 +0,0 @@
|
||||
/***
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 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.Handle;
|
||||
import org.objectweb.asm.Label;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.Type;
|
||||
|
||||
/**
|
||||
* A {@link org.objectweb.asm.MethodVisitor} to insert before, after and around
|
||||
* advices in methods and constructors.
|
||||
* <p>
|
||||
* The behavior for constructors is like this:
|
||||
* <ol>
|
||||
*
|
||||
* <li>as long as the INVOKESPECIAL for the object initialization has not been
|
||||
* reached, every bytecode instruction is dispatched in the ctor code visitor</li>
|
||||
*
|
||||
* <li>when this one is reached, it is only added in the ctor code visitor and a
|
||||
* JP invoke is added</li>
|
||||
*
|
||||
* <li>after that, only the other code visitor receives the instructions</li>
|
||||
*
|
||||
* </ol>
|
||||
*
|
||||
* @author Eugene Kuleshov
|
||||
* @author Eric Bruneton
|
||||
*/
|
||||
public abstract class AdviceAdapter extends GeneratorAdapter implements Opcodes {
|
||||
|
||||
private static final Object THIS = new Object();
|
||||
|
||||
private static final Object OTHER = new Object();
|
||||
|
||||
protected int methodAccess;
|
||||
|
||||
protected String methodDesc;
|
||||
|
||||
private boolean constructor;
|
||||
|
||||
private boolean superInitialized;
|
||||
|
||||
private List<Object> stackFrame;
|
||||
|
||||
private Map<Label, List<Object>> branches;
|
||||
|
||||
/**
|
||||
* Creates a new {@link org.objectweb.asm.commons.AdviceAdapter}.
|
||||
*
|
||||
* @param api
|
||||
* the ASM API version implemented by this visitor. Must be one
|
||||
* of {@link Opcodes#ASM4}.
|
||||
* @param mv
|
||||
* the method visitor to which this adapter delegates calls.
|
||||
* @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}).
|
||||
*/
|
||||
protected AdviceAdapter(final int api, final MethodVisitor mv,
|
||||
final int access, final String name, final String desc) {
|
||||
super(api, mv, access, name, desc);
|
||||
methodAccess = access;
|
||||
methodDesc = desc;
|
||||
constructor = "<init>".equals(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitCode() {
|
||||
mv.visitCode();
|
||||
if (constructor) {
|
||||
stackFrame = new ArrayList<Object>();
|
||||
branches = new HashMap<Label, List<Object>>();
|
||||
} else {
|
||||
superInitialized = true;
|
||||
onMethodEnter();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLabel(final Label label) {
|
||||
mv.visitLabel(label);
|
||||
if (constructor && branches != null) {
|
||||
List<Object> frame = branches.get(label);
|
||||
if (frame != null) {
|
||||
stackFrame = frame;
|
||||
branches.remove(label);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitInsn(final int opcode) {
|
||||
if (constructor) {
|
||||
int s;
|
||||
switch (opcode) {
|
||||
case RETURN: // empty stack
|
||||
onMethodExit(opcode);
|
||||
break;
|
||||
case IRETURN: // 1 before n/a after
|
||||
case FRETURN: // 1 before n/a after
|
||||
case ARETURN: // 1 before n/a after
|
||||
case ATHROW: // 1 before n/a after
|
||||
popValue();
|
||||
onMethodExit(opcode);
|
||||
break;
|
||||
case LRETURN: // 2 before n/a after
|
||||
case DRETURN: // 2 before n/a after
|
||||
popValue();
|
||||
popValue();
|
||||
onMethodExit(opcode);
|
||||
break;
|
||||
case NOP:
|
||||
case LALOAD: // remove 2 add 2
|
||||
case DALOAD: // remove 2 add 2
|
||||
case LNEG:
|
||||
case DNEG:
|
||||
case FNEG:
|
||||
case INEG:
|
||||
case L2D:
|
||||
case D2L:
|
||||
case F2I:
|
||||
case I2B:
|
||||
case I2C:
|
||||
case I2S:
|
||||
case I2F:
|
||||
case ARRAYLENGTH:
|
||||
break;
|
||||
case ACONST_NULL:
|
||||
case ICONST_M1:
|
||||
case ICONST_0:
|
||||
case ICONST_1:
|
||||
case ICONST_2:
|
||||
case ICONST_3:
|
||||
case ICONST_4:
|
||||
case ICONST_5:
|
||||
case FCONST_0:
|
||||
case FCONST_1:
|
||||
case FCONST_2:
|
||||
case F2L: // 1 before 2 after
|
||||
case F2D:
|
||||
case I2L:
|
||||
case I2D:
|
||||
pushValue(OTHER);
|
||||
break;
|
||||
case LCONST_0:
|
||||
case LCONST_1:
|
||||
case DCONST_0:
|
||||
case DCONST_1:
|
||||
pushValue(OTHER);
|
||||
pushValue(OTHER);
|
||||
break;
|
||||
case IALOAD: // remove 2 add 1
|
||||
case FALOAD: // remove 2 add 1
|
||||
case AALOAD: // remove 2 add 1
|
||||
case BALOAD: // remove 2 add 1
|
||||
case CALOAD: // remove 2 add 1
|
||||
case SALOAD: // remove 2 add 1
|
||||
case POP:
|
||||
case IADD:
|
||||
case FADD:
|
||||
case ISUB:
|
||||
case LSHL: // 3 before 2 after
|
||||
case LSHR: // 3 before 2 after
|
||||
case LUSHR: // 3 before 2 after
|
||||
case L2I: // 2 before 1 after
|
||||
case L2F: // 2 before 1 after
|
||||
case D2I: // 2 before 1 after
|
||||
case D2F: // 2 before 1 after
|
||||
case FSUB:
|
||||
case FMUL:
|
||||
case FDIV:
|
||||
case FREM:
|
||||
case FCMPL: // 2 before 1 after
|
||||
case FCMPG: // 2 before 1 after
|
||||
case IMUL:
|
||||
case IDIV:
|
||||
case IREM:
|
||||
case ISHL:
|
||||
case ISHR:
|
||||
case IUSHR:
|
||||
case IAND:
|
||||
case IOR:
|
||||
case IXOR:
|
||||
case MONITORENTER:
|
||||
case MONITOREXIT:
|
||||
popValue();
|
||||
break;
|
||||
case POP2:
|
||||
case LSUB:
|
||||
case LMUL:
|
||||
case LDIV:
|
||||
case LREM:
|
||||
case LADD:
|
||||
case LAND:
|
||||
case LOR:
|
||||
case LXOR:
|
||||
case DADD:
|
||||
case DMUL:
|
||||
case DSUB:
|
||||
case DDIV:
|
||||
case DREM:
|
||||
popValue();
|
||||
popValue();
|
||||
break;
|
||||
case IASTORE:
|
||||
case FASTORE:
|
||||
case AASTORE:
|
||||
case BASTORE:
|
||||
case CASTORE:
|
||||
case SASTORE:
|
||||
case LCMP: // 4 before 1 after
|
||||
case DCMPL:
|
||||
case DCMPG:
|
||||
popValue();
|
||||
popValue();
|
||||
popValue();
|
||||
break;
|
||||
case LASTORE:
|
||||
case DASTORE:
|
||||
popValue();
|
||||
popValue();
|
||||
popValue();
|
||||
popValue();
|
||||
break;
|
||||
case DUP:
|
||||
pushValue(peekValue());
|
||||
break;
|
||||
case DUP_X1:
|
||||
s = stackFrame.size();
|
||||
stackFrame.add(s - 2, stackFrame.get(s - 1));
|
||||
break;
|
||||
case DUP_X2:
|
||||
s = stackFrame.size();
|
||||
stackFrame.add(s - 3, stackFrame.get(s - 1));
|
||||
break;
|
||||
case DUP2:
|
||||
s = stackFrame.size();
|
||||
stackFrame.add(s - 2, stackFrame.get(s - 1));
|
||||
stackFrame.add(s - 2, stackFrame.get(s - 1));
|
||||
break;
|
||||
case DUP2_X1:
|
||||
s = stackFrame.size();
|
||||
stackFrame.add(s - 3, stackFrame.get(s - 1));
|
||||
stackFrame.add(s - 3, stackFrame.get(s - 1));
|
||||
break;
|
||||
case DUP2_X2:
|
||||
s = stackFrame.size();
|
||||
stackFrame.add(s - 4, stackFrame.get(s - 1));
|
||||
stackFrame.add(s - 4, stackFrame.get(s - 1));
|
||||
break;
|
||||
case SWAP:
|
||||
s = stackFrame.size();
|
||||
stackFrame.add(s - 2, stackFrame.get(s - 1));
|
||||
stackFrame.remove(s);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (opcode) {
|
||||
case RETURN:
|
||||
case IRETURN:
|
||||
case FRETURN:
|
||||
case ARETURN:
|
||||
case LRETURN:
|
||||
case DRETURN:
|
||||
case ATHROW:
|
||||
onMethodExit(opcode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
mv.visitInsn(opcode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitVarInsn(final int opcode, final int var) {
|
||||
super.visitVarInsn(opcode, var);
|
||||
if (constructor) {
|
||||
switch (opcode) {
|
||||
case ILOAD:
|
||||
case FLOAD:
|
||||
pushValue(OTHER);
|
||||
break;
|
||||
case LLOAD:
|
||||
case DLOAD:
|
||||
pushValue(OTHER);
|
||||
pushValue(OTHER);
|
||||
break;
|
||||
case ALOAD:
|
||||
pushValue(var == 0 ? THIS : OTHER);
|
||||
break;
|
||||
case ASTORE:
|
||||
case ISTORE:
|
||||
case FSTORE:
|
||||
popValue();
|
||||
break;
|
||||
case LSTORE:
|
||||
case DSTORE:
|
||||
popValue();
|
||||
popValue();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitFieldInsn(final int opcode, final String owner,
|
||||
final String name, final String desc) {
|
||||
mv.visitFieldInsn(opcode, owner, name, desc);
|
||||
if (constructor) {
|
||||
char c = desc.charAt(0);
|
||||
boolean longOrDouble = c == 'J' || c == 'D';
|
||||
switch (opcode) {
|
||||
case GETSTATIC:
|
||||
pushValue(OTHER);
|
||||
if (longOrDouble) {
|
||||
pushValue(OTHER);
|
||||
}
|
||||
break;
|
||||
case PUTSTATIC:
|
||||
popValue();
|
||||
if (longOrDouble) {
|
||||
popValue();
|
||||
}
|
||||
break;
|
||||
case PUTFIELD:
|
||||
popValue();
|
||||
if (longOrDouble) {
|
||||
popValue();
|
||||
popValue();
|
||||
}
|
||||
break;
|
||||
// case GETFIELD:
|
||||
default:
|
||||
if (longOrDouble) {
|
||||
pushValue(OTHER);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitIntInsn(final int opcode, final int operand) {
|
||||
mv.visitIntInsn(opcode, operand);
|
||||
if (constructor && opcode != NEWARRAY) {
|
||||
pushValue(OTHER);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLdcInsn(final Object cst) {
|
||||
mv.visitLdcInsn(cst);
|
||||
if (constructor) {
|
||||
pushValue(OTHER);
|
||||
if (cst instanceof Double || cst instanceof Long) {
|
||||
pushValue(OTHER);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMultiANewArrayInsn(final String desc, final int dims) {
|
||||
mv.visitMultiANewArrayInsn(desc, dims);
|
||||
if (constructor) {
|
||||
for (int i = 0; i < dims; i++) {
|
||||
popValue();
|
||||
}
|
||||
pushValue(OTHER);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTypeInsn(final int opcode, final String type) {
|
||||
mv.visitTypeInsn(opcode, type);
|
||||
// ANEWARRAY, CHECKCAST or INSTANCEOF don't change stack
|
||||
if (constructor && opcode == NEW) {
|
||||
pushValue(OTHER);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMethodInsn(final int opcode, final String owner,
|
||||
final String name, final String desc) {
|
||||
mv.visitMethodInsn(opcode, owner, name, desc);
|
||||
if (constructor) {
|
||||
Type[] types = Type.getArgumentTypes(desc);
|
||||
for (int i = 0; i < types.length; i++) {
|
||||
popValue();
|
||||
if (types[i].getSize() == 2) {
|
||||
popValue();
|
||||
}
|
||||
}
|
||||
switch (opcode) {
|
||||
// case INVOKESTATIC:
|
||||
// break;
|
||||
case INVOKEINTERFACE:
|
||||
case INVOKEVIRTUAL:
|
||||
popValue(); // objectref
|
||||
break;
|
||||
case INVOKESPECIAL:
|
||||
Object type = popValue(); // objectref
|
||||
if (type == THIS && !superInitialized) {
|
||||
onMethodEnter();
|
||||
superInitialized = true;
|
||||
// once super has been initialized it is no longer
|
||||
// necessary to keep track of stack state
|
||||
constructor = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
Type returnType = Type.getReturnType(desc);
|
||||
if (returnType != Type.VOID_TYPE) {
|
||||
pushValue(OTHER);
|
||||
if (returnType.getSize() == 2) {
|
||||
pushValue(OTHER);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitInvokeDynamicInsn(String name, String desc, Handle bsm,
|
||||
Object... bsmArgs) {
|
||||
mv.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
|
||||
if (constructor) {
|
||||
Type[] types = Type.getArgumentTypes(desc);
|
||||
for (int i = 0; i < types.length; i++) {
|
||||
popValue();
|
||||
if (types[i].getSize() == 2) {
|
||||
popValue();
|
||||
}
|
||||
}
|
||||
|
||||
Type returnType = Type.getReturnType(desc);
|
||||
if (returnType != Type.VOID_TYPE) {
|
||||
pushValue(OTHER);
|
||||
if (returnType.getSize() == 2) {
|
||||
pushValue(OTHER);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitJumpInsn(final int opcode, final Label label) {
|
||||
mv.visitJumpInsn(opcode, label);
|
||||
if (constructor) {
|
||||
switch (opcode) {
|
||||
case IFEQ:
|
||||
case IFNE:
|
||||
case IFLT:
|
||||
case IFGE:
|
||||
case IFGT:
|
||||
case IFLE:
|
||||
case IFNULL:
|
||||
case IFNONNULL:
|
||||
popValue();
|
||||
break;
|
||||
case IF_ICMPEQ:
|
||||
case IF_ICMPNE:
|
||||
case IF_ICMPLT:
|
||||
case IF_ICMPGE:
|
||||
case IF_ICMPGT:
|
||||
case IF_ICMPLE:
|
||||
case IF_ACMPEQ:
|
||||
case IF_ACMPNE:
|
||||
popValue();
|
||||
popValue();
|
||||
break;
|
||||
case JSR:
|
||||
pushValue(OTHER);
|
||||
break;
|
||||
}
|
||||
addBranch(label);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLookupSwitchInsn(final Label dflt, final int[] keys,
|
||||
final Label[] labels) {
|
||||
mv.visitLookupSwitchInsn(dflt, keys, labels);
|
||||
if (constructor) {
|
||||
popValue();
|
||||
addBranches(dflt, labels);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTableSwitchInsn(final int min, final int max,
|
||||
final Label dflt, final Label... labels) {
|
||||
mv.visitTableSwitchInsn(min, max, dflt, labels);
|
||||
if (constructor) {
|
||||
popValue();
|
||||
addBranches(dflt, labels);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTryCatchBlock(Label start, Label end, Label handler,
|
||||
String type) {
|
||||
super.visitTryCatchBlock(start, end, handler, type);
|
||||
if (constructor && !branches.containsKey(handler)) {
|
||||
List<Object> stackFrame = new ArrayList<Object>();
|
||||
stackFrame.add(OTHER);
|
||||
branches.put(handler, stackFrame);
|
||||
}
|
||||
}
|
||||
|
||||
private void addBranches(final Label dflt, final Label[] labels) {
|
||||
addBranch(dflt);
|
||||
for (int i = 0; i < labels.length; i++) {
|
||||
addBranch(labels[i]);
|
||||
}
|
||||
}
|
||||
|
||||
private void addBranch(final Label label) {
|
||||
if (branches.containsKey(label)) {
|
||||
return;
|
||||
}
|
||||
branches.put(label, new ArrayList<Object>(stackFrame));
|
||||
}
|
||||
|
||||
private Object popValue() {
|
||||
return stackFrame.remove(stackFrame.size() - 1);
|
||||
}
|
||||
|
||||
private Object peekValue() {
|
||||
return stackFrame.get(stackFrame.size() - 1);
|
||||
}
|
||||
|
||||
private void pushValue(final Object o) {
|
||||
stackFrame.add(o);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called at the beginning of the method or after super class class call in
|
||||
* the constructor. <br>
|
||||
* <br>
|
||||
*
|
||||
* <i>Custom code can use or change all the local variables, but should not
|
||||
* change state of the stack.</i>
|
||||
*/
|
||||
protected void onMethodEnter() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Called before explicit exit from the method using either return or throw.
|
||||
* Top element on the stack contains the return value or exception instance.
|
||||
* For example:
|
||||
*
|
||||
* <pre>
|
||||
* public void onMethodExit(int opcode) {
|
||||
* if(opcode==RETURN) {
|
||||
* visitInsn(ACONST_NULL);
|
||||
* } else if(opcode==ARETURN || opcode==ATHROW) {
|
||||
* dup();
|
||||
* } else {
|
||||
* if(opcode==LRETURN || opcode==DRETURN) {
|
||||
* dup2();
|
||||
* } else {
|
||||
* dup();
|
||||
* }
|
||||
* box(Type.getReturnType(this.methodDesc));
|
||||
* }
|
||||
* visitIntInsn(SIPUSH, opcode);
|
||||
* visitMethodInsn(INVOKESTATIC, owner, "onExit", "(Ljava/lang/Object;I)V");
|
||||
* }
|
||||
*
|
||||
* // an actual call back method
|
||||
* public static void onExit(Object param, int opcode) {
|
||||
* ...
|
||||
* </pre>
|
||||
*
|
||||
* <br>
|
||||
* <br>
|
||||
*
|
||||
* <i>Custom code can use or change all the local variables, but should not
|
||||
* change state of the stack.</i>
|
||||
*
|
||||
* @param opcode
|
||||
* one of the RETURN, IRETURN, FRETURN, ARETURN, LRETURN, DRETURN
|
||||
* or ATHROW
|
||||
*
|
||||
*/
|
||||
protected void onMethodExit(int opcode) {
|
||||
}
|
||||
|
||||
// TODO onException, onMethodCall
|
||||
}
|
||||
@@ -1,920 +0,0 @@
|
||||
/***
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 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.Handle;
|
||||
import org.objectweb.asm.Label;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.Type;
|
||||
|
||||
/**
|
||||
* A {@link MethodVisitor} 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>X</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>X</i> methods (this
|
||||
* requires a reference to the AnalyzerAdapter that is before it in the chain).
|
||||
* If this adapter is used with a class that does not contain stack map table
|
||||
* attributes (i.e., pre Java 6 classes) then this adapter may not be able to
|
||||
* compute the stack map frame for each instruction. In this case no exception
|
||||
* is thrown but the {@link #locals} and {@link #stack} fields will be null for
|
||||
* these instructions.
|
||||
*
|
||||
* @author Eric Bruneton
|
||||
*/
|
||||
public class AnalyzerAdapter extends MethodVisitor {
|
||||
|
||||
/**
|
||||
* <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
|
||||
* two elements, the second one being TOP). Reference types are represented
|
||||
* by String objects (representing internal names), and uninitialized types
|
||||
* by Label objects (this label designates the NEW instruction that created
|
||||
* this uninitialized value). This field is <tt>null</tt> for unreachable
|
||||
* instructions.
|
||||
*/
|
||||
public List<Object> 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
|
||||
* two elements, the second one being TOP). Reference types are represented
|
||||
* by String objects (representing internal names), and uninitialized types
|
||||
* by Label objects (this label designates the NEW instruction that created
|
||||
* this uninitialized value). This field is <tt>null</tt> for unreachable
|
||||
* instructions.
|
||||
*/
|
||||
public List<Object> stack;
|
||||
|
||||
/**
|
||||
* The labels that designate the next instruction to be visited. May be
|
||||
* <tt>null</tt>.
|
||||
*/
|
||||
private List<Label> 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.
|
||||
*/
|
||||
public Map<Object, Object> uninitializedTypes;
|
||||
|
||||
/**
|
||||
* The maximum stack size of this method.
|
||||
*/
|
||||
private int maxStack;
|
||||
|
||||
/**
|
||||
* The maximum number of local variables of this method.
|
||||
*/
|
||||
private int maxLocals;
|
||||
|
||||
/**
|
||||
* The owner's class name.
|
||||
*/
|
||||
private String owner;
|
||||
|
||||
/**
|
||||
* Creates a new {@link org.objectweb.asm.commons.AnalyzerAdapter}. <i>Subclasses must not use this
|
||||
* constructor</i>. Instead, they must use the
|
||||
* {@link #AnalyzerAdapter(int, String, int, String, String, MethodVisitor)}
|
||||
* version.
|
||||
*
|
||||
* @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) {
|
||||
this(Opcodes.ASM4, owner, access, name, desc, mv);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link org.objectweb.asm.commons.AnalyzerAdapter}.
|
||||
*
|
||||
* @param api
|
||||
* the ASM API version implemented by this visitor. Must be one
|
||||
* of {@link Opcodes#ASM4}.
|
||||
* @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>.
|
||||
*/
|
||||
protected AnalyzerAdapter(final int api, final String owner,
|
||||
final int access, final String name, final String desc,
|
||||
final MethodVisitor mv) {
|
||||
super(api, mv);
|
||||
this.owner = owner;
|
||||
locals = new ArrayList<Object>();
|
||||
stack = new ArrayList<Object>();
|
||||
uninitializedTypes = new HashMap<Object, Object>();
|
||||
|
||||
if ((access & Opcodes.ACC_STATIC) == 0) {
|
||||
if ("<init>".equals(name)) {
|
||||
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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
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<Object>();
|
||||
this.stack = new ArrayList<Object>();
|
||||
}
|
||||
visitFrameTypes(nLocal, local, this.locals);
|
||||
visitFrameTypes(nStack, stack, this.stack);
|
||||
maxStack = Math.max(maxStack, this.stack.size());
|
||||
}
|
||||
|
||||
private static void visitFrameTypes(final int n, final Object[] types,
|
||||
final List<Object> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitIntInsn(final int opcode, final int operand) {
|
||||
if (mv != null) {
|
||||
mv.visitIntInsn(opcode, operand);
|
||||
}
|
||||
execute(opcode, operand, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitVarInsn(final int opcode, final int var) {
|
||||
if (mv != null) {
|
||||
mv.visitVarInsn(opcode, var);
|
||||
}
|
||||
execute(opcode, var, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTypeInsn(final int opcode, final String type) {
|
||||
if (opcode == Opcodes.NEW) {
|
||||
if (labels == null) {
|
||||
Label l = new Label();
|
||||
labels = new ArrayList<Label>(3);
|
||||
labels.add(l);
|
||||
if (mv != null) {
|
||||
mv.visitLabel(l);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < labels.size(); ++i) {
|
||||
uninitializedTypes.put(labels.get(i), type);
|
||||
}
|
||||
}
|
||||
if (mv != null) {
|
||||
mv.visitTypeInsn(opcode, type);
|
||||
}
|
||||
execute(opcode, 0, type);
|
||||
}
|
||||
|
||||
@Override
|
||||
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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMethodInsn(final int opcode, final String owner,
|
||||
final String name, final String desc) {
|
||||
if (mv != null) {
|
||||
mv.visitMethodInsn(opcode, owner, name, desc);
|
||||
}
|
||||
if (this.locals == null) {
|
||||
labels = null;
|
||||
return;
|
||||
}
|
||||
pop(desc);
|
||||
if (opcode != Opcodes.INVOKESTATIC) {
|
||||
Object t = pop();
|
||||
if (opcode == Opcodes.INVOKESPECIAL && name.charAt(0) == '<') {
|
||||
Object u;
|
||||
if (t == Opcodes.UNINITIALIZED_THIS) {
|
||||
u = this.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;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitInvokeDynamicInsn(String name, String desc, Handle bsm,
|
||||
Object... bsmArgs) {
|
||||
if (mv != null) {
|
||||
mv.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
|
||||
}
|
||||
if (this.locals == null) {
|
||||
labels = null;
|
||||
return;
|
||||
}
|
||||
pop(desc);
|
||||
pushDesc(desc);
|
||||
labels = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLabel(final Label label) {
|
||||
if (mv != null) {
|
||||
mv.visitLabel(label);
|
||||
}
|
||||
if (labels == null) {
|
||||
labels = new ArrayList<Label>(3);
|
||||
}
|
||||
labels.add(label);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLdcInsn(final Object cst) {
|
||||
if (mv != null) {
|
||||
mv.visitLdcInsn(cst);
|
||||
}
|
||||
if (this.locals == null) {
|
||||
labels = null;
|
||||
return;
|
||||
}
|
||||
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) {
|
||||
int sort = ((Type) cst).getSort();
|
||||
if (sort == Type.OBJECT || sort == Type.ARRAY) {
|
||||
push("java/lang/Class");
|
||||
} else if (sort == Type.METHOD) {
|
||||
push("java/lang/invoke/MethodType");
|
||||
} else {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
} else if (cst instanceof Handle) {
|
||||
push("java/lang/invoke/MethodHandle");
|
||||
} else {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
labels = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitIincInsn(final int var, final int increment) {
|
||||
if (mv != null) {
|
||||
mv.visitIincInsn(var, increment);
|
||||
}
|
||||
execute(Opcodes.IINC, var, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
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;
|
||||
}
|
||||
|
||||
@Override
|
||||
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;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMultiANewArrayInsn(final String desc, final int dims) {
|
||||
if (mv != null) {
|
||||
mv.visitMultiANewArrayInsn(desc, dims);
|
||||
}
|
||||
execute(Opcodes.MULTIANEWARRAY, dims, desc);
|
||||
}
|
||||
|
||||
@Override
|
||||
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);
|
||||
return;
|
||||
case 'F':
|
||||
push(Opcodes.FLOAT);
|
||||
return;
|
||||
case 'J':
|
||||
push(Opcodes.LONG);
|
||||
push(Opcodes.TOP);
|
||||
return;
|
||||
case 'D':
|
||||
push(Opcodes.DOUBLE);
|
||||
push(Opcodes.TOP);
|
||||
return;
|
||||
case '[':
|
||||
if (index == 0) {
|
||||
push(desc);
|
||||
} else {
|
||||
push(desc.substring(index, desc.length()));
|
||||
}
|
||||
break;
|
||||
// case 'L':
|
||||
default:
|
||||
if (index == 0) {
|
||||
push(desc.substring(1, desc.length() - 1));
|
||||
} else {
|
||||
push(desc.substring(index + 1, desc.length() - 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Object pop() {
|
||||
return stack.remove(stack.size() - 1);
|
||||
}
|
||||
|
||||
private void pop(final int n) {
|
||||
int size = stack.size();
|
||||
int end = size - n;
|
||||
for (int i = size - 1; i >= end; --i) {
|
||||
stack.remove(i);
|
||||
}
|
||||
}
|
||||
|
||||
private void pop(final String desc) {
|
||||
char c = desc.charAt(0);
|
||||
if (c == '(') {
|
||||
int n = 0;
|
||||
Type[] types = Type.getArgumentTypes(desc);
|
||||
for (int i = 0; i < types.length; ++i) {
|
||||
n += types[i].getSize();
|
||||
}
|
||||
pop(n);
|
||||
} else if (c == 'J' || c == 'D') {
|
||||
pop(2);
|
||||
} else {
|
||||
pop(1);
|
||||
}
|
||||
}
|
||||
|
||||
private void execute(final int opcode, final int iarg, final String sarg) {
|
||||
if (this.locals == null) {
|
||||
labels = null;
|
||||
return;
|
||||
}
|
||||
Object t1, t2, t3, t4;
|
||||
switch (opcode) {
|
||||
case Opcodes.NOP:
|
||||
case Opcodes.INEG:
|
||||
case Opcodes.LNEG:
|
||||
case Opcodes.FNEG:
|
||||
case Opcodes.DNEG:
|
||||
case Opcodes.I2B:
|
||||
case Opcodes.I2C:
|
||||
case Opcodes.I2S:
|
||||
case Opcodes.GOTO:
|
||||
case Opcodes.RETURN:
|
||||
break;
|
||||
case Opcodes.ACONST_NULL:
|
||||
push(Opcodes.NULL);
|
||||
break;
|
||||
case Opcodes.ICONST_M1:
|
||||
case Opcodes.ICONST_0:
|
||||
case Opcodes.ICONST_1:
|
||||
case Opcodes.ICONST_2:
|
||||
case Opcodes.ICONST_3:
|
||||
case Opcodes.ICONST_4:
|
||||
case Opcodes.ICONST_5:
|
||||
case Opcodes.BIPUSH:
|
||||
case Opcodes.SIPUSH:
|
||||
push(Opcodes.INTEGER);
|
||||
break;
|
||||
case Opcodes.LCONST_0:
|
||||
case Opcodes.LCONST_1:
|
||||
push(Opcodes.LONG);
|
||||
push(Opcodes.TOP);
|
||||
break;
|
||||
case Opcodes.FCONST_0:
|
||||
case Opcodes.FCONST_1:
|
||||
case Opcodes.FCONST_2:
|
||||
push(Opcodes.FLOAT);
|
||||
break;
|
||||
case Opcodes.DCONST_0:
|
||||
case Opcodes.DCONST_1:
|
||||
push(Opcodes.DOUBLE);
|
||||
push(Opcodes.TOP);
|
||||
break;
|
||||
case Opcodes.ILOAD:
|
||||
case Opcodes.FLOAD:
|
||||
case Opcodes.ALOAD:
|
||||
push(get(iarg));
|
||||
break;
|
||||
case Opcodes.LLOAD:
|
||||
case Opcodes.DLOAD:
|
||||
push(get(iarg));
|
||||
push(Opcodes.TOP);
|
||||
break;
|
||||
case Opcodes.IALOAD:
|
||||
case Opcodes.BALOAD:
|
||||
case Opcodes.CALOAD:
|
||||
case Opcodes.SALOAD:
|
||||
pop(2);
|
||||
push(Opcodes.INTEGER);
|
||||
break;
|
||||
case Opcodes.LALOAD:
|
||||
case Opcodes.D2L:
|
||||
pop(2);
|
||||
push(Opcodes.LONG);
|
||||
push(Opcodes.TOP);
|
||||
break;
|
||||
case Opcodes.FALOAD:
|
||||
pop(2);
|
||||
push(Opcodes.FLOAT);
|
||||
break;
|
||||
case Opcodes.DALOAD:
|
||||
case Opcodes.L2D:
|
||||
pop(2);
|
||||
push(Opcodes.DOUBLE);
|
||||
push(Opcodes.TOP);
|
||||
break;
|
||||
case Opcodes.AALOAD:
|
||||
pop(1);
|
||||
t1 = pop();
|
||||
if (t1 instanceof String) {
|
||||
pushDesc(((String) t1).substring(1));
|
||||
} else {
|
||||
push("java/lang/Object");
|
||||
}
|
||||
break;
|
||||
case Opcodes.ISTORE:
|
||||
case Opcodes.FSTORE:
|
||||
case Opcodes.ASTORE:
|
||||
t1 = pop();
|
||||
set(iarg, t1);
|
||||
if (iarg > 0) {
|
||||
t2 = get(iarg - 1);
|
||||
if (t2 == Opcodes.LONG || t2 == Opcodes.DOUBLE) {
|
||||
set(iarg - 1, Opcodes.TOP);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Opcodes.LSTORE:
|
||||
case Opcodes.DSTORE:
|
||||
pop(1);
|
||||
t1 = pop();
|
||||
set(iarg, t1);
|
||||
set(iarg + 1, Opcodes.TOP);
|
||||
if (iarg > 0) {
|
||||
t2 = get(iarg - 1);
|
||||
if (t2 == Opcodes.LONG || t2 == Opcodes.DOUBLE) {
|
||||
set(iarg - 1, Opcodes.TOP);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Opcodes.IASTORE:
|
||||
case Opcodes.BASTORE:
|
||||
case Opcodes.CASTORE:
|
||||
case Opcodes.SASTORE:
|
||||
case Opcodes.FASTORE:
|
||||
case Opcodes.AASTORE:
|
||||
pop(3);
|
||||
break;
|
||||
case Opcodes.LASTORE:
|
||||
case Opcodes.DASTORE:
|
||||
pop(4);
|
||||
break;
|
||||
case Opcodes.POP:
|
||||
case Opcodes.IFEQ:
|
||||
case Opcodes.IFNE:
|
||||
case Opcodes.IFLT:
|
||||
case Opcodes.IFGE:
|
||||
case Opcodes.IFGT:
|
||||
case Opcodes.IFLE:
|
||||
case Opcodes.IRETURN:
|
||||
case Opcodes.FRETURN:
|
||||
case Opcodes.ARETURN:
|
||||
case Opcodes.TABLESWITCH:
|
||||
case Opcodes.LOOKUPSWITCH:
|
||||
case Opcodes.ATHROW:
|
||||
case Opcodes.MONITORENTER:
|
||||
case Opcodes.MONITOREXIT:
|
||||
case Opcodes.IFNULL:
|
||||
case Opcodes.IFNONNULL:
|
||||
pop(1);
|
||||
break;
|
||||
case Opcodes.POP2:
|
||||
case Opcodes.IF_ICMPEQ:
|
||||
case Opcodes.IF_ICMPNE:
|
||||
case Opcodes.IF_ICMPLT:
|
||||
case Opcodes.IF_ICMPGE:
|
||||
case Opcodes.IF_ICMPGT:
|
||||
case Opcodes.IF_ICMPLE:
|
||||
case Opcodes.IF_ACMPEQ:
|
||||
case Opcodes.IF_ACMPNE:
|
||||
case Opcodes.LRETURN:
|
||||
case Opcodes.DRETURN:
|
||||
pop(2);
|
||||
break;
|
||||
case Opcodes.DUP:
|
||||
t1 = pop();
|
||||
push(t1);
|
||||
push(t1);
|
||||
break;
|
||||
case Opcodes.DUP_X1:
|
||||
t1 = pop();
|
||||
t2 = pop();
|
||||
push(t1);
|
||||
push(t2);
|
||||
push(t1);
|
||||
break;
|
||||
case Opcodes.DUP_X2:
|
||||
t1 = pop();
|
||||
t2 = pop();
|
||||
t3 = pop();
|
||||
push(t1);
|
||||
push(t3);
|
||||
push(t2);
|
||||
push(t1);
|
||||
break;
|
||||
case Opcodes.DUP2:
|
||||
t1 = pop();
|
||||
t2 = pop();
|
||||
push(t2);
|
||||
push(t1);
|
||||
push(t2);
|
||||
push(t1);
|
||||
break;
|
||||
case Opcodes.DUP2_X1:
|
||||
t1 = pop();
|
||||
t2 = pop();
|
||||
t3 = pop();
|
||||
push(t2);
|
||||
push(t1);
|
||||
push(t3);
|
||||
push(t2);
|
||||
push(t1);
|
||||
break;
|
||||
case Opcodes.DUP2_X2:
|
||||
t1 = pop();
|
||||
t2 = pop();
|
||||
t3 = pop();
|
||||
t4 = pop();
|
||||
push(t2);
|
||||
push(t1);
|
||||
push(t4);
|
||||
push(t3);
|
||||
push(t2);
|
||||
push(t1);
|
||||
break;
|
||||
case Opcodes.SWAP:
|
||||
t1 = pop();
|
||||
t2 = pop();
|
||||
push(t1);
|
||||
push(t2);
|
||||
break;
|
||||
case Opcodes.IADD:
|
||||
case Opcodes.ISUB:
|
||||
case Opcodes.IMUL:
|
||||
case Opcodes.IDIV:
|
||||
case Opcodes.IREM:
|
||||
case Opcodes.IAND:
|
||||
case Opcodes.IOR:
|
||||
case Opcodes.IXOR:
|
||||
case Opcodes.ISHL:
|
||||
case Opcodes.ISHR:
|
||||
case Opcodes.IUSHR:
|
||||
case Opcodes.L2I:
|
||||
case Opcodes.D2I:
|
||||
case Opcodes.FCMPL:
|
||||
case Opcodes.FCMPG:
|
||||
pop(2);
|
||||
push(Opcodes.INTEGER);
|
||||
break;
|
||||
case Opcodes.LADD:
|
||||
case Opcodes.LSUB:
|
||||
case Opcodes.LMUL:
|
||||
case Opcodes.LDIV:
|
||||
case Opcodes.LREM:
|
||||
case Opcodes.LAND:
|
||||
case Opcodes.LOR:
|
||||
case Opcodes.LXOR:
|
||||
pop(4);
|
||||
push(Opcodes.LONG);
|
||||
push(Opcodes.TOP);
|
||||
break;
|
||||
case Opcodes.FADD:
|
||||
case Opcodes.FSUB:
|
||||
case Opcodes.FMUL:
|
||||
case Opcodes.FDIV:
|
||||
case Opcodes.FREM:
|
||||
case Opcodes.L2F:
|
||||
case Opcodes.D2F:
|
||||
pop(2);
|
||||
push(Opcodes.FLOAT);
|
||||
break;
|
||||
case Opcodes.DADD:
|
||||
case Opcodes.DSUB:
|
||||
case Opcodes.DMUL:
|
||||
case Opcodes.DDIV:
|
||||
case Opcodes.DREM:
|
||||
pop(4);
|
||||
push(Opcodes.DOUBLE);
|
||||
push(Opcodes.TOP);
|
||||
break;
|
||||
case Opcodes.LSHL:
|
||||
case Opcodes.LSHR:
|
||||
case Opcodes.LUSHR:
|
||||
pop(3);
|
||||
push(Opcodes.LONG);
|
||||
push(Opcodes.TOP);
|
||||
break;
|
||||
case Opcodes.IINC:
|
||||
set(iarg, Opcodes.INTEGER);
|
||||
break;
|
||||
case Opcodes.I2L:
|
||||
case Opcodes.F2L:
|
||||
pop(1);
|
||||
push(Opcodes.LONG);
|
||||
push(Opcodes.TOP);
|
||||
break;
|
||||
case Opcodes.I2F:
|
||||
pop(1);
|
||||
push(Opcodes.FLOAT);
|
||||
break;
|
||||
case Opcodes.I2D:
|
||||
case Opcodes.F2D:
|
||||
pop(1);
|
||||
push(Opcodes.DOUBLE);
|
||||
push(Opcodes.TOP);
|
||||
break;
|
||||
case Opcodes.F2I:
|
||||
case Opcodes.ARRAYLENGTH:
|
||||
case Opcodes.INSTANCEOF:
|
||||
pop(1);
|
||||
push(Opcodes.INTEGER);
|
||||
break;
|
||||
case Opcodes.LCMP:
|
||||
case Opcodes.DCMPL:
|
||||
case Opcodes.DCMPG:
|
||||
pop(4);
|
||||
push(Opcodes.INTEGER);
|
||||
break;
|
||||
case Opcodes.JSR:
|
||||
case Opcodes.RET:
|
||||
throw new RuntimeException("JSR/RET are not supported");
|
||||
case Opcodes.GETSTATIC:
|
||||
pushDesc(sarg);
|
||||
break;
|
||||
case Opcodes.PUTSTATIC:
|
||||
pop(sarg);
|
||||
break;
|
||||
case Opcodes.GETFIELD:
|
||||
pop(1);
|
||||
pushDesc(sarg);
|
||||
break;
|
||||
case Opcodes.PUTFIELD:
|
||||
pop(sarg);
|
||||
pop();
|
||||
break;
|
||||
case Opcodes.NEW:
|
||||
push(labels.get(0));
|
||||
break;
|
||||
case Opcodes.NEWARRAY:
|
||||
pop();
|
||||
switch (iarg) {
|
||||
case Opcodes.T_BOOLEAN:
|
||||
pushDesc("[Z");
|
||||
break;
|
||||
case Opcodes.T_CHAR:
|
||||
pushDesc("[C");
|
||||
break;
|
||||
case Opcodes.T_BYTE:
|
||||
pushDesc("[B");
|
||||
break;
|
||||
case Opcodes.T_SHORT:
|
||||
pushDesc("[S");
|
||||
break;
|
||||
case Opcodes.T_INT:
|
||||
pushDesc("[I");
|
||||
break;
|
||||
case Opcodes.T_FLOAT:
|
||||
pushDesc("[F");
|
||||
break;
|
||||
case Opcodes.T_DOUBLE:
|
||||
pushDesc("[D");
|
||||
break;
|
||||
// case Opcodes.T_LONG:
|
||||
default:
|
||||
pushDesc("[J");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case Opcodes.ANEWARRAY:
|
||||
pop();
|
||||
pushDesc("[" + Type.getObjectType(sarg));
|
||||
break;
|
||||
case Opcodes.CHECKCAST:
|
||||
pop();
|
||||
pushDesc(Type.getObjectType(sarg).getDescriptor());
|
||||
break;
|
||||
// case Opcodes.MULTIANEWARRAY:
|
||||
default:
|
||||
pop(iarg);
|
||||
pushDesc(sarg);
|
||||
break;
|
||||
}
|
||||
labels = null;
|
||||
}
|
||||
}
|
||||
@@ -1,217 +0,0 @@
|
||||
/***
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 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 org.objectweb.asm.Handle;
|
||||
import org.objectweb.asm.Label;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
|
||||
/**
|
||||
* A {@link MethodVisitor} that can be used to approximate method size.
|
||||
*
|
||||
* @author Eugene Kuleshov
|
||||
*/
|
||||
public class CodeSizeEvaluator extends MethodVisitor implements Opcodes {
|
||||
|
||||
private int minSize;
|
||||
|
||||
private int maxSize;
|
||||
|
||||
public CodeSizeEvaluator(final MethodVisitor mv) {
|
||||
this(Opcodes.ASM4, mv);
|
||||
}
|
||||
|
||||
protected CodeSizeEvaluator(final int api, final MethodVisitor mv) {
|
||||
super(api, mv);
|
||||
}
|
||||
|
||||
public int getMinSize() {
|
||||
return this.minSize;
|
||||
}
|
||||
|
||||
public int getMaxSize() {
|
||||
return this.maxSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitInsn(final int opcode) {
|
||||
minSize += 1;
|
||||
maxSize += 1;
|
||||
if (mv != null) {
|
||||
mv.visitInsn(opcode);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitIntInsn(final int opcode, final int operand) {
|
||||
if (opcode == SIPUSH) {
|
||||
minSize += 3;
|
||||
maxSize += 3;
|
||||
} else {
|
||||
minSize += 2;
|
||||
maxSize += 2;
|
||||
}
|
||||
if (mv != null) {
|
||||
mv.visitIntInsn(opcode, operand);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitVarInsn(final int opcode, final int var) {
|
||||
if (var < 4 && opcode != RET) {
|
||||
minSize += 1;
|
||||
maxSize += 1;
|
||||
} else if (var >= 256) {
|
||||
minSize += 4;
|
||||
maxSize += 4;
|
||||
} else {
|
||||
minSize += 2;
|
||||
maxSize += 2;
|
||||
}
|
||||
if (mv != null) {
|
||||
mv.visitVarInsn(opcode, var);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTypeInsn(final int opcode, final String type) {
|
||||
minSize += 3;
|
||||
maxSize += 3;
|
||||
if (mv != null) {
|
||||
mv.visitTypeInsn(opcode, type);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitFieldInsn(final int opcode, final String owner,
|
||||
final String name, final String desc) {
|
||||
minSize += 3;
|
||||
maxSize += 3;
|
||||
if (mv != null) {
|
||||
mv.visitFieldInsn(opcode, owner, name, desc);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMethodInsn(final int opcode, final String owner,
|
||||
final String name, final String desc) {
|
||||
if (opcode == INVOKEINTERFACE) {
|
||||
minSize += 5;
|
||||
maxSize += 5;
|
||||
} else {
|
||||
minSize += 3;
|
||||
maxSize += 3;
|
||||
}
|
||||
if (mv != null) {
|
||||
mv.visitMethodInsn(opcode, owner, name, desc);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitInvokeDynamicInsn(String name, String desc, Handle bsm,
|
||||
Object... bsmArgs) {
|
||||
minSize += 5;
|
||||
maxSize += 5;
|
||||
if (mv != null) {
|
||||
mv.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitJumpInsn(final int opcode, final Label label) {
|
||||
minSize += 3;
|
||||
if (opcode == GOTO || opcode == JSR) {
|
||||
maxSize += 5;
|
||||
} else {
|
||||
maxSize += 8;
|
||||
}
|
||||
if (mv != null) {
|
||||
mv.visitJumpInsn(opcode, label);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLdcInsn(final Object cst) {
|
||||
if (cst instanceof Long || cst instanceof Double) {
|
||||
minSize += 3;
|
||||
maxSize += 3;
|
||||
} else {
|
||||
minSize += 2;
|
||||
maxSize += 3;
|
||||
}
|
||||
if (mv != null) {
|
||||
mv.visitLdcInsn(cst);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitIincInsn(final int var, final int increment) {
|
||||
if (var > 255 || increment > 127 || increment < -128) {
|
||||
minSize += 6;
|
||||
maxSize += 6;
|
||||
} else {
|
||||
minSize += 3;
|
||||
maxSize += 3;
|
||||
}
|
||||
if (mv != null) {
|
||||
mv.visitIincInsn(var, increment);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTableSwitchInsn(final int min, final int max,
|
||||
final Label dflt, final Label... labels) {
|
||||
minSize += 13 + labels.length * 4;
|
||||
maxSize += 16 + labels.length * 4;
|
||||
if (mv != null) {
|
||||
mv.visitTableSwitchInsn(min, max, dflt, labels);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLookupSwitchInsn(final Label dflt, final int[] keys,
|
||||
final Label[] labels) {
|
||||
minSize += 9 + keys.length * 8;
|
||||
maxSize += 12 + keys.length * 8;
|
||||
if (mv != null) {
|
||||
mv.visitLookupSwitchInsn(dflt, keys, labels);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMultiANewArrayInsn(final String desc, final int dims) {
|
||||
minSize += 4;
|
||||
maxSize += 4;
|
||||
if (mv != null) {
|
||||
mv.visitMultiANewArrayInsn(desc, dims);
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,736 +0,0 @@
|
||||
/***
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 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.AbstractMap;
|
||||
import java.util.ArrayList;
|
||||
import java.util.BitSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.objectweb.asm.Label;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.tree.AbstractInsnNode;
|
||||
import org.objectweb.asm.tree.InsnList;
|
||||
import org.objectweb.asm.tree.InsnNode;
|
||||
import org.objectweb.asm.tree.JumpInsnNode;
|
||||
import org.objectweb.asm.tree.LabelNode;
|
||||
import org.objectweb.asm.tree.LocalVariableNode;
|
||||
import org.objectweb.asm.tree.LookupSwitchInsnNode;
|
||||
import org.objectweb.asm.tree.MethodNode;
|
||||
import org.objectweb.asm.tree.TableSwitchInsnNode;
|
||||
import org.objectweb.asm.tree.TryCatchBlockNode;
|
||||
|
||||
/**
|
||||
* A {@link org.objectweb.asm.MethodVisitor} that removes JSR instructions and
|
||||
* inlines the referenced subroutines.
|
||||
*
|
||||
* <b>Explanation of how it works</b> TODO
|
||||
*
|
||||
* @author Niko Matsakis
|
||||
*/
|
||||
public class JSRInlinerAdapter extends MethodNode implements Opcodes {
|
||||
|
||||
private static final boolean LOGGING = false;
|
||||
|
||||
/**
|
||||
* For each label that is jumped to by a JSR, we create a BitSet instance.
|
||||
*/
|
||||
private final Map<LabelNode, BitSet> subroutineHeads = new HashMap<LabelNode, BitSet>();
|
||||
|
||||
/**
|
||||
* This subroutine instance denotes the line of execution that is not
|
||||
* contained within any subroutine; i.e., the "subroutine" that is executing
|
||||
* when a method first begins.
|
||||
*/
|
||||
private final BitSet mainSubroutine = new BitSet();
|
||||
|
||||
/**
|
||||
* This BitSet contains the index of every instruction that belongs to more
|
||||
* than one subroutine. This should not happen often.
|
||||
*/
|
||||
final BitSet dualCitizens = new BitSet();
|
||||
|
||||
/**
|
||||
* Creates a new JSRInliner. <i>Subclasses must not use this
|
||||
* constructor</i>. Instead, they must use the
|
||||
* {@link #JSRInlinerAdapter(int, MethodVisitor, int, String, String, String, String[])}
|
||||
* version.
|
||||
*
|
||||
* @param mv
|
||||
* the <code>MethodVisitor</code> to send the resulting inlined
|
||||
* method code to (use <code>null</code> for none).
|
||||
* @param access
|
||||
* the method's access flags (see {@link Opcodes}). This
|
||||
* parameter also indicates if the method is synthetic and/or
|
||||
* deprecated.
|
||||
* @param name
|
||||
* the method's name.
|
||||
* @param desc
|
||||
* the method's descriptor (see {@link Type}).
|
||||
* @param signature
|
||||
* the method's signature. May be <tt>null</tt>.
|
||||
* @param exceptions
|
||||
* the internal names of the method's exception classes (see
|
||||
* {@link Type#getInternalName() getInternalName}). May be
|
||||
* <tt>null</tt>.
|
||||
*/
|
||||
public JSRInlinerAdapter(final MethodVisitor mv, final int access,
|
||||
final String name, final String desc, final String signature,
|
||||
final String[] exceptions) {
|
||||
this(Opcodes.ASM4, mv, access, name, desc, signature, exceptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new JSRInliner.
|
||||
*
|
||||
* @param api
|
||||
* the ASM API version implemented by this visitor. Must be one
|
||||
* of {@link Opcodes#ASM4}.
|
||||
* @param mv
|
||||
* the <code>MethodVisitor</code> to send the resulting inlined
|
||||
* method code to (use <code>null</code> for none).
|
||||
* @param access
|
||||
* the method's access flags (see {@link Opcodes}). This
|
||||
* parameter also indicates if the method is synthetic and/or
|
||||
* deprecated.
|
||||
* @param name
|
||||
* the method's name.
|
||||
* @param desc
|
||||
* the method's descriptor (see {@link Type}).
|
||||
* @param signature
|
||||
* the method's signature. May be <tt>null</tt>.
|
||||
* @param exceptions
|
||||
* the internal names of the method's exception classes (see
|
||||
* {@link Type#getInternalName() getInternalName}). May be
|
||||
* <tt>null</tt>.
|
||||
*/
|
||||
protected JSRInlinerAdapter(final int api, final MethodVisitor mv,
|
||||
final int access, final String name, final String desc,
|
||||
final String signature, final String[] exceptions) {
|
||||
super(api, access, name, desc, signature, exceptions);
|
||||
this.mv = mv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects a JSR instruction and sets a flag to indicate we will need to do
|
||||
* inlining.
|
||||
*/
|
||||
@Override
|
||||
public void visitJumpInsn(final int opcode, final Label lbl) {
|
||||
super.visitJumpInsn(opcode, lbl);
|
||||
LabelNode ln = ((JumpInsnNode) instructions.getLast()).label;
|
||||
if (opcode == JSR && !subroutineHeads.containsKey(ln)) {
|
||||
subroutineHeads.put(ln, new BitSet());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If any JSRs were seen, triggers the inlining process. Otherwise, forwards
|
||||
* the byte codes untouched.
|
||||
*/
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
if (!subroutineHeads.isEmpty()) {
|
||||
markSubroutines();
|
||||
if (LOGGING) {
|
||||
log(mainSubroutine.toString());
|
||||
Iterator<BitSet> it = subroutineHeads.values().iterator();
|
||||
while (it.hasNext()) {
|
||||
BitSet sub = it.next();
|
||||
log(sub.toString());
|
||||
}
|
||||
}
|
||||
emitCode();
|
||||
}
|
||||
|
||||
// Forward the translate opcodes on if appropriate:
|
||||
if (mv != null) {
|
||||
accept(mv);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Walks the method and determines which internal subroutine(s), if any,
|
||||
* each instruction is a method of.
|
||||
*/
|
||||
private void markSubroutines() {
|
||||
BitSet anyvisited = new BitSet();
|
||||
|
||||
// First walk the main subroutine and find all those instructions which
|
||||
// can be reached without invoking any JSR at all
|
||||
markSubroutineWalk(mainSubroutine, 0, anyvisited);
|
||||
|
||||
// Go through the head of each subroutine and find any nodes reachable
|
||||
// to that subroutine without following any JSR links.
|
||||
for (Iterator<Map.Entry<LabelNode, BitSet>> it = subroutineHeads
|
||||
.entrySet().iterator(); it.hasNext();) {
|
||||
Map.Entry<LabelNode, BitSet> entry = it.next();
|
||||
LabelNode lab = entry.getKey();
|
||||
BitSet sub = entry.getValue();
|
||||
int index = instructions.indexOf(lab);
|
||||
markSubroutineWalk(sub, index, anyvisited);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a depth first search walking the normal byte code path starting
|
||||
* at <code>index</code>, and adding each instruction encountered into the
|
||||
* subroutine <code>sub</code>. After this walk is complete, iterates over
|
||||
* the exception handlers to ensure that we also include those byte codes
|
||||
* which are reachable through an exception that may be thrown during the
|
||||
* execution of the subroutine. Invoked from <code>markSubroutines()</code>.
|
||||
*
|
||||
* @param sub
|
||||
* the subroutine whose instructions must be computed.
|
||||
* @param index
|
||||
* an instruction of this subroutine.
|
||||
* @param anyvisited
|
||||
* indexes of the already visited instructions, i.e. marked as
|
||||
* part of this subroutine or any previously computed subroutine.
|
||||
*/
|
||||
private void markSubroutineWalk(final BitSet sub, final int index,
|
||||
final BitSet anyvisited) {
|
||||
if (LOGGING) {
|
||||
log("markSubroutineWalk: sub=" + sub + " index=" + index);
|
||||
}
|
||||
|
||||
// First find those instructions reachable via normal execution
|
||||
markSubroutineWalkDFS(sub, index, anyvisited);
|
||||
|
||||
// Now, make sure we also include any applicable exception handlers
|
||||
boolean loop = true;
|
||||
while (loop) {
|
||||
loop = false;
|
||||
for (Iterator<TryCatchBlockNode> it = tryCatchBlocks.iterator(); it
|
||||
.hasNext();) {
|
||||
TryCatchBlockNode trycatch = it.next();
|
||||
|
||||
if (LOGGING) {
|
||||
// TODO use of default toString().
|
||||
log("Scanning try/catch " + trycatch);
|
||||
}
|
||||
|
||||
// If the handler has already been processed, skip it.
|
||||
int handlerindex = instructions.indexOf(trycatch.handler);
|
||||
if (sub.get(handlerindex)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int startindex = instructions.indexOf(trycatch.start);
|
||||
int endindex = instructions.indexOf(trycatch.end);
|
||||
int nextbit = sub.nextSetBit(startindex);
|
||||
if (nextbit != -1 && nextbit < endindex) {
|
||||
if (LOGGING) {
|
||||
log("Adding exception handler: " + startindex + '-'
|
||||
+ endindex + " due to " + nextbit + " handler "
|
||||
+ handlerindex);
|
||||
}
|
||||
markSubroutineWalkDFS(sub, handlerindex, anyvisited);
|
||||
loop = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a simple DFS of the instructions, assigning each to the
|
||||
* subroutine <code>sub</code>. Starts from <code>index</code>. Invoked only
|
||||
* by <code>markSubroutineWalk()</code>.
|
||||
*
|
||||
* @param sub
|
||||
* the subroutine whose instructions must be computed.
|
||||
* @param index
|
||||
* an instruction of this subroutine.
|
||||
* @param anyvisited
|
||||
* indexes of the already visited instructions, i.e. marked as
|
||||
* part of this subroutine or any previously computed subroutine.
|
||||
*/
|
||||
private void markSubroutineWalkDFS(final BitSet sub, int index,
|
||||
final BitSet anyvisited) {
|
||||
while (true) {
|
||||
AbstractInsnNode node = instructions.get(index);
|
||||
|
||||
// don't visit a node twice
|
||||
if (sub.get(index)) {
|
||||
return;
|
||||
}
|
||||
sub.set(index);
|
||||
|
||||
// check for those nodes already visited by another subroutine
|
||||
if (anyvisited.get(index)) {
|
||||
dualCitizens.set(index);
|
||||
if (LOGGING) {
|
||||
log("Instruction #" + index + " is dual citizen.");
|
||||
}
|
||||
}
|
||||
anyvisited.set(index);
|
||||
|
||||
if (node.getType() == AbstractInsnNode.JUMP_INSN
|
||||
&& node.getOpcode() != JSR) {
|
||||
// we do not follow recursively called subroutines here; but any
|
||||
// other sort of branch we do follow
|
||||
JumpInsnNode jnode = (JumpInsnNode) node;
|
||||
int destidx = instructions.indexOf(jnode.label);
|
||||
markSubroutineWalkDFS(sub, destidx, anyvisited);
|
||||
}
|
||||
if (node.getType() == AbstractInsnNode.TABLESWITCH_INSN) {
|
||||
TableSwitchInsnNode tsnode = (TableSwitchInsnNode) node;
|
||||
int destidx = instructions.indexOf(tsnode.dflt);
|
||||
markSubroutineWalkDFS(sub, destidx, anyvisited);
|
||||
for (int i = tsnode.labels.size() - 1; i >= 0; --i) {
|
||||
LabelNode l = tsnode.labels.get(i);
|
||||
destidx = instructions.indexOf(l);
|
||||
markSubroutineWalkDFS(sub, destidx, anyvisited);
|
||||
}
|
||||
}
|
||||
if (node.getType() == AbstractInsnNode.LOOKUPSWITCH_INSN) {
|
||||
LookupSwitchInsnNode lsnode = (LookupSwitchInsnNode) node;
|
||||
int destidx = instructions.indexOf(lsnode.dflt);
|
||||
markSubroutineWalkDFS(sub, destidx, anyvisited);
|
||||
for (int i = lsnode.labels.size() - 1; i >= 0; --i) {
|
||||
LabelNode l = lsnode.labels.get(i);
|
||||
destidx = instructions.indexOf(l);
|
||||
markSubroutineWalkDFS(sub, destidx, anyvisited);
|
||||
}
|
||||
}
|
||||
|
||||
// check to see if this opcode falls through to the next instruction
|
||||
// or not; if not, return.
|
||||
switch (instructions.get(index).getOpcode()) {
|
||||
case GOTO:
|
||||
case RET:
|
||||
case TABLESWITCH:
|
||||
case LOOKUPSWITCH:
|
||||
case IRETURN:
|
||||
case LRETURN:
|
||||
case FRETURN:
|
||||
case DRETURN:
|
||||
case ARETURN:
|
||||
case RETURN:
|
||||
case ATHROW:
|
||||
/*
|
||||
* note: this either returns from this subroutine, or a parent
|
||||
* subroutine which invoked it
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
// Use tail recursion here in the form of an outer while loop to
|
||||
// avoid our stack growing needlessly:
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the new instructions, inlining each instantiation of each
|
||||
* subroutine until the code is fully elaborated.
|
||||
*/
|
||||
private void emitCode() {
|
||||
LinkedList<Instantiation> worklist = new LinkedList<Instantiation>();
|
||||
// Create an instantiation of the "root" subroutine, which is just the
|
||||
// main routine
|
||||
worklist.add(new Instantiation(null, mainSubroutine));
|
||||
|
||||
// Emit instantiations of each subroutine we encounter, including the
|
||||
// main subroutine
|
||||
InsnList newInstructions = new InsnList();
|
||||
List<TryCatchBlockNode> newTryCatchBlocks = new ArrayList<TryCatchBlockNode>();
|
||||
List<LocalVariableNode> newLocalVariables = new ArrayList<LocalVariableNode>();
|
||||
while (!worklist.isEmpty()) {
|
||||
Instantiation inst = worklist.removeFirst();
|
||||
emitSubroutine(inst, worklist, newInstructions, newTryCatchBlocks,
|
||||
newLocalVariables);
|
||||
}
|
||||
instructions = newInstructions;
|
||||
tryCatchBlocks = newTryCatchBlocks;
|
||||
localVariables = newLocalVariables;
|
||||
}
|
||||
|
||||
/**
|
||||
* Emits one instantiation of one subroutine, specified by
|
||||
* <code>instant</code>. May add new instantiations that are invoked by this
|
||||
* one to the <code>worklist</code> parameter, and new try/catch blocks to
|
||||
* <code>newTryCatchBlocks</code>.
|
||||
*
|
||||
* @param instant
|
||||
* the instantiation that must be performed.
|
||||
* @param worklist
|
||||
* list of the instantiations that remain to be done.
|
||||
* @param newInstructions
|
||||
* the instruction list to which the instantiated code must be
|
||||
* appended.
|
||||
* @param newTryCatchBlocks
|
||||
* the exception handler list to which the instantiated handlers
|
||||
* must be appended.
|
||||
*/
|
||||
private void emitSubroutine(final Instantiation instant,
|
||||
final List<Instantiation> worklist, final InsnList newInstructions,
|
||||
final List<TryCatchBlockNode> newTryCatchBlocks,
|
||||
final List<LocalVariableNode> newLocalVariables) {
|
||||
LabelNode duplbl = null;
|
||||
|
||||
if (LOGGING) {
|
||||
log("--------------------------------------------------------");
|
||||
log("Emitting instantiation of subroutine " + instant.subroutine);
|
||||
}
|
||||
|
||||
// Emit the relevant instructions for this instantiation, translating
|
||||
// labels and jump targets as we go:
|
||||
for (int i = 0, c = instructions.size(); i < c; i++) {
|
||||
AbstractInsnNode insn = instructions.get(i);
|
||||
Instantiation owner = instant.findOwner(i);
|
||||
|
||||
// Always remap labels:
|
||||
if (insn.getType() == AbstractInsnNode.LABEL) {
|
||||
// Translate labels into their renamed equivalents.
|
||||
// Avoid adding the same label more than once. Note
|
||||
// that because we own this instruction the gotoTable
|
||||
// and the rangeTable will always agree.
|
||||
LabelNode ilbl = (LabelNode) insn;
|
||||
LabelNode remap = instant.rangeLabel(ilbl);
|
||||
if (LOGGING) {
|
||||
// TODO use of default toString().
|
||||
log("Translating lbl #" + i + ':' + ilbl + " to " + remap);
|
||||
}
|
||||
if (remap != duplbl) {
|
||||
newInstructions.add(remap);
|
||||
duplbl = remap;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// We don't want to emit instructions that were already
|
||||
// emitted by a subroutine higher on the stack. Note that
|
||||
// it is still possible for a given instruction to be
|
||||
// emitted twice because it may belong to two subroutines
|
||||
// that do not invoke each other.
|
||||
if (owner != instant) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (LOGGING) {
|
||||
log("Emitting inst #" + i);
|
||||
}
|
||||
|
||||
if (insn.getOpcode() == RET) {
|
||||
// Translate RET instruction(s) to a jump to the return label
|
||||
// for the appropriate instantiation. The problem is that the
|
||||
// subroutine may "fall through" to the ret of a parent
|
||||
// subroutine; therefore, to find the appropriate ret label we
|
||||
// find the lowest subroutine on the stack that claims to own
|
||||
// this instruction. See the class javadoc comment for an
|
||||
// explanation on why this technique is safe (note: it is only
|
||||
// safe if the input is verifiable).
|
||||
LabelNode retlabel = null;
|
||||
for (Instantiation p = instant; p != null; p = p.previous) {
|
||||
if (p.subroutine.get(i)) {
|
||||
retlabel = p.returnLabel;
|
||||
}
|
||||
}
|
||||
if (retlabel == null) {
|
||||
// This is only possible if the mainSubroutine owns a RET
|
||||
// instruction, which should never happen for verifiable
|
||||
// code.
|
||||
throw new RuntimeException("Instruction #" + i
|
||||
+ " is a RET not owned by any subroutine");
|
||||
}
|
||||
newInstructions.add(new JumpInsnNode(GOTO, retlabel));
|
||||
} else if (insn.getOpcode() == JSR) {
|
||||
LabelNode lbl = ((JumpInsnNode) insn).label;
|
||||
BitSet sub = subroutineHeads.get(lbl);
|
||||
Instantiation newinst = new Instantiation(instant, sub);
|
||||
LabelNode startlbl = newinst.gotoLabel(lbl);
|
||||
|
||||
if (LOGGING) {
|
||||
log(" Creating instantiation of subr " + sub);
|
||||
}
|
||||
|
||||
// Rather than JSRing, we will jump to the inline version and
|
||||
// push NULL for what was once the return value. This hack
|
||||
// allows us to avoid doing any sort of data flow analysis to
|
||||
// figure out which instructions manipulate the old return value
|
||||
// pointer which is now known to be unneeded.
|
||||
newInstructions.add(new InsnNode(ACONST_NULL));
|
||||
newInstructions.add(new JumpInsnNode(GOTO, startlbl));
|
||||
newInstructions.add(newinst.returnLabel);
|
||||
|
||||
// Insert this new instantiation into the queue to be emitted
|
||||
// later.
|
||||
worklist.add(newinst);
|
||||
} else {
|
||||
newInstructions.add(insn.clone(instant));
|
||||
}
|
||||
}
|
||||
|
||||
// Emit try/catch blocks that are relevant to this method.
|
||||
for (Iterator<TryCatchBlockNode> it = tryCatchBlocks.iterator(); it
|
||||
.hasNext();) {
|
||||
TryCatchBlockNode trycatch = it.next();
|
||||
|
||||
if (LOGGING) {
|
||||
// TODO use of default toString().
|
||||
log("try catch block original labels=" + trycatch.start + '-'
|
||||
+ trycatch.end + "->" + trycatch.handler);
|
||||
}
|
||||
|
||||
final LabelNode start = instant.rangeLabel(trycatch.start);
|
||||
final LabelNode end = instant.rangeLabel(trycatch.end);
|
||||
|
||||
// Ignore empty try/catch regions
|
||||
if (start == end) {
|
||||
if (LOGGING) {
|
||||
log(" try catch block empty in this subroutine");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
final LabelNode handler = instant.gotoLabel(trycatch.handler);
|
||||
|
||||
if (LOGGING) {
|
||||
// TODO use of default toString().
|
||||
log(" try catch block new labels=" + start + '-' + end + "->"
|
||||
+ handler);
|
||||
}
|
||||
|
||||
if (start == null || end == null || handler == null) {
|
||||
throw new RuntimeException("Internal error!");
|
||||
}
|
||||
|
||||
newTryCatchBlocks.add(new TryCatchBlockNode(start, end, handler,
|
||||
trycatch.type));
|
||||
}
|
||||
|
||||
for (Iterator<LocalVariableNode> it = localVariables.iterator(); it
|
||||
.hasNext();) {
|
||||
LocalVariableNode lvnode = it.next();
|
||||
if (LOGGING) {
|
||||
log("local var " + lvnode.name);
|
||||
}
|
||||
final LabelNode start = instant.rangeLabel(lvnode.start);
|
||||
final LabelNode end = instant.rangeLabel(lvnode.end);
|
||||
if (start == end) {
|
||||
if (LOGGING) {
|
||||
log(" local variable empty in this sub");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
newLocalVariables.add(new LocalVariableNode(lvnode.name,
|
||||
lvnode.desc, lvnode.signature, start, end, lvnode.index));
|
||||
}
|
||||
}
|
||||
|
||||
private static void log(final String str) {
|
||||
System.err.println(str);
|
||||
}
|
||||
|
||||
/**
|
||||
* A class that represents an instantiation of a subroutine. Each
|
||||
* instantiation has an associate "stack" --- which is a listing of those
|
||||
* instantiations that were active when this particular instance of this
|
||||
* subroutine was invoked. Each instantiation also has a map from the
|
||||
* original labels of the program to the labels appropriate for this
|
||||
* instantiation, and finally a label to return to.
|
||||
*/
|
||||
private class Instantiation extends AbstractMap<LabelNode, LabelNode> {
|
||||
|
||||
/**
|
||||
* Previous instantiations; the stack must be statically predictable to
|
||||
* be inlinable.
|
||||
*/
|
||||
final Instantiation previous;
|
||||
|
||||
/**
|
||||
* The subroutine this is an instantiation of.
|
||||
*/
|
||||
public final BitSet subroutine;
|
||||
|
||||
/**
|
||||
* This table maps Labels from the original source to Labels pointing at
|
||||
* code specific to this instantiation, for use in remapping try/catch
|
||||
* blocks,as well as gotos.
|
||||
*
|
||||
* Note that in the presence of dual citizens instructions, that is,
|
||||
* instructions which belong to more than one subroutine due to the
|
||||
* merging of control flow without a RET instruction, we will map the
|
||||
* target label of a GOTO to the label used by the instantiation lowest
|
||||
* on the stack. This avoids code duplication during inlining in most
|
||||
* cases.
|
||||
*
|
||||
* @see #findOwner(int)
|
||||
*/
|
||||
public final Map<LabelNode, LabelNode> rangeTable = new HashMap<LabelNode, LabelNode>();
|
||||
|
||||
/**
|
||||
* All returns for this instantiation will be mapped to this label
|
||||
*/
|
||||
public final LabelNode returnLabel;
|
||||
|
||||
Instantiation(final Instantiation prev, final BitSet sub) {
|
||||
previous = prev;
|
||||
subroutine = sub;
|
||||
for (Instantiation p = prev; p != null; p = p.previous) {
|
||||
if (p.subroutine == sub) {
|
||||
throw new RuntimeException("Recursive invocation of " + sub);
|
||||
}
|
||||
}
|
||||
|
||||
// Determine the label to return to when this subroutine terminates
|
||||
// via RET: note that the main subroutine never terminates via RET.
|
||||
if (prev != null) {
|
||||
returnLabel = new LabelNode();
|
||||
} else {
|
||||
returnLabel = null;
|
||||
}
|
||||
|
||||
// Each instantiation will remap the labels from the code above to
|
||||
// refer to its particular copy of its own instructions. Note that
|
||||
// we collapse labels which point at the same instruction into one:
|
||||
// this is fairly common as we are often ignoring large chunks of
|
||||
// instructions, so what were previously distinct labels become
|
||||
// duplicates.
|
||||
LabelNode duplbl = null;
|
||||
for (int i = 0, c = instructions.size(); i < c; i++) {
|
||||
AbstractInsnNode insn = instructions.get(i);
|
||||
|
||||
if (insn.getType() == AbstractInsnNode.LABEL) {
|
||||
LabelNode ilbl = (LabelNode) insn;
|
||||
|
||||
if (duplbl == null) {
|
||||
// if we already have a label pointing at this spot,
|
||||
// don't recreate it.
|
||||
duplbl = new LabelNode();
|
||||
}
|
||||
|
||||
// Add an entry in the rangeTable for every label
|
||||
// in the original code which points at the next
|
||||
// instruction of our own to be emitted.
|
||||
rangeTable.put(ilbl, duplbl);
|
||||
} else if (findOwner(i) == this) {
|
||||
// We will emit this instruction, so clear the 'duplbl' flag
|
||||
// since the next Label will refer to a distinct
|
||||
// instruction.
|
||||
duplbl = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the "owner" of a particular instruction relative to this
|
||||
* instantiation: the owner referes to the Instantiation which will emit
|
||||
* the version of this instruction that we will execute.
|
||||
*
|
||||
* Typically, the return value is either <code>this</code> or
|
||||
* <code>null</code>. <code>this</code> indicates that this
|
||||
* instantiation will generate the version of this instruction that we
|
||||
* will execute, and <code>null</code> indicates that this instantiation
|
||||
* never executes the given instruction.
|
||||
*
|
||||
* Sometimes, however, an instruction can belong to multiple
|
||||
* subroutines; this is called a "dual citizen" instruction (though it
|
||||
* may belong to more than 2 subroutines), and occurs when multiple
|
||||
* subroutines branch to common points of control. In this case, the
|
||||
* owner is the subroutine that appears lowest on the stack, and which
|
||||
* also owns the instruction in question.
|
||||
*
|
||||
* @param i
|
||||
* the index of the instruction in the original code
|
||||
* @return the "owner" of a particular instruction relative to this
|
||||
* instantiation.
|
||||
*/
|
||||
public Instantiation findOwner(final int i) {
|
||||
if (!subroutine.get(i)) {
|
||||
return null;
|
||||
}
|
||||
if (!dualCitizens.get(i)) {
|
||||
return this;
|
||||
}
|
||||
Instantiation own = this;
|
||||
for (Instantiation p = previous; p != null; p = p.previous) {
|
||||
if (p.subroutine.get(i)) {
|
||||
own = p;
|
||||
}
|
||||
}
|
||||
return own;
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks up the label <code>l</code> in the <code>gotoTable</code>, thus
|
||||
* translating it from a Label in the original code, to a Label in the
|
||||
* inlined code that is appropriate for use by an instruction that
|
||||
* branched to the original label.
|
||||
*
|
||||
* @param l
|
||||
* The label we will be translating
|
||||
* @return a label for use by a branch instruction in the inlined code
|
||||
* @see #rangeLabel
|
||||
*/
|
||||
public LabelNode gotoLabel(final LabelNode l) {
|
||||
// owner should never be null, because owner is only null
|
||||
// if an instruction cannot be reached from this subroutine
|
||||
Instantiation owner = findOwner(instructions.indexOf(l));
|
||||
return owner.rangeTable.get(l);
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks up the label <code>l</code> in the <code>rangeTable</code>,
|
||||
* thus translating it from a Label in the original code, to a Label in
|
||||
* the inlined code that is appropriate for use by an try/catch or
|
||||
* variable use annotation.
|
||||
*
|
||||
* @param l
|
||||
* The label we will be translating
|
||||
* @return a label for use by a try/catch or variable annotation in the
|
||||
* original code
|
||||
* @see #rangeTable
|
||||
*/
|
||||
public LabelNode rangeLabel(final LabelNode l) {
|
||||
return rangeTable.get(l);
|
||||
}
|
||||
|
||||
// AbstractMap implementation
|
||||
|
||||
@Override
|
||||
public Set<Entry<LabelNode, LabelNode>> entrySet() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LabelNode get(final Object o) {
|
||||
return gotoLabel((LabelNode) o);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,360 +0,0 @@
|
||||
/***
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 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 org.objectweb.asm.Label;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.Type;
|
||||
|
||||
/**
|
||||
* A {@link MethodVisitor} that renumbers local variables in their order of
|
||||
* appearance. This adapter allows one to easily add new local variables to a
|
||||
* method. It may be used by inheriting from this class, but the preferred way
|
||||
* of using it is via delegation: the next visitor in the chain can indeed add
|
||||
* new locals when needed by calling {@link #newLocal} on this adapter (this
|
||||
* requires a reference back to this {@link org.objectweb.asm.commons.LocalVariablesSorter}).
|
||||
*
|
||||
* @author Chris Nokleberg
|
||||
* @author Eugene Kuleshov
|
||||
* @author Eric Bruneton
|
||||
*/
|
||||
public class LocalVariablesSorter extends MethodVisitor {
|
||||
|
||||
private static final Type OBJECT_TYPE = Type
|
||||
.getObjectType("java/lang/Object");
|
||||
|
||||
/**
|
||||
* Mapping from old to new local variable indexes. A local variable at index
|
||||
* i of size 1 is remapped to 'mapping[2*i]', while a local variable at
|
||||
* index i of size 2 is remapped to 'mapping[2*i+1]'.
|
||||
*/
|
||||
private int[] mapping = new int[40];
|
||||
|
||||
/**
|
||||
* Array used to store stack map local variable types after remapping.
|
||||
*/
|
||||
private Object[] newLocals = new Object[20];
|
||||
|
||||
/**
|
||||
* Index of the first local variable, after formal parameters.
|
||||
*/
|
||||
protected final int firstLocal;
|
||||
|
||||
/**
|
||||
* Index of the next local variable to be created by {@link #newLocal}.
|
||||
*/
|
||||
protected int nextLocal;
|
||||
|
||||
/**
|
||||
* Indicates if at least one local variable has moved due to remapping.
|
||||
*/
|
||||
private boolean changed;
|
||||
|
||||
/**
|
||||
* Creates a new {@link org.objectweb.asm.commons.LocalVariablesSorter}. <i>Subclasses must not use
|
||||
* this constructor</i>. Instead, they must use the
|
||||
* {@link #LocalVariablesSorter(int, int, String, MethodVisitor)} version.
|
||||
*
|
||||
* @param access
|
||||
* access flags of the adapted method.
|
||||
* @param desc
|
||||
* the method's descriptor (see {@link Type Type}).
|
||||
* @param mv
|
||||
* the method visitor to which this adapter delegates calls.
|
||||
*/
|
||||
public LocalVariablesSorter(final int access, final String desc,
|
||||
final MethodVisitor mv) {
|
||||
this(Opcodes.ASM4, access, desc, mv);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link org.objectweb.asm.commons.LocalVariablesSorter}.
|
||||
*
|
||||
* @param api
|
||||
* the ASM API version implemented by this visitor. Must be one
|
||||
* of {@link Opcodes#ASM4}.
|
||||
* @param access
|
||||
* access flags of the adapted method.
|
||||
* @param desc
|
||||
* the method's descriptor (see {@link Type Type}).
|
||||
* @param mv
|
||||
* the method visitor to which this adapter delegates calls.
|
||||
*/
|
||||
protected LocalVariablesSorter(final int api, final int access,
|
||||
final String desc, final MethodVisitor mv) {
|
||||
super(api, mv);
|
||||
Type[] args = Type.getArgumentTypes(desc);
|
||||
nextLocal = (Opcodes.ACC_STATIC & access) == 0 ? 1 : 0;
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
nextLocal += args[i].getSize();
|
||||
}
|
||||
firstLocal = nextLocal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitVarInsn(final int opcode, final int var) {
|
||||
Type type;
|
||||
switch (opcode) {
|
||||
case Opcodes.LLOAD:
|
||||
case Opcodes.LSTORE:
|
||||
type = Type.LONG_TYPE;
|
||||
break;
|
||||
|
||||
case Opcodes.DLOAD:
|
||||
case Opcodes.DSTORE:
|
||||
type = Type.DOUBLE_TYPE;
|
||||
break;
|
||||
|
||||
case Opcodes.FLOAD:
|
||||
case Opcodes.FSTORE:
|
||||
type = Type.FLOAT_TYPE;
|
||||
break;
|
||||
|
||||
case Opcodes.ILOAD:
|
||||
case Opcodes.ISTORE:
|
||||
type = Type.INT_TYPE;
|
||||
break;
|
||||
|
||||
default:
|
||||
// case Opcodes.ALOAD:
|
||||
// case Opcodes.ASTORE:
|
||||
// case RET:
|
||||
type = OBJECT_TYPE;
|
||||
break;
|
||||
}
|
||||
mv.visitVarInsn(opcode, remap(var, type));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitIincInsn(final int var, final int increment) {
|
||||
mv.visitIincInsn(remap(var, Type.INT_TYPE), increment);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMaxs(final int maxStack, final int maxLocals) {
|
||||
mv.visitMaxs(maxStack, nextLocal);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLocalVariable(final String name, final String desc,
|
||||
final String signature, final Label start, final Label end,
|
||||
final int index) {
|
||||
int newIndex = remap(index, Type.getType(desc));
|
||||
mv.visitLocalVariable(name, desc, signature, start, end, newIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
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 (!changed) { // optimization for the case where mapping = identity
|
||||
mv.visitFrame(type, nLocal, local, nStack, stack);
|
||||
return;
|
||||
}
|
||||
|
||||
// creates a copy of newLocals
|
||||
Object[] oldLocals = new Object[newLocals.length];
|
||||
System.arraycopy(newLocals, 0, oldLocals, 0, oldLocals.length);
|
||||
|
||||
updateNewLocals(newLocals);
|
||||
|
||||
// copies types from 'local' to 'newLocals'
|
||||
// 'newLocals' already contains the variables added with 'newLocal'
|
||||
|
||||
int index = 0; // old local variable index
|
||||
int number = 0; // old local variable number
|
||||
for (; number < nLocal; ++number) {
|
||||
Object t = local[number];
|
||||
int size = t == Opcodes.LONG || t == Opcodes.DOUBLE ? 2 : 1;
|
||||
if (t != Opcodes.TOP) {
|
||||
Type typ = OBJECT_TYPE;
|
||||
if (t == Opcodes.INTEGER) {
|
||||
typ = Type.INT_TYPE;
|
||||
} else if (t == Opcodes.FLOAT) {
|
||||
typ = Type.FLOAT_TYPE;
|
||||
} else if (t == Opcodes.LONG) {
|
||||
typ = Type.LONG_TYPE;
|
||||
} else if (t == Opcodes.DOUBLE) {
|
||||
typ = Type.DOUBLE_TYPE;
|
||||
} else if (t instanceof String) {
|
||||
typ = Type.getObjectType((String) t);
|
||||
}
|
||||
setFrameLocal(remap(index, typ), t);
|
||||
}
|
||||
index += size;
|
||||
}
|
||||
|
||||
// removes TOP after long and double types as well as trailing TOPs
|
||||
|
||||
index = 0;
|
||||
number = 0;
|
||||
for (int i = 0; index < newLocals.length; ++i) {
|
||||
Object t = newLocals[index++];
|
||||
if (t != null && t != Opcodes.TOP) {
|
||||
newLocals[i] = t;
|
||||
number = i + 1;
|
||||
if (t == Opcodes.LONG || t == Opcodes.DOUBLE) {
|
||||
index += 1;
|
||||
}
|
||||
} else {
|
||||
newLocals[i] = Opcodes.TOP;
|
||||
}
|
||||
}
|
||||
|
||||
// visits remapped frame
|
||||
mv.visitFrame(type, number, newLocals, nStack, stack);
|
||||
|
||||
// restores original value of 'newLocals'
|
||||
newLocals = oldLocals;
|
||||
}
|
||||
|
||||
// -------------
|
||||
|
||||
/**
|
||||
* Creates a new local variable of the given type.
|
||||
*
|
||||
* @param type
|
||||
* the type of the local variable to be created.
|
||||
* @return the identifier of the newly created local variable.
|
||||
*/
|
||||
public int newLocal(final Type type) {
|
||||
Object t;
|
||||
switch (type.getSort()) {
|
||||
case Type.BOOLEAN:
|
||||
case Type.CHAR:
|
||||
case Type.BYTE:
|
||||
case Type.SHORT:
|
||||
case Type.INT:
|
||||
t = Opcodes.INTEGER;
|
||||
break;
|
||||
case Type.FLOAT:
|
||||
t = Opcodes.FLOAT;
|
||||
break;
|
||||
case Type.LONG:
|
||||
t = Opcodes.LONG;
|
||||
break;
|
||||
case Type.DOUBLE:
|
||||
t = Opcodes.DOUBLE;
|
||||
break;
|
||||
case Type.ARRAY:
|
||||
t = type.getDescriptor();
|
||||
break;
|
||||
// case Type.OBJECT:
|
||||
default:
|
||||
t = type.getInternalName();
|
||||
break;
|
||||
}
|
||||
int local = newLocalMapping(type);
|
||||
setLocalType(local, type);
|
||||
setFrameLocal(local, t);
|
||||
return local;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies subclasses that a new stack map frame is being visited. The
|
||||
* array argument contains the stack map frame types corresponding to the
|
||||
* local variables added with {@link #newLocal}. This method can update
|
||||
* these types in place for the stack map frame being visited. The default
|
||||
* implementation of this method does nothing, i.e. a local variable added
|
||||
* with {@link #newLocal} will have the same type in all stack map frames.
|
||||
* But this behavior is not always the desired one, for instance if a local
|
||||
* variable is added in the middle of a try/catch block: the frame for the
|
||||
* exception handler should have a TOP type for this new local.
|
||||
*
|
||||
* @param newLocals
|
||||
* the stack map frame types corresponding to the local variables
|
||||
* added with {@link #newLocal} (and null for the others). The
|
||||
* format of this array is the same as in
|
||||
* {@link MethodVisitor#visitFrame}, except that long and double
|
||||
* types use two slots. The types for the current stack map frame
|
||||
* must be updated in place in this array.
|
||||
*/
|
||||
protected void updateNewLocals(Object[] newLocals) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies subclasses that a local variable has been added or remapped. The
|
||||
* default implementation of this method does nothing.
|
||||
*
|
||||
* @param local
|
||||
* a local variable identifier, as returned by {@link #newLocal
|
||||
* newLocal()}.
|
||||
* @param type
|
||||
* the type of the value being stored in the local variable.
|
||||
*/
|
||||
protected void setLocalType(final int local, final Type type) {
|
||||
}
|
||||
|
||||
private void setFrameLocal(final int local, final Object type) {
|
||||
int l = newLocals.length;
|
||||
if (local >= l) {
|
||||
Object[] a = new Object[Math.max(2 * l, local + 1)];
|
||||
System.arraycopy(newLocals, 0, a, 0, l);
|
||||
newLocals = a;
|
||||
}
|
||||
newLocals[local] = type;
|
||||
}
|
||||
|
||||
private int remap(final int var, final Type type) {
|
||||
if (var + type.getSize() <= firstLocal) {
|
||||
return var;
|
||||
}
|
||||
int key = 2 * var + type.getSize() - 1;
|
||||
int size = mapping.length;
|
||||
if (key >= size) {
|
||||
int[] newMapping = new int[Math.max(2 * size, key + 1)];
|
||||
System.arraycopy(mapping, 0, newMapping, 0, size);
|
||||
mapping = newMapping;
|
||||
}
|
||||
int value = mapping[key];
|
||||
if (value == 0) {
|
||||
value = newLocalMapping(type);
|
||||
setLocalType(value, type);
|
||||
mapping[key] = value + 1;
|
||||
} else {
|
||||
value--;
|
||||
}
|
||||
if (value != var) {
|
||||
changed = true;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
protected int newLocalMapping(final Type type) {
|
||||
int local = nextLocal;
|
||||
nextLocal += type.getSize();
|
||||
return local;
|
||||
}
|
||||
}
|
||||
@@ -1,282 +0,0 @@
|
||||
/***
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 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.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.objectweb.asm.Type;
|
||||
|
||||
/**
|
||||
* A named method descriptor.
|
||||
*
|
||||
* @author Juozas Baliuka
|
||||
* @author Chris Nokleberg
|
||||
* @author Eric Bruneton
|
||||
*/
|
||||
public class Method {
|
||||
|
||||
/**
|
||||
* The method name.
|
||||
*/
|
||||
private final String name;
|
||||
|
||||
/**
|
||||
* The method descriptor.
|
||||
*/
|
||||
private final String desc;
|
||||
|
||||
/**
|
||||
* Maps primitive Java type names to their descriptors.
|
||||
*/
|
||||
private static final Map<String, String> DESCRIPTORS;
|
||||
|
||||
static {
|
||||
DESCRIPTORS = new HashMap<String, String>();
|
||||
DESCRIPTORS.put("void", "V");
|
||||
DESCRIPTORS.put("byte", "B");
|
||||
DESCRIPTORS.put("char", "C");
|
||||
DESCRIPTORS.put("double", "D");
|
||||
DESCRIPTORS.put("float", "F");
|
||||
DESCRIPTORS.put("int", "I");
|
||||
DESCRIPTORS.put("long", "J");
|
||||
DESCRIPTORS.put("short", "S");
|
||||
DESCRIPTORS.put("boolean", "Z");
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link org.objectweb.asm.commons.Method}.
|
||||
*
|
||||
* @param name
|
||||
* the method's name.
|
||||
* @param desc
|
||||
* the method's descriptor.
|
||||
*/
|
||||
public Method(final String name, final String desc) {
|
||||
this.name = name;
|
||||
this.desc = desc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link org.objectweb.asm.commons.Method}.
|
||||
*
|
||||
* @param name
|
||||
* the method's name.
|
||||
* @param returnType
|
||||
* the method's return type.
|
||||
* @param argumentTypes
|
||||
* the method's argument types.
|
||||
*/
|
||||
public Method(final String name, final Type returnType,
|
||||
final Type[] argumentTypes) {
|
||||
this(name, Type.getMethodDescriptor(returnType, argumentTypes));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link org.objectweb.asm.commons.Method}.
|
||||
*
|
||||
* @param m
|
||||
* a java.lang.reflect method descriptor
|
||||
* @return a {@link org.objectweb.asm.commons.Method} corresponding to the given Java method
|
||||
* declaration.
|
||||
*/
|
||||
public static Method getMethod(java.lang.reflect.Method m) {
|
||||
return new Method(m.getName(), Type.getMethodDescriptor(m));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link org.objectweb.asm.commons.Method}.
|
||||
*
|
||||
* @param c
|
||||
* a java.lang.reflect constructor descriptor
|
||||
* @return a {@link org.objectweb.asm.commons.Method} corresponding to the given Java constructor
|
||||
* declaration.
|
||||
*/
|
||||
public static Method getMethod(java.lang.reflect.Constructor<?> c) {
|
||||
return new Method("<init>", Type.getConstructorDescriptor(c));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link org.objectweb.asm.commons.Method} corresponding to the given Java method
|
||||
* declaration.
|
||||
*
|
||||
* @param method
|
||||
* a Java method declaration, without argument names, of the form
|
||||
* "returnType name (argumentType1, ... argumentTypeN)", where
|
||||
* the types are in plain Java (e.g. "int", "float",
|
||||
* "java.util.List", ...). Classes of the java.lang package can
|
||||
* be specified by their unqualified name; all other classes
|
||||
* names must be fully qualified.
|
||||
* @return a {@link org.objectweb.asm.commons.Method} corresponding to the given Java method
|
||||
* declaration.
|
||||
* @throws IllegalArgumentException
|
||||
* if <code>method</code> could not get parsed.
|
||||
*/
|
||||
public static Method getMethod(final String method)
|
||||
throws IllegalArgumentException {
|
||||
return getMethod(method, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link org.objectweb.asm.commons.Method} corresponding to the given Java method
|
||||
* declaration.
|
||||
*
|
||||
* @param method
|
||||
* a Java method declaration, without argument names, of the form
|
||||
* "returnType name (argumentType1, ... argumentTypeN)", where
|
||||
* the types are in plain Java (e.g. "int", "float",
|
||||
* "java.util.List", ...). Classes of the java.lang package may
|
||||
* be specified by their unqualified name, depending on the
|
||||
* defaultPackage argument; all other classes names must be fully
|
||||
* qualified.
|
||||
* @param defaultPackage
|
||||
* true if unqualified class names belong to the default package,
|
||||
* or false if they correspond to java.lang classes. For instance
|
||||
* "Object" means "Object" if this option is true, or
|
||||
* "java.lang.Object" otherwise.
|
||||
* @return a {@link org.objectweb.asm.commons.Method} corresponding to the given Java method
|
||||
* declaration.
|
||||
* @throws IllegalArgumentException
|
||||
* if <code>method</code> could not get parsed.
|
||||
*/
|
||||
public static Method getMethod(final String method,
|
||||
final boolean defaultPackage) throws IllegalArgumentException {
|
||||
int space = method.indexOf(' ');
|
||||
int start = method.indexOf('(', space) + 1;
|
||||
int end = method.indexOf(')', start);
|
||||
if (space == -1 || start == -1 || end == -1) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
String returnType = method.substring(0, space);
|
||||
String methodName = method.substring(space + 1, start - 1).trim();
|
||||
StringBuffer sb = new StringBuffer();
|
||||
sb.append('(');
|
||||
int p;
|
||||
do {
|
||||
String s;
|
||||
p = method.indexOf(',', start);
|
||||
if (p == -1) {
|
||||
s = map(method.substring(start, end).trim(), defaultPackage);
|
||||
} else {
|
||||
s = map(method.substring(start, p).trim(), defaultPackage);
|
||||
start = p + 1;
|
||||
}
|
||||
sb.append(s);
|
||||
} while (p != -1);
|
||||
sb.append(')');
|
||||
sb.append(map(returnType, defaultPackage));
|
||||
return new Method(methodName, sb.toString());
|
||||
}
|
||||
|
||||
private static String map(final String type, final boolean defaultPackage) {
|
||||
if ("".equals(type)) {
|
||||
return type;
|
||||
}
|
||||
|
||||
StringBuffer sb = new StringBuffer();
|
||||
int index = 0;
|
||||
while ((index = type.indexOf("[]", index) + 1) > 0) {
|
||||
sb.append('[');
|
||||
}
|
||||
|
||||
String t = type.substring(0, type.length() - sb.length() * 2);
|
||||
String desc = DESCRIPTORS.get(t);
|
||||
if (desc != null) {
|
||||
sb.append(desc);
|
||||
} else {
|
||||
sb.append('L');
|
||||
if (t.indexOf('.') < 0) {
|
||||
if (!defaultPackage) {
|
||||
sb.append("java/lang/");
|
||||
}
|
||||
sb.append(t);
|
||||
} else {
|
||||
sb.append(t.replace('.', '/'));
|
||||
}
|
||||
sb.append(';');
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the method described by this object.
|
||||
*
|
||||
* @return the name of the method described by this object.
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the descriptor of the method described by this object.
|
||||
*
|
||||
* @return the descriptor of the method described by this object.
|
||||
*/
|
||||
public String getDescriptor() {
|
||||
return desc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the return type of the method described by this object.
|
||||
*
|
||||
* @return the return type of the method described by this object.
|
||||
*/
|
||||
public Type getReturnType() {
|
||||
return Type.getReturnType(desc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the argument types of the method described by this object.
|
||||
*
|
||||
* @return the argument types of the method described by this object.
|
||||
*/
|
||||
public Type[] getArgumentTypes() {
|
||||
return Type.getArgumentTypes(desc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name + desc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (!(o instanceof Method)) {
|
||||
return false;
|
||||
}
|
||||
Method other = (Method) o;
|
||||
return name.equals(other.name) && desc.equals(other.desc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return name.hashCode() ^ desc.hashCode();
|
||||
}
|
||||
}
|
||||
@@ -1,223 +0,0 @@
|
||||
/***
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 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 org.objectweb.asm.Handle;
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.signature.SignatureReader;
|
||||
import org.objectweb.asm.signature.SignatureVisitor;
|
||||
import org.objectweb.asm.signature.SignatureWriter;
|
||||
|
||||
/**
|
||||
* A class responsible for remapping types and names. Subclasses can override
|
||||
* the following methods:
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@link #map(String)} - map type</li>
|
||||
* <li>{@link #mapFieldName(String, String, String)} - map field name</li>
|
||||
* <li>{@link #mapMethodName(String, String, String)} - map method name</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author Eugene Kuleshov
|
||||
*/
|
||||
public abstract class Remapper {
|
||||
|
||||
public String mapDesc(String desc) {
|
||||
Type t = Type.getType(desc);
|
||||
switch (t.getSort()) {
|
||||
case Type.ARRAY:
|
||||
String s = mapDesc(t.getElementType().getDescriptor());
|
||||
for (int i = 0; i < t.getDimensions(); ++i) {
|
||||
s = '[' + s;
|
||||
}
|
||||
return s;
|
||||
case Type.OBJECT:
|
||||
String newType = map(t.getInternalName());
|
||||
if (newType != null) {
|
||||
return 'L' + newType + ';';
|
||||
}
|
||||
}
|
||||
return desc;
|
||||
}
|
||||
|
||||
private Type mapType(Type t) {
|
||||
switch (t.getSort()) {
|
||||
case Type.ARRAY:
|
||||
String s = mapDesc(t.getElementType().getDescriptor());
|
||||
for (int i = 0; i < t.getDimensions(); ++i) {
|
||||
s = '[' + s;
|
||||
}
|
||||
return Type.getType(s);
|
||||
case Type.OBJECT:
|
||||
s = map(t.getInternalName());
|
||||
return s != null ? Type.getObjectType(s) : t;
|
||||
case Type.METHOD:
|
||||
return Type.getMethodType(mapMethodDesc(t.getDescriptor()));
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
public String mapType(String type) {
|
||||
if (type == null) {
|
||||
return null;
|
||||
}
|
||||
return mapType(Type.getObjectType(type)).getInternalName();
|
||||
}
|
||||
|
||||
public String[] mapTypes(String[] types) {
|
||||
String[] newTypes = null;
|
||||
boolean needMapping = false;
|
||||
for (int i = 0; i < types.length; i++) {
|
||||
String type = types[i];
|
||||
String newType = map(type);
|
||||
if (newType != null && newTypes == null) {
|
||||
newTypes = new String[types.length];
|
||||
if (i > 0) {
|
||||
System.arraycopy(types, 0, newTypes, 0, i);
|
||||
}
|
||||
needMapping = true;
|
||||
}
|
||||
if (needMapping) {
|
||||
newTypes[i] = newType == null ? type : newType;
|
||||
}
|
||||
}
|
||||
return needMapping ? newTypes : types;
|
||||
}
|
||||
|
||||
public String mapMethodDesc(String desc) {
|
||||
if ("()V".equals(desc)) {
|
||||
return desc;
|
||||
}
|
||||
|
||||
Type[] args = Type.getArgumentTypes(desc);
|
||||
StringBuffer s = new StringBuffer("(");
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
s.append(mapDesc(args[i].getDescriptor()));
|
||||
}
|
||||
Type returnType = Type.getReturnType(desc);
|
||||
if (returnType == Type.VOID_TYPE) {
|
||||
s.append(")V");
|
||||
return s.toString();
|
||||
}
|
||||
s.append(')').append(mapDesc(returnType.getDescriptor()));
|
||||
return s.toString();
|
||||
}
|
||||
|
||||
public Object mapValue(Object value) {
|
||||
if (value instanceof Type) {
|
||||
return mapType((Type) value);
|
||||
}
|
||||
if (value instanceof Handle) {
|
||||
Handle h = (Handle) value;
|
||||
return new Handle(h.getTag(), mapType(h.getOwner()), mapMethodName(
|
||||
h.getOwner(), h.getName(), h.getDesc()),
|
||||
mapMethodDesc(h.getDesc()));
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param typeSignature
|
||||
* true if signature is a FieldTypeSignature, such as the
|
||||
* signature parameter of the ClassVisitor.visitField or
|
||||
* MethodVisitor.visitLocalVariable methods
|
||||
*/
|
||||
public String mapSignature(String signature, boolean typeSignature) {
|
||||
if (signature == null) {
|
||||
return null;
|
||||
}
|
||||
SignatureReader r = new SignatureReader(signature);
|
||||
SignatureWriter w = new SignatureWriter();
|
||||
SignatureVisitor a = createRemappingSignatureAdapter(w);
|
||||
if (typeSignature) {
|
||||
r.acceptType(a);
|
||||
} else {
|
||||
r.accept(a);
|
||||
}
|
||||
return w.toString();
|
||||
}
|
||||
|
||||
protected SignatureVisitor createRemappingSignatureAdapter(
|
||||
SignatureVisitor v) {
|
||||
return new RemappingSignatureAdapter(v, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Map method name to the new name. Subclasses can override.
|
||||
*
|
||||
* @param owner
|
||||
* owner of the method.
|
||||
* @param name
|
||||
* name of the method.
|
||||
* @param desc
|
||||
* descriptor of the method.
|
||||
* @return new name of the method
|
||||
*/
|
||||
public String mapMethodName(String owner, String name, String desc) {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Map invokedynamic method name to the new name. Subclasses can override.
|
||||
*
|
||||
* @param name
|
||||
* name of the invokedynamic.
|
||||
* @param desc
|
||||
* descriptor of the invokedynamic.
|
||||
* @return new invokdynamic name.
|
||||
*/
|
||||
public String mapInvokeDynamicMethodName(String name, String desc) {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Map field name to the new name. Subclasses can override.
|
||||
*
|
||||
* @param owner
|
||||
* owner of the field.
|
||||
* @param name
|
||||
* name of the field
|
||||
* @param desc
|
||||
* descriptor of the field
|
||||
* @return new name of the field.
|
||||
*/
|
||||
public String mapFieldName(String owner, String name, String desc) {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Map type name to the new name. Subclasses can override.
|
||||
*/
|
||||
public String map(String typeName) {
|
||||
return typeName;
|
||||
}
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
/***
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 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 org.objectweb.asm.AnnotationVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
|
||||
/**
|
||||
* An {@link org.objectweb.asm.AnnotationVisitor} adapter for type remapping.
|
||||
*
|
||||
* @author Eugene Kuleshov
|
||||
*/
|
||||
public class RemappingAnnotationAdapter extends AnnotationVisitor {
|
||||
|
||||
protected final Remapper remapper;
|
||||
|
||||
public RemappingAnnotationAdapter(final AnnotationVisitor av,
|
||||
final Remapper remapper) {
|
||||
this(Opcodes.ASM4, av, remapper);
|
||||
}
|
||||
|
||||
protected RemappingAnnotationAdapter(final int api,
|
||||
final AnnotationVisitor av, final Remapper remapper) {
|
||||
super(api, av);
|
||||
this.remapper = remapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(String name, Object value) {
|
||||
av.visit(name, remapper.mapValue(value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnum(String name, String desc, String value) {
|
||||
av.visitEnum(name, remapper.mapDesc(desc), value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitAnnotation(String name, String desc) {
|
||||
AnnotationVisitor v = av.visitAnnotation(name, remapper.mapDesc(desc));
|
||||
return v == null ? null : (v == av ? this
|
||||
: new RemappingAnnotationAdapter(v, remapper));
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitArray(String name) {
|
||||
AnnotationVisitor v = av.visitArray(name);
|
||||
return v == null ? null : (v == av ? this
|
||||
: new RemappingAnnotationAdapter(v, remapper));
|
||||
}
|
||||
}
|
||||
@@ -1,126 +0,0 @@
|
||||
/***
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 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 org.objectweb.asm.AnnotationVisitor;
|
||||
import org.objectweb.asm.ClassVisitor;
|
||||
import org.objectweb.asm.FieldVisitor;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
|
||||
/**
|
||||
* A {@link org.objectweb.asm.ClassVisitor} for type remapping.
|
||||
*
|
||||
* @author Eugene Kuleshov
|
||||
*/
|
||||
public class RemappingClassAdapter extends ClassVisitor {
|
||||
|
||||
protected final Remapper remapper;
|
||||
|
||||
protected String className;
|
||||
|
||||
public RemappingClassAdapter(final ClassVisitor cv, final Remapper remapper) {
|
||||
this(Opcodes.ASM4, cv, remapper);
|
||||
}
|
||||
|
||||
protected RemappingClassAdapter(final int api, final ClassVisitor cv,
|
||||
final Remapper remapper) {
|
||||
super(api, cv);
|
||||
this.remapper = remapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(int version, int access, String name, String signature,
|
||||
String superName, String[] interfaces) {
|
||||
this.className = name;
|
||||
super.visit(version, access, remapper.mapType(name), remapper
|
||||
.mapSignature(signature, false), remapper.mapType(superName),
|
||||
interfaces == null ? null : remapper.mapTypes(interfaces));
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
|
||||
AnnotationVisitor av;
|
||||
av = super.visitAnnotation(remapper.mapDesc(desc), visible);
|
||||
return av == null ? null : createRemappingAnnotationAdapter(av);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FieldVisitor visitField(int access, String name, String desc,
|
||||
String signature, Object value) {
|
||||
FieldVisitor fv = super.visitField(access,
|
||||
remapper.mapFieldName(className, name, desc),
|
||||
remapper.mapDesc(desc), remapper.mapSignature(signature, true),
|
||||
remapper.mapValue(value));
|
||||
return fv == null ? null : createRemappingFieldAdapter(fv);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodVisitor visitMethod(int access, String name, String desc,
|
||||
String signature, String[] exceptions) {
|
||||
String newDesc = remapper.mapMethodDesc(desc);
|
||||
MethodVisitor mv = super.visitMethod(access, remapper.mapMethodName(
|
||||
className, name, desc), newDesc, remapper.mapSignature(
|
||||
signature, false),
|
||||
exceptions == null ? null : remapper.mapTypes(exceptions));
|
||||
return mv == null ? null : createRemappingMethodAdapter(access,
|
||||
newDesc, mv);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitInnerClass(String name, String outerName,
|
||||
String innerName, int access) {
|
||||
// TODO should innerName be changed?
|
||||
super.visitInnerClass(remapper.mapType(name), outerName == null ? null
|
||||
: remapper.mapType(outerName), innerName, access);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitOuterClass(String owner, String name, String desc) {
|
||||
super.visitOuterClass(remapper.mapType(owner), name == null ? null
|
||||
: remapper.mapMethodName(owner, name, desc),
|
||||
desc == null ? null : remapper.mapMethodDesc(desc));
|
||||
}
|
||||
|
||||
protected FieldVisitor createRemappingFieldAdapter(FieldVisitor fv) {
|
||||
return new RemappingFieldAdapter(fv, remapper);
|
||||
}
|
||||
|
||||
protected MethodVisitor createRemappingMethodAdapter(int access,
|
||||
String newDesc, MethodVisitor mv) {
|
||||
return new RemappingMethodAdapter(access, newDesc, mv, remapper);
|
||||
}
|
||||
|
||||
protected AnnotationVisitor createRemappingAnnotationAdapter(
|
||||
AnnotationVisitor av) {
|
||||
return new RemappingAnnotationAdapter(av, remapper);
|
||||
}
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
/***
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 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 org.objectweb.asm.AnnotationVisitor;
|
||||
import org.objectweb.asm.FieldVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
|
||||
/**
|
||||
* A {@link FieldVisitor} adapter for type remapping.
|
||||
*
|
||||
* @author Eugene Kuleshov
|
||||
*/
|
||||
public class RemappingFieldAdapter extends FieldVisitor {
|
||||
|
||||
private final Remapper remapper;
|
||||
|
||||
public RemappingFieldAdapter(final FieldVisitor fv, final Remapper remapper) {
|
||||
this(Opcodes.ASM4, fv, remapper);
|
||||
}
|
||||
|
||||
protected RemappingFieldAdapter(final int api, final FieldVisitor fv,
|
||||
final Remapper remapper) {
|
||||
super(api, fv);
|
||||
this.remapper = remapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
|
||||
AnnotationVisitor av = fv.visitAnnotation(remapper.mapDesc(desc),
|
||||
visible);
|
||||
return av == null ? null : new RemappingAnnotationAdapter(av, remapper);
|
||||
}
|
||||
}
|
||||
@@ -1,161 +0,0 @@
|
||||
/***
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 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 org.objectweb.asm.AnnotationVisitor;
|
||||
import org.objectweb.asm.Handle;
|
||||
import org.objectweb.asm.Label;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
|
||||
/**
|
||||
* A {@link org.objectweb.asm.commons.LocalVariablesSorter} for type mapping.
|
||||
*
|
||||
* @author Eugene Kuleshov
|
||||
*/
|
||||
public class RemappingMethodAdapter extends LocalVariablesSorter {
|
||||
|
||||
protected final Remapper remapper;
|
||||
|
||||
public RemappingMethodAdapter(final int access, final String desc,
|
||||
final MethodVisitor mv, final Remapper remapper) {
|
||||
this(Opcodes.ASM4, access, desc, mv, remapper);
|
||||
}
|
||||
|
||||
protected RemappingMethodAdapter(final int api, final int access,
|
||||
final String desc, final MethodVisitor mv, final Remapper remapper) {
|
||||
super(api, access, desc, mv);
|
||||
this.remapper = remapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitAnnotationDefault() {
|
||||
AnnotationVisitor av = mv.visitAnnotationDefault();
|
||||
return av == null ? av : new RemappingAnnotationAdapter(av, remapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
|
||||
AnnotationVisitor av = mv.visitAnnotation(remapper.mapDesc(desc),
|
||||
visible);
|
||||
return av == null ? av : new RemappingAnnotationAdapter(av, remapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitParameterAnnotation(int parameter,
|
||||
String desc, boolean visible) {
|
||||
AnnotationVisitor av = mv.visitParameterAnnotation(parameter,
|
||||
remapper.mapDesc(desc), visible);
|
||||
return av == null ? av : new RemappingAnnotationAdapter(av, remapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitFrame(int type, int nLocal, Object[] local, int nStack,
|
||||
Object[] stack) {
|
||||
super.visitFrame(type, nLocal, remapEntries(nLocal, local), nStack,
|
||||
remapEntries(nStack, stack));
|
||||
}
|
||||
|
||||
private Object[] remapEntries(int n, Object[] entries) {
|
||||
for (int i = 0; i < n; i++) {
|
||||
if (entries[i] instanceof String) {
|
||||
Object[] newEntries = new Object[n];
|
||||
if (i > 0) {
|
||||
System.arraycopy(entries, 0, newEntries, 0, i);
|
||||
}
|
||||
do {
|
||||
Object t = entries[i];
|
||||
newEntries[i++] = t instanceof String ? remapper
|
||||
.mapType((String) t) : t;
|
||||
} while (i < n);
|
||||
return newEntries;
|
||||
}
|
||||
}
|
||||
return entries;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitFieldInsn(int opcode, String owner, String name,
|
||||
String desc) {
|
||||
super.visitFieldInsn(opcode, remapper.mapType(owner),
|
||||
remapper.mapFieldName(owner, name, desc),
|
||||
remapper.mapDesc(desc));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMethodInsn(int opcode, String owner, String name,
|
||||
String desc) {
|
||||
super.visitMethodInsn(opcode, remapper.mapType(owner),
|
||||
remapper.mapMethodName(owner, name, desc),
|
||||
remapper.mapMethodDesc(desc));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitInvokeDynamicInsn(String name, String desc, Handle bsm,
|
||||
Object... bsmArgs) {
|
||||
for (int i = 0; i < bsmArgs.length; i++) {
|
||||
bsmArgs[i] = remapper.mapValue(bsmArgs[i]);
|
||||
}
|
||||
super.visitInvokeDynamicInsn(
|
||||
remapper.mapInvokeDynamicMethodName(name, desc),
|
||||
remapper.mapMethodDesc(desc), (Handle) remapper.mapValue(bsm),
|
||||
bsmArgs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTypeInsn(int opcode, String type) {
|
||||
super.visitTypeInsn(opcode, remapper.mapType(type));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLdcInsn(Object cst) {
|
||||
super.visitLdcInsn(remapper.mapValue(cst));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMultiANewArrayInsn(String desc, int dims) {
|
||||
super.visitMultiANewArrayInsn(remapper.mapDesc(desc), dims);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTryCatchBlock(Label start, Label end, Label handler,
|
||||
String type) {
|
||||
super.visitTryCatchBlock(start, end, handler, type == null ? null
|
||||
: remapper.mapType(type));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLocalVariable(String name, String desc, String signature,
|
||||
Label start, Label end, int index) {
|
||||
super.visitLocalVariable(name, remapper.mapDesc(desc),
|
||||
remapper.mapSignature(signature, true), start, end, index);
|
||||
}
|
||||
}
|
||||
@@ -1,153 +0,0 @@
|
||||
/***
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 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 org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.signature.SignatureVisitor;
|
||||
|
||||
/**
|
||||
* A {@link SignatureVisitor} adapter for type mapping.
|
||||
*
|
||||
* @author Eugene Kuleshov
|
||||
*/
|
||||
public class RemappingSignatureAdapter extends SignatureVisitor {
|
||||
|
||||
private final SignatureVisitor v;
|
||||
|
||||
private final Remapper remapper;
|
||||
|
||||
private String className;
|
||||
|
||||
public RemappingSignatureAdapter(final SignatureVisitor v,
|
||||
final Remapper remapper) {
|
||||
this(Opcodes.ASM4, v, remapper);
|
||||
}
|
||||
|
||||
protected RemappingSignatureAdapter(final int api,
|
||||
final SignatureVisitor v, final Remapper remapper) {
|
||||
super(api);
|
||||
this.v = v;
|
||||
this.remapper = remapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitClassType(String name) {
|
||||
className = name;
|
||||
v.visitClassType(remapper.mapType(name));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitInnerClassType(String name) {
|
||||
className = className + '$' + name;
|
||||
String remappedName = remapper.mapType(className);
|
||||
v.visitInnerClassType(remappedName.substring(remappedName
|
||||
.lastIndexOf('$') + 1));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitFormalTypeParameter(String name) {
|
||||
v.visitFormalTypeParameter(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTypeVariable(String name) {
|
||||
v.visitTypeVariable(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureVisitor visitArrayType() {
|
||||
v.visitArrayType();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitBaseType(char descriptor) {
|
||||
v.visitBaseType(descriptor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureVisitor visitClassBound() {
|
||||
v.visitClassBound();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureVisitor visitExceptionType() {
|
||||
v.visitExceptionType();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureVisitor visitInterface() {
|
||||
v.visitInterface();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureVisitor visitInterfaceBound() {
|
||||
v.visitInterfaceBound();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureVisitor visitParameterType() {
|
||||
v.visitParameterType();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureVisitor visitReturnType() {
|
||||
v.visitReturnType();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureVisitor visitSuperclass() {
|
||||
v.visitSuperclass();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTypeArgument() {
|
||||
v.visitTypeArgument();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureVisitor visitTypeArgument(char wildcard) {
|
||||
v.visitTypeArgument(wildcard);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
v.visitEnd();
|
||||
}
|
||||
}
|
||||
@@ -1,533 +0,0 @@
|
||||
/***
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 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.io.ByteArrayOutputStream;
|
||||
import java.io.DataOutput;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.security.MessageDigest;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.objectweb.asm.ClassVisitor;
|
||||
import org.objectweb.asm.FieldVisitor;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
|
||||
/**
|
||||
* A {@link org.objectweb.asm.ClassVisitor} that adds a serial version unique identifier to a
|
||||
* class if missing. Here is typical usage of this class:
|
||||
*
|
||||
* <pre>
|
||||
* ClassWriter cw = new ClassWriter(...);
|
||||
* ClassVisitor sv = new SerialVersionUIDAdder(cw);
|
||||
* ClassVisitor ca = new MyClassAdapter(sv);
|
||||
* new ClassReader(orginalClass).accept(ca, false);
|
||||
* </pre>
|
||||
*
|
||||
* The SVUID algorithm can be found <a href=
|
||||
* "http://java.sun.com/j2se/1.4.2/docs/guide/serialization/spec/class.html"
|
||||
* >http://java.sun.com/j2se/1.4.2/docs/guide/serialization/spec/class.html</a>:
|
||||
*
|
||||
* <pre>
|
||||
* The serialVersionUID is computed using the signature of a stream of bytes
|
||||
* that reflect the class definition. The National Institute of Standards and
|
||||
* Technology (NIST) Secure Hash Algorithm (SHA-1) is used to compute a
|
||||
* signature for the stream. The first two 32-bit quantities are used to form a
|
||||
* 64-bit hash. A java.lang.DataOutputStream is used to convert primitive data
|
||||
* types to a sequence of bytes. The values input to the stream are defined by
|
||||
* the Java Virtual Machine (VM) specification for classes.
|
||||
*
|
||||
* The sequence of items in the stream is as follows:
|
||||
*
|
||||
* 1. The class name written using UTF encoding.
|
||||
* 2. The class modifiers written as a 32-bit integer.
|
||||
* 3. The name of each interface sorted by name written using UTF encoding.
|
||||
* 4. For each field of the class sorted by field name (except private static
|
||||
* and private transient fields):
|
||||
* 1. The name of the field in UTF encoding.
|
||||
* 2. The modifiers of the field written as a 32-bit integer.
|
||||
* 3. The descriptor of the field in UTF encoding
|
||||
* 5. If a class initializer exists, write out the following:
|
||||
* 1. The name of the method, <clinit>, in UTF encoding.
|
||||
* 2. The modifier of the method, java.lang.reflect.Modifier.STATIC,
|
||||
* written as a 32-bit integer.
|
||||
* 3. The descriptor of the method, ()V, in UTF encoding.
|
||||
* 6. For each non-private constructor sorted by method name and signature:
|
||||
* 1. The name of the method, <init>, in UTF encoding.
|
||||
* 2. The modifiers of the method written as a 32-bit integer.
|
||||
* 3. The descriptor of the method in UTF encoding.
|
||||
* 7. For each non-private method sorted by method name and signature:
|
||||
* 1. The name of the method in UTF encoding.
|
||||
* 2. The modifiers of the method written as a 32-bit integer.
|
||||
* 3. The descriptor of the method in UTF encoding.
|
||||
* 8. The SHA-1 algorithm is executed on the stream of bytes produced by
|
||||
* DataOutputStream and produces five 32-bit values sha[0..4].
|
||||
*
|
||||
* 9. The hash value is assembled from the first and second 32-bit values of
|
||||
* the SHA-1 message digest. If the result of the message digest, the five
|
||||
* 32-bit words H0 H1 H2 H3 H4, is in an array of five int values named
|
||||
* sha, the hash value would be computed as follows:
|
||||
*
|
||||
* long hash = ((sha[0] >>> 24) & 0xFF) |
|
||||
* ((sha[0] >>> 16) & 0xFF) << 8 |
|
||||
* ((sha[0] >>> 8) & 0xFF) << 16 |
|
||||
* ((sha[0] >>> 0) & 0xFF) << 24 |
|
||||
* ((sha[1] >>> 24) & 0xFF) << 32 |
|
||||
* ((sha[1] >>> 16) & 0xFF) << 40 |
|
||||
* ((sha[1] >>> 8) & 0xFF) << 48 |
|
||||
* ((sha[1] >>> 0) & 0xFF) << 56;
|
||||
* </pre>
|
||||
*
|
||||
* @author Rajendra Inamdar, Vishal Vishnoi
|
||||
*/
|
||||
public class SerialVersionUIDAdder extends ClassVisitor {
|
||||
|
||||
/**
|
||||
* Flag that indicates if we need to compute SVUID.
|
||||
*/
|
||||
private boolean computeSVUID;
|
||||
|
||||
/**
|
||||
* Set to true if the class already has SVUID.
|
||||
*/
|
||||
private boolean hasSVUID;
|
||||
|
||||
/**
|
||||
* Classes access flags.
|
||||
*/
|
||||
private int access;
|
||||
|
||||
/**
|
||||
* Internal name of the class
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* Interfaces implemented by the class.
|
||||
*/
|
||||
private String[] interfaces;
|
||||
|
||||
/**
|
||||
* Collection of fields. (except private static and private transient
|
||||
* fields)
|
||||
*/
|
||||
private Collection<Item> svuidFields;
|
||||
|
||||
/**
|
||||
* Set to true if the class has static initializer.
|
||||
*/
|
||||
private boolean hasStaticInitializer;
|
||||
|
||||
/**
|
||||
* Collection of non-private constructors.
|
||||
*/
|
||||
private Collection<Item> svuidConstructors;
|
||||
|
||||
/**
|
||||
* Collection of non-private methods.
|
||||
*/
|
||||
private Collection<Item> svuidMethods;
|
||||
|
||||
/**
|
||||
* Creates a new {@link org.objectweb.asm.commons.SerialVersionUIDAdder}. <i>Subclasses must not use
|
||||
* this constructor</i>. Instead, they must use the
|
||||
* {@link #SerialVersionUIDAdder(int, org.objectweb.asm.ClassVisitor)} version.
|
||||
*
|
||||
* @param cv
|
||||
* a {@link org.objectweb.asm.ClassVisitor} to which this visitor will delegate
|
||||
* calls.
|
||||
*/
|
||||
public SerialVersionUIDAdder(final ClassVisitor cv) {
|
||||
this(Opcodes.ASM4, cv);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link org.objectweb.asm.commons.SerialVersionUIDAdder}.
|
||||
*
|
||||
* @param api
|
||||
* the ASM API version implemented by this visitor. Must be one
|
||||
* of {@link Opcodes#ASM4}.
|
||||
* @param cv
|
||||
* a {@link org.objectweb.asm.ClassVisitor} to which this visitor will delegate
|
||||
* calls.
|
||||
*/
|
||||
protected SerialVersionUIDAdder(final int api, final ClassVisitor cv) {
|
||||
super(api, cv);
|
||||
svuidFields = new ArrayList<Item>();
|
||||
svuidConstructors = new ArrayList<Item>();
|
||||
svuidMethods = new ArrayList<Item>();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Overriden methods
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
* Visit class header and get class name, access , and interfaces
|
||||
* information (step 1,2, and 3) for SVUID computation.
|
||||
*/
|
||||
@Override
|
||||
public void visit(final int version, final int access, final String name,
|
||||
final String signature, final String superName,
|
||||
final String[] interfaces) {
|
||||
computeSVUID = (access & Opcodes.ACC_INTERFACE) == 0;
|
||||
|
||||
if (computeSVUID) {
|
||||
this.name = name;
|
||||
this.access = access;
|
||||
this.interfaces = interfaces;
|
||||
}
|
||||
|
||||
super.visit(version, access, name, signature, superName, interfaces);
|
||||
}
|
||||
|
||||
/*
|
||||
* Visit the methods and get constructor and method information (step 5 and
|
||||
* 7). Also determine if there is a class initializer (step 6).
|
||||
*/
|
||||
@Override
|
||||
public MethodVisitor visitMethod(final int access, final String name,
|
||||
final String desc, final String signature, final String[] exceptions) {
|
||||
if (computeSVUID) {
|
||||
if ("<clinit>".equals(name)) {
|
||||
hasStaticInitializer = true;
|
||||
}
|
||||
/*
|
||||
* Remembers non private constructors and methods for SVUID
|
||||
* computation For constructor and method modifiers, only the
|
||||
* ACC_PUBLIC, ACC_PRIVATE, ACC_PROTECTED, ACC_STATIC, ACC_FINAL,
|
||||
* ACC_SYNCHRONIZED, ACC_NATIVE, ACC_ABSTRACT and ACC_STRICT flags
|
||||
* are used.
|
||||
*/
|
||||
int mods = access
|
||||
& (Opcodes.ACC_PUBLIC | Opcodes.ACC_PRIVATE
|
||||
| Opcodes.ACC_PROTECTED | Opcodes.ACC_STATIC
|
||||
| Opcodes.ACC_FINAL | Opcodes.ACC_SYNCHRONIZED
|
||||
| Opcodes.ACC_NATIVE | Opcodes.ACC_ABSTRACT | Opcodes.ACC_STRICT);
|
||||
|
||||
// all non private methods
|
||||
if ((access & Opcodes.ACC_PRIVATE) == 0) {
|
||||
if ("<init>".equals(name)) {
|
||||
svuidConstructors.add(new Item(name, mods, desc));
|
||||
} else if (!"<clinit>".equals(name)) {
|
||||
svuidMethods.add(new Item(name, mods, desc));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return super.visitMethod(access, name, desc, signature, exceptions);
|
||||
}
|
||||
|
||||
/*
|
||||
* Gets class field information for step 4 of the algorithm. Also determines
|
||||
* if the class already has a SVUID.
|
||||
*/
|
||||
@Override
|
||||
public FieldVisitor visitField(final int access, final String name,
|
||||
final String desc, final String signature, final Object value) {
|
||||
if (computeSVUID) {
|
||||
if ("serialVersionUID".equals(name)) {
|
||||
// since the class already has SVUID, we won't be computing it.
|
||||
computeSVUID = false;
|
||||
hasSVUID = true;
|
||||
}
|
||||
/*
|
||||
* Remember field for SVUID computation For field modifiers, only
|
||||
* the ACC_PUBLIC, ACC_PRIVATE, ACC_PROTECTED, ACC_STATIC,
|
||||
* ACC_FINAL, ACC_VOLATILE, and ACC_TRANSIENT flags are used when
|
||||
* computing serialVersionUID values.
|
||||
*/
|
||||
if ((access & Opcodes.ACC_PRIVATE) == 0
|
||||
|| (access & (Opcodes.ACC_STATIC | Opcodes.ACC_TRANSIENT)) == 0) {
|
||||
int mods = access
|
||||
& (Opcodes.ACC_PUBLIC | Opcodes.ACC_PRIVATE
|
||||
| Opcodes.ACC_PROTECTED | Opcodes.ACC_STATIC
|
||||
| Opcodes.ACC_FINAL | Opcodes.ACC_VOLATILE | Opcodes.ACC_TRANSIENT);
|
||||
svuidFields.add(new Item(name, mods, desc));
|
||||
}
|
||||
}
|
||||
|
||||
return super.visitField(access, name, desc, signature, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a bizarre special case. Nested classes (static classes declared
|
||||
* inside another class) that are protected have their access bit set to
|
||||
* public in their class files to deal with some odd reflection situation.
|
||||
* Our SVUID computation must do as the JVM does and ignore access bits in
|
||||
* the class file in favor of the access bits InnerClass attribute.
|
||||
*/
|
||||
@Override
|
||||
public void visitInnerClass(final String aname, final String outerName,
|
||||
final String innerName, final int attr_access) {
|
||||
if ((name != null) && name.equals(aname)) {
|
||||
this.access = attr_access;
|
||||
}
|
||||
super.visitInnerClass(aname, outerName, innerName, attr_access);
|
||||
}
|
||||
|
||||
/*
|
||||
* Add the SVUID if class doesn't have one
|
||||
*/
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
// compute SVUID and add it to the class
|
||||
if (computeSVUID && !hasSVUID) {
|
||||
try {
|
||||
addSVUID(computeSVUID());
|
||||
} catch (Throwable e) {
|
||||
throw new RuntimeException("Error while computing SVUID for "
|
||||
+ name, e);
|
||||
}
|
||||
}
|
||||
|
||||
super.visitEnd();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Utility methods
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns true if the class already has a SVUID field. The result of this
|
||||
* method is only valid when visitEnd is or has been called.
|
||||
*
|
||||
* @return true if the class already has a SVUID field.
|
||||
*/
|
||||
public boolean hasSVUID() {
|
||||
return hasSVUID;
|
||||
}
|
||||
|
||||
protected void addSVUID(long svuid) {
|
||||
FieldVisitor fv = super.visitField(Opcodes.ACC_FINAL
|
||||
+ Opcodes.ACC_STATIC, "serialVersionUID", "J", null, new Long(
|
||||
svuid));
|
||||
if (fv != null) {
|
||||
fv.visitEnd();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes and returns the value of SVUID.
|
||||
*
|
||||
* @return Returns the serial version UID
|
||||
* @throws java.io.IOException
|
||||
* if an I/O error occurs
|
||||
*/
|
||||
protected long computeSVUID() throws IOException {
|
||||
ByteArrayOutputStream bos;
|
||||
DataOutputStream dos = null;
|
||||
long svuid = 0;
|
||||
|
||||
try {
|
||||
bos = new ByteArrayOutputStream();
|
||||
dos = new DataOutputStream(bos);
|
||||
|
||||
/*
|
||||
* 1. The class name written using UTF encoding.
|
||||
*/
|
||||
dos.writeUTF(name.replace('/', '.'));
|
||||
|
||||
/*
|
||||
* 2. The class modifiers written as a 32-bit integer.
|
||||
*/
|
||||
dos.writeInt(access
|
||||
& (Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL
|
||||
| Opcodes.ACC_INTERFACE | Opcodes.ACC_ABSTRACT));
|
||||
|
||||
/*
|
||||
* 3. The name of each interface sorted by name written using UTF
|
||||
* encoding.
|
||||
*/
|
||||
Arrays.sort(interfaces);
|
||||
for (int i = 0; i < interfaces.length; i++) {
|
||||
dos.writeUTF(interfaces[i].replace('/', '.'));
|
||||
}
|
||||
|
||||
/*
|
||||
* 4. For each field of the class sorted by field name (except
|
||||
* private static and private transient fields):
|
||||
*
|
||||
* 1. The name of the field in UTF encoding. 2. The modifiers of the
|
||||
* field written as a 32-bit integer. 3. The descriptor of the field
|
||||
* in UTF encoding
|
||||
*
|
||||
* Note that field signatures are not dot separated. Method and
|
||||
* constructor signatures are dot separated. Go figure...
|
||||
*/
|
||||
writeItems(svuidFields, dos, false);
|
||||
|
||||
/*
|
||||
* 5. If a class initializer exists, write out the following: 1. The
|
||||
* name of the method, <clinit>, in UTF encoding. 2. The modifier of
|
||||
* the method, java.lang.reflect.Modifier.STATIC, written as a
|
||||
* 32-bit integer. 3. The descriptor of the method, ()V, in UTF
|
||||
* encoding.
|
||||
*/
|
||||
if (hasStaticInitializer) {
|
||||
dos.writeUTF("<clinit>");
|
||||
dos.writeInt(Opcodes.ACC_STATIC);
|
||||
dos.writeUTF("()V");
|
||||
} // if..
|
||||
|
||||
/*
|
||||
* 6. For each non-private constructor sorted by method name and
|
||||
* signature: 1. The name of the method, <init>, in UTF encoding. 2.
|
||||
* The modifiers of the method written as a 32-bit integer. 3. The
|
||||
* descriptor of the method in UTF encoding.
|
||||
*/
|
||||
writeItems(svuidConstructors, dos, true);
|
||||
|
||||
/*
|
||||
* 7. For each non-private method sorted by method name and
|
||||
* signature: 1. The name of the method in UTF encoding. 2. The
|
||||
* modifiers of the method written as a 32-bit integer. 3. The
|
||||
* descriptor of the method in UTF encoding.
|
||||
*/
|
||||
writeItems(svuidMethods, dos, true);
|
||||
|
||||
dos.flush();
|
||||
|
||||
/*
|
||||
* 8. The SHA-1 algorithm is executed on the stream of bytes
|
||||
* produced by DataOutputStream and produces five 32-bit values
|
||||
* sha[0..4].
|
||||
*/
|
||||
byte[] hashBytes = computeSHAdigest(bos.toByteArray());
|
||||
|
||||
/*
|
||||
* 9. The hash value is assembled from the first and second 32-bit
|
||||
* values of the SHA-1 message digest. If the result of the message
|
||||
* digest, the five 32-bit words H0 H1 H2 H3 H4, is in an array of
|
||||
* five int values named sha, the hash value would be computed as
|
||||
* follows:
|
||||
*
|
||||
* long hash = ((sha[0] >>> 24) & 0xFF) | ((sha[0] >>> 16) & 0xFF)
|
||||
* << 8 | ((sha[0] >>> 8) & 0xFF) << 16 | ((sha[0] >>> 0) & 0xFF) <<
|
||||
* 24 | ((sha[1] >>> 24) & 0xFF) << 32 | ((sha[1] >>> 16) & 0xFF) <<
|
||||
* 40 | ((sha[1] >>> 8) & 0xFF) << 48 | ((sha[1] >>> 0) & 0xFF) <<
|
||||
* 56;
|
||||
*/
|
||||
for (int i = Math.min(hashBytes.length, 8) - 1; i >= 0; i--) {
|
||||
svuid = (svuid << 8) | (hashBytes[i] & 0xFF);
|
||||
}
|
||||
} finally {
|
||||
// close the stream (if open)
|
||||
if (dos != null) {
|
||||
dos.close();
|
||||
}
|
||||
}
|
||||
|
||||
return svuid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the SHA-1 message digest of the given value.
|
||||
*
|
||||
* @param value
|
||||
* the value whose SHA message digest must be computed.
|
||||
* @return the SHA-1 message digest of the given value.
|
||||
*/
|
||||
protected byte[] computeSHAdigest(final byte[] value) {
|
||||
try {
|
||||
return MessageDigest.getInstance("SHA").digest(value);
|
||||
} catch (Exception e) {
|
||||
throw new UnsupportedOperationException(e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorts the items in the collection and writes it to the data output stream
|
||||
*
|
||||
* @param itemCollection
|
||||
* collection of items
|
||||
* @param dos
|
||||
* a <code>DataOutputStream</code> value
|
||||
* @param dotted
|
||||
* a <code>boolean</code> value
|
||||
* @exception java.io.IOException
|
||||
* if an error occurs
|
||||
*/
|
||||
private static void writeItems(final Collection<Item> itemCollection,
|
||||
final DataOutput dos, final boolean dotted) throws IOException {
|
||||
int size = itemCollection.size();
|
||||
Item[] items = itemCollection.toArray(new Item[size]);
|
||||
Arrays.sort(items);
|
||||
for (int i = 0; i < size; i++) {
|
||||
dos.writeUTF(items[i].name);
|
||||
dos.writeInt(items[i].access);
|
||||
dos.writeUTF(dotted ? items[i].desc.replace('/', '.')
|
||||
: items[i].desc);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Inner classes
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
private static class Item implements Comparable<Item> {
|
||||
|
||||
final String name;
|
||||
|
||||
final int access;
|
||||
|
||||
final String desc;
|
||||
|
||||
Item(final String name, final int access, final String desc) {
|
||||
this.name = name;
|
||||
this.access = access;
|
||||
this.desc = desc;
|
||||
}
|
||||
|
||||
public int compareTo(final Item other) {
|
||||
int retVal = name.compareTo(other.name);
|
||||
if (retVal == 0) {
|
||||
retVal = desc.compareTo(other.desc);
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (o instanceof Item) {
|
||||
return compareTo((Item) o) == 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return (name + desc).hashCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
/***
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 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.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A {@link org.objectweb.asm.commons.Remapper} using a {@link java.util.Map} to define its mapping.
|
||||
*
|
||||
* @author Eugene Kuleshov
|
||||
*/
|
||||
public class SimpleRemapper extends Remapper {
|
||||
|
||||
private final Map<String, String> mapping;
|
||||
|
||||
public SimpleRemapper(Map<String, String> mapping) {
|
||||
this.mapping = mapping;
|
||||
}
|
||||
|
||||
public SimpleRemapper(String oldName, String newName) {
|
||||
this.mapping = Collections.singletonMap(oldName, newName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String mapMethodName(String owner, String name, String desc) {
|
||||
String s = map(owner + '.' + name + desc);
|
||||
return s == null ? name : s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String mapFieldName(String owner, String name, String desc) {
|
||||
String s = map(owner + '.' + name);
|
||||
return s == null ? name : s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String map(String key) {
|
||||
return mapping.get(key);
|
||||
}
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
/***
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 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 org.objectweb.asm.ClassVisitor;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
|
||||
/**
|
||||
* A {@link org.objectweb.asm.ClassVisitor} that merges clinit methods into a single one.
|
||||
*
|
||||
* @author Eric Bruneton
|
||||
*/
|
||||
public class StaticInitMerger extends ClassVisitor {
|
||||
|
||||
private String name;
|
||||
|
||||
private MethodVisitor clinit;
|
||||
|
||||
private final String prefix;
|
||||
|
||||
private int counter;
|
||||
|
||||
public StaticInitMerger(final String prefix, final ClassVisitor cv) {
|
||||
this(Opcodes.ASM4, prefix, cv);
|
||||
}
|
||||
|
||||
protected StaticInitMerger(final int api, final String prefix,
|
||||
final ClassVisitor cv) {
|
||||
super(api, cv);
|
||||
this.prefix = prefix;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(final int version, final int access, final String name,
|
||||
final String signature, final String superName,
|
||||
final String[] interfaces) {
|
||||
cv.visit(version, access, name, signature, superName, interfaces);
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodVisitor visitMethod(final int access, final String name,
|
||||
final String desc, final String signature, final String[] exceptions) {
|
||||
MethodVisitor mv;
|
||||
if ("<clinit>".equals(name)) {
|
||||
int a = Opcodes.ACC_PRIVATE + Opcodes.ACC_STATIC;
|
||||
String n = prefix + counter++;
|
||||
mv = cv.visitMethod(a, n, desc, signature, exceptions);
|
||||
|
||||
if (clinit == null) {
|
||||
clinit = cv.visitMethod(a, name, desc, null, null);
|
||||
}
|
||||
clinit.visitMethodInsn(Opcodes.INVOKESTATIC, this.name, n, desc);
|
||||
} else {
|
||||
mv = cv.visitMethod(access, name, desc, signature, exceptions);
|
||||
}
|
||||
return mv;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
if (clinit != null) {
|
||||
clinit.visitInsn(Opcodes.RETURN);
|
||||
clinit.visitMaxs(0, 0);
|
||||
}
|
||||
cv.visitEnd();
|
||||
}
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
/***
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 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 org.objectweb.asm.Label;
|
||||
|
||||
/**
|
||||
* A code generator for switch statements.
|
||||
*
|
||||
* @author Juozas Baliuka
|
||||
* @author Chris Nokleberg
|
||||
* @author Eric Bruneton
|
||||
*/
|
||||
public interface TableSwitchGenerator {
|
||||
|
||||
/**
|
||||
* Generates the code for a switch case.
|
||||
*
|
||||
* @param key
|
||||
* the switch case key.
|
||||
* @param end
|
||||
* a label that corresponds to the end of the switch statement.
|
||||
*/
|
||||
void generateCase(int key, Label end);
|
||||
|
||||
/**
|
||||
* Generates the code for the default switch case.
|
||||
*/
|
||||
void generateDefault();
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
/***
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 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.Collections;
|
||||
import java.util.Comparator;
|
||||
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.tree.MethodNode;
|
||||
import org.objectweb.asm.tree.TryCatchBlockNode;
|
||||
|
||||
/**
|
||||
* A {@link MethodVisitor} adapter to sort the exception handlers. The handlers
|
||||
* are sorted in a method innermost-to-outermost. This allows the programmer to
|
||||
* add handlers without worrying about ordering them correctly with respect to
|
||||
* existing, in-code handlers.
|
||||
*
|
||||
* Behavior is only defined for properly-nested handlers. If any "try" blocks
|
||||
* overlap (something that isn't possible in Java code) then this may not do
|
||||
* what you want. In fact, this adapter just sorts by the length of the "try"
|
||||
* block, taking advantage of the fact that a given try block must be larger
|
||||
* than any block it contains).
|
||||
*
|
||||
* @author Adrian Sampson
|
||||
*/
|
||||
public class TryCatchBlockSorter extends MethodNode {
|
||||
|
||||
public TryCatchBlockSorter(final MethodVisitor mv, final int access,
|
||||
final String name, final String desc, final String signature,
|
||||
final String[] exceptions) {
|
||||
this(Opcodes.ASM4, mv, access, name, desc, signature, exceptions);
|
||||
}
|
||||
|
||||
protected TryCatchBlockSorter(final int api, final MethodVisitor mv,
|
||||
final int access, final String name, final String desc,
|
||||
final String signature, final String[] exceptions) {
|
||||
super(api, access, name, desc, signature, exceptions);
|
||||
this.mv = mv;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
// Compares TryCatchBlockNodes by the length of their "try" block.
|
||||
Comparator<TryCatchBlockNode> comp = new Comparator<TryCatchBlockNode>() {
|
||||
|
||||
public int compare(TryCatchBlockNode t1, TryCatchBlockNode t2) {
|
||||
int len1 = blockLength(t1);
|
||||
int len2 = blockLength(t2);
|
||||
return len1 - len2;
|
||||
}
|
||||
|
||||
private int blockLength(TryCatchBlockNode block) {
|
||||
int startidx = instructions.indexOf(block.start);
|
||||
int endidx = instructions.indexOf(block.end);
|
||||
return endidx - startidx;
|
||||
}
|
||||
};
|
||||
Collections.sort(tryCatchBlocks, comp);
|
||||
if (mv != null) {
|
||||
accept(mv);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
<html>
|
||||
<!--
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 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.
|
||||
-->
|
||||
<body>
|
||||
Provides some useful class and method adapters. <i>The preferred way of using
|
||||
these adapters is by chaining them together and to custom adapters (instead of
|
||||
inheriting from them)</i>. Indeed this approach provides more combination
|
||||
possibilities than inheritance. For instance, suppose you want to implement an
|
||||
adapter MyAdapter than needs sorted local variables and intermediate stack map
|
||||
frame values taking into account the local variables sort. By using inheritance,
|
||||
this would require MyAdapter to extend AnalyzerAdapter, itself extending
|
||||
LocalVariablesSorter. But AnalyzerAdapter is not a subclass of
|
||||
LocalVariablesSorter, so this is not possible. On the contrary, by using
|
||||
delegation, you can make LocalVariablesSorter delegate to AnalyzerAdapter,
|
||||
itself delegating to MyAdapter. In this case AnalyzerAdapter computes
|
||||
intermediate frames based on the output of LocalVariablesSorter, and MyAdapter
|
||||
can add new locals by calling the newLocal method on LocalVariablesSorter, and
|
||||
can get the stack map frame state before each instruction by reading the locals
|
||||
and stack fields in AnalyzerAdapter (this requires references from MyAdapter
|
||||
back to LocalVariablesSorter and AnalyzerAdapter).
|
||||
</body>
|
||||
@@ -1,550 +0,0 @@
|
||||
/***
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 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.tree.analysis;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.tree.AbstractInsnNode;
|
||||
import org.objectweb.asm.tree.IincInsnNode;
|
||||
import org.objectweb.asm.tree.InsnList;
|
||||
import org.objectweb.asm.tree.JumpInsnNode;
|
||||
import org.objectweb.asm.tree.LabelNode;
|
||||
import org.objectweb.asm.tree.LookupSwitchInsnNode;
|
||||
import org.objectweb.asm.tree.MethodNode;
|
||||
import org.objectweb.asm.tree.TableSwitchInsnNode;
|
||||
import org.objectweb.asm.tree.TryCatchBlockNode;
|
||||
import org.objectweb.asm.tree.VarInsnNode;
|
||||
|
||||
/**
|
||||
* A semantic bytecode analyzer. <i>This class does not fully check that JSR and
|
||||
* RET instructions are valid.</i>
|
||||
*
|
||||
* @param <V>
|
||||
* type of the Value used for the analysis.
|
||||
*
|
||||
* @author Eric Bruneton
|
||||
*/
|
||||
public class Analyzer<V extends Value> implements Opcodes {
|
||||
|
||||
private final Interpreter<V> interpreter;
|
||||
|
||||
private int n;
|
||||
|
||||
private InsnList insns;
|
||||
|
||||
private List<TryCatchBlockNode>[] handlers;
|
||||
|
||||
private Frame<V>[] frames;
|
||||
|
||||
private Subroutine[] subroutines;
|
||||
|
||||
private boolean[] queued;
|
||||
|
||||
private int[] queue;
|
||||
|
||||
private int top;
|
||||
|
||||
/**
|
||||
* Constructs a new {@link org.objectweb.asm.tree.analysis.Analyzer}.
|
||||
*
|
||||
* @param interpreter
|
||||
* the interpreter to be used to symbolically interpret the
|
||||
* bytecode instructions.
|
||||
*/
|
||||
public Analyzer(final Interpreter<V> interpreter) {
|
||||
this.interpreter = interpreter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Analyzes the given method.
|
||||
*
|
||||
* @param owner
|
||||
* the internal name of the class to which the method belongs.
|
||||
* @param m
|
||||
* the method to be analyzed.
|
||||
* @return the symbolic state of the execution stack frame at each bytecode
|
||||
* instruction of the method. The size of the returned array is
|
||||
* equal to the number of instructions (and labels) of the method. A
|
||||
* given frame is <tt>null</tt> if and only if the corresponding
|
||||
* instruction cannot be reached (dead code).
|
||||
* @throws AnalyzerException
|
||||
* if a problem occurs during the analysis.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public Frame<V>[] analyze(final String owner, final MethodNode m)
|
||||
throws AnalyzerException {
|
||||
if ((m.access & (ACC_ABSTRACT | ACC_NATIVE)) != 0) {
|
||||
frames = (Frame<V>[]) new Frame<?>[0];
|
||||
return frames;
|
||||
}
|
||||
n = m.instructions.size();
|
||||
insns = m.instructions;
|
||||
handlers = (List<TryCatchBlockNode>[]) new List<?>[n];
|
||||
frames = (Frame<V>[]) new Frame<?>[n];
|
||||
subroutines = new Subroutine[n];
|
||||
queued = new boolean[n];
|
||||
queue = new int[n];
|
||||
top = 0;
|
||||
|
||||
// computes exception handlers for each instruction
|
||||
for (int i = 0; i < m.tryCatchBlocks.size(); ++i) {
|
||||
TryCatchBlockNode tcb = m.tryCatchBlocks.get(i);
|
||||
int begin = insns.indexOf(tcb.start);
|
||||
int end = insns.indexOf(tcb.end);
|
||||
for (int j = begin; j < end; ++j) {
|
||||
List<TryCatchBlockNode> insnHandlers = handlers[j];
|
||||
if (insnHandlers == null) {
|
||||
insnHandlers = new ArrayList<TryCatchBlockNode>();
|
||||
handlers[j] = insnHandlers;
|
||||
}
|
||||
insnHandlers.add(tcb);
|
||||
}
|
||||
}
|
||||
|
||||
// computes the subroutine for each instruction:
|
||||
Subroutine main = new Subroutine(null, m.maxLocals, null);
|
||||
List<AbstractInsnNode> subroutineCalls = new ArrayList<AbstractInsnNode>();
|
||||
Map<LabelNode, Subroutine> subroutineHeads = new HashMap<LabelNode, Subroutine>();
|
||||
findSubroutine(0, main, subroutineCalls);
|
||||
while (!subroutineCalls.isEmpty()) {
|
||||
JumpInsnNode jsr = (JumpInsnNode) subroutineCalls.remove(0);
|
||||
Subroutine sub = subroutineHeads.get(jsr.label);
|
||||
if (sub == null) {
|
||||
sub = new Subroutine(jsr.label, m.maxLocals, jsr);
|
||||
subroutineHeads.put(jsr.label, sub);
|
||||
findSubroutine(insns.indexOf(jsr.label), sub, subroutineCalls);
|
||||
} else {
|
||||
sub.callers.add(jsr);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < n; ++i) {
|
||||
if (subroutines[i] != null && subroutines[i].start == null) {
|
||||
subroutines[i] = null;
|
||||
}
|
||||
}
|
||||
|
||||
// initializes the data structures for the control flow analysis
|
||||
Frame<V> current = newFrame(m.maxLocals, m.maxStack);
|
||||
Frame<V> handler = newFrame(m.maxLocals, m.maxStack);
|
||||
current.setReturn(interpreter.newValue(Type.getReturnType(m.desc)));
|
||||
Type[] args = Type.getArgumentTypes(m.desc);
|
||||
int local = 0;
|
||||
if ((m.access & ACC_STATIC) == 0) {
|
||||
Type ctype = Type.getObjectType(owner);
|
||||
current.setLocal(local++, interpreter.newValue(ctype));
|
||||
}
|
||||
for (int i = 0; i < args.length; ++i) {
|
||||
current.setLocal(local++, interpreter.newValue(args[i]));
|
||||
if (args[i].getSize() == 2) {
|
||||
current.setLocal(local++, interpreter.newValue(null));
|
||||
}
|
||||
}
|
||||
while (local < m.maxLocals) {
|
||||
current.setLocal(local++, interpreter.newValue(null));
|
||||
}
|
||||
merge(0, current, null);
|
||||
|
||||
init(owner, m);
|
||||
|
||||
// control flow analysis
|
||||
while (top > 0) {
|
||||
int insn = queue[--top];
|
||||
Frame<V> f = frames[insn];
|
||||
Subroutine subroutine = subroutines[insn];
|
||||
queued[insn] = false;
|
||||
|
||||
AbstractInsnNode insnNode = null;
|
||||
try {
|
||||
insnNode = m.instructions.get(insn);
|
||||
int insnOpcode = insnNode.getOpcode();
|
||||
int insnType = insnNode.getType();
|
||||
|
||||
if (insnType == AbstractInsnNode.LABEL
|
||||
|| insnType == AbstractInsnNode.LINE
|
||||
|| insnType == AbstractInsnNode.FRAME) {
|
||||
merge(insn + 1, f, subroutine);
|
||||
newControlFlowEdge(insn, insn + 1);
|
||||
} else {
|
||||
current.init(f).execute(insnNode, interpreter);
|
||||
subroutine = subroutine == null ? null : subroutine.copy();
|
||||
|
||||
if (insnNode instanceof JumpInsnNode) {
|
||||
JumpInsnNode j = (JumpInsnNode) insnNode;
|
||||
if (insnOpcode != GOTO && insnOpcode != JSR) {
|
||||
merge(insn + 1, current, subroutine);
|
||||
newControlFlowEdge(insn, insn + 1);
|
||||
}
|
||||
int jump = insns.indexOf(j.label);
|
||||
if (insnOpcode == JSR) {
|
||||
merge(jump, current, new Subroutine(j.label,
|
||||
m.maxLocals, j));
|
||||
} else {
|
||||
merge(jump, current, subroutine);
|
||||
}
|
||||
newControlFlowEdge(insn, jump);
|
||||
} else if (insnNode instanceof LookupSwitchInsnNode) {
|
||||
LookupSwitchInsnNode lsi = (LookupSwitchInsnNode) insnNode;
|
||||
int jump = insns.indexOf(lsi.dflt);
|
||||
merge(jump, current, subroutine);
|
||||
newControlFlowEdge(insn, jump);
|
||||
for (int j = 0; j < lsi.labels.size(); ++j) {
|
||||
LabelNode label = lsi.labels.get(j);
|
||||
jump = insns.indexOf(label);
|
||||
merge(jump, current, subroutine);
|
||||
newControlFlowEdge(insn, jump);
|
||||
}
|
||||
} else if (insnNode instanceof TableSwitchInsnNode) {
|
||||
TableSwitchInsnNode tsi = (TableSwitchInsnNode) insnNode;
|
||||
int jump = insns.indexOf(tsi.dflt);
|
||||
merge(jump, current, subroutine);
|
||||
newControlFlowEdge(insn, jump);
|
||||
for (int j = 0; j < tsi.labels.size(); ++j) {
|
||||
LabelNode label = tsi.labels.get(j);
|
||||
jump = insns.indexOf(label);
|
||||
merge(jump, current, subroutine);
|
||||
newControlFlowEdge(insn, jump);
|
||||
}
|
||||
} else if (insnOpcode == RET) {
|
||||
if (subroutine == null) {
|
||||
throw new AnalyzerException(insnNode,
|
||||
"RET instruction outside of a sub routine");
|
||||
}
|
||||
for (int i = 0; i < subroutine.callers.size(); ++i) {
|
||||
JumpInsnNode caller = subroutine.callers.get(i);
|
||||
int call = insns.indexOf(caller);
|
||||
if (frames[call] != null) {
|
||||
merge(call + 1, frames[call], current,
|
||||
subroutines[call], subroutine.access);
|
||||
newControlFlowEdge(insn, call + 1);
|
||||
}
|
||||
}
|
||||
} else if (insnOpcode != ATHROW
|
||||
&& (insnOpcode < IRETURN || insnOpcode > RETURN)) {
|
||||
if (subroutine != null) {
|
||||
if (insnNode instanceof VarInsnNode) {
|
||||
int var = ((VarInsnNode) insnNode).var;
|
||||
subroutine.access[var] = true;
|
||||
if (insnOpcode == LLOAD || insnOpcode == DLOAD
|
||||
|| insnOpcode == LSTORE
|
||||
|| insnOpcode == DSTORE) {
|
||||
subroutine.access[var + 1] = true;
|
||||
}
|
||||
} else if (insnNode instanceof IincInsnNode) {
|
||||
int var = ((IincInsnNode) insnNode).var;
|
||||
subroutine.access[var] = true;
|
||||
}
|
||||
}
|
||||
merge(insn + 1, current, subroutine);
|
||||
newControlFlowEdge(insn, insn + 1);
|
||||
}
|
||||
}
|
||||
|
||||
List<TryCatchBlockNode> insnHandlers = handlers[insn];
|
||||
if (insnHandlers != null) {
|
||||
for (int i = 0; i < insnHandlers.size(); ++i) {
|
||||
TryCatchBlockNode tcb = insnHandlers.get(i);
|
||||
Type type;
|
||||
if (tcb.type == null) {
|
||||
type = Type.getObjectType("java/lang/Throwable");
|
||||
} else {
|
||||
type = Type.getObjectType(tcb.type);
|
||||
}
|
||||
int jump = insns.indexOf(tcb.handler);
|
||||
if (newControlFlowExceptionEdge(insn, tcb)) {
|
||||
handler.init(f);
|
||||
handler.clearStack();
|
||||
handler.push(interpreter.newValue(type));
|
||||
merge(jump, handler, subroutine);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (AnalyzerException e) {
|
||||
throw new AnalyzerException(e.node, "Error at instruction "
|
||||
+ insn + ": " + e.getMessage(), e);
|
||||
} catch (Exception e) {
|
||||
throw new AnalyzerException(insnNode, "Error at instruction "
|
||||
+ insn + ": " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
return frames;
|
||||
}
|
||||
|
||||
private void findSubroutine(int insn, final Subroutine sub,
|
||||
final List<AbstractInsnNode> calls) throws AnalyzerException {
|
||||
while (true) {
|
||||
if (insn < 0 || insn >= n) {
|
||||
throw new AnalyzerException(null,
|
||||
"Execution can fall off end of the code");
|
||||
}
|
||||
if (subroutines[insn] != null) {
|
||||
return;
|
||||
}
|
||||
subroutines[insn] = sub.copy();
|
||||
AbstractInsnNode node = insns.get(insn);
|
||||
|
||||
// calls findSubroutine recursively on normal successors
|
||||
if (node instanceof JumpInsnNode) {
|
||||
if (node.getOpcode() == JSR) {
|
||||
// do not follow a JSR, it leads to another subroutine!
|
||||
calls.add(node);
|
||||
} else {
|
||||
JumpInsnNode jnode = (JumpInsnNode) node;
|
||||
findSubroutine(insns.indexOf(jnode.label), sub, calls);
|
||||
}
|
||||
} else if (node instanceof TableSwitchInsnNode) {
|
||||
TableSwitchInsnNode tsnode = (TableSwitchInsnNode) node;
|
||||
findSubroutine(insns.indexOf(tsnode.dflt), sub, calls);
|
||||
for (int i = tsnode.labels.size() - 1; i >= 0; --i) {
|
||||
LabelNode l = tsnode.labels.get(i);
|
||||
findSubroutine(insns.indexOf(l), sub, calls);
|
||||
}
|
||||
} else if (node instanceof LookupSwitchInsnNode) {
|
||||
LookupSwitchInsnNode lsnode = (LookupSwitchInsnNode) node;
|
||||
findSubroutine(insns.indexOf(lsnode.dflt), sub, calls);
|
||||
for (int i = lsnode.labels.size() - 1; i >= 0; --i) {
|
||||
LabelNode l = lsnode.labels.get(i);
|
||||
findSubroutine(insns.indexOf(l), sub, calls);
|
||||
}
|
||||
}
|
||||
|
||||
// calls findSubroutine recursively on exception handler successors
|
||||
List<TryCatchBlockNode> insnHandlers = handlers[insn];
|
||||
if (insnHandlers != null) {
|
||||
for (int i = 0; i < insnHandlers.size(); ++i) {
|
||||
TryCatchBlockNode tcb = insnHandlers.get(i);
|
||||
findSubroutine(insns.indexOf(tcb.handler), sub, calls);
|
||||
}
|
||||
}
|
||||
|
||||
// if insn does not falls through to the next instruction, return.
|
||||
switch (node.getOpcode()) {
|
||||
case GOTO:
|
||||
case RET:
|
||||
case TABLESWITCH:
|
||||
case LOOKUPSWITCH:
|
||||
case IRETURN:
|
||||
case LRETURN:
|
||||
case FRETURN:
|
||||
case DRETURN:
|
||||
case ARETURN:
|
||||
case RETURN:
|
||||
case ATHROW:
|
||||
return;
|
||||
}
|
||||
insn++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the symbolic stack frame for each instruction of the last
|
||||
* recently analyzed method.
|
||||
*
|
||||
* @return the symbolic state of the execution stack frame at each bytecode
|
||||
* instruction of the method. The size of the returned array is
|
||||
* equal to the number of instructions (and labels) of the method. A
|
||||
* given frame is <tt>null</tt> if the corresponding instruction
|
||||
* cannot be reached, or if an error occured during the analysis of
|
||||
* the method.
|
||||
*/
|
||||
public Frame<V>[] getFrames() {
|
||||
return frames;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the exception handlers for the given instruction.
|
||||
*
|
||||
* @param insn
|
||||
* the index of an instruction of the last recently analyzed
|
||||
* method.
|
||||
* @return a list of {@link TryCatchBlockNode} objects.
|
||||
*/
|
||||
public List<TryCatchBlockNode> getHandlers(final int insn) {
|
||||
return handlers[insn];
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes this analyzer. This method is called just before the
|
||||
* execution of control flow analysis loop in #analyze. The default
|
||||
* implementation of this method does nothing.
|
||||
*
|
||||
* @param owner
|
||||
* the internal name of the class to which the method belongs.
|
||||
* @param m
|
||||
* the method to be analyzed.
|
||||
* @throws AnalyzerException
|
||||
* if a problem occurs.
|
||||
*/
|
||||
protected void init(String owner, MethodNode m) throws AnalyzerException {
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new frame with the given size.
|
||||
*
|
||||
* @param nLocals
|
||||
* the maximum number of local variables of the frame.
|
||||
* @param nStack
|
||||
* the maximum stack size of the frame.
|
||||
* @return the created frame.
|
||||
*/
|
||||
protected Frame<V> newFrame(final int nLocals, final int nStack) {
|
||||
return new Frame<V>(nLocals, nStack);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new frame that is identical to the given frame.
|
||||
*
|
||||
* @param src
|
||||
* a frame.
|
||||
* @return the created frame.
|
||||
*/
|
||||
protected Frame<V> newFrame(final Frame<? extends V> src) {
|
||||
return new Frame<V>(src);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a control flow graph edge. The default implementation of this
|
||||
* method does nothing. It can be overriden in order to construct the
|
||||
* control flow graph of a method (this method is called by the
|
||||
* {@link #analyze analyze} method during its visit of the method's code).
|
||||
*
|
||||
* @param insn
|
||||
* an instruction index.
|
||||
* @param successor
|
||||
* index of a successor instruction.
|
||||
*/
|
||||
protected void newControlFlowEdge(final int insn, final int successor) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a control flow graph edge corresponding to an exception handler.
|
||||
* The default implementation of this method does nothing. It can be
|
||||
* overridden in order to construct the control flow graph of a method (this
|
||||
* method is called by the {@link #analyze analyze} method during its visit
|
||||
* of the method's code).
|
||||
*
|
||||
* @param insn
|
||||
* an instruction index.
|
||||
* @param successor
|
||||
* index of a successor instruction.
|
||||
* @return true if this edge must be considered in the data flow analysis
|
||||
* performed by this analyzer, or false otherwise. The default
|
||||
* implementation of this method always returns true.
|
||||
*/
|
||||
protected boolean newControlFlowExceptionEdge(final int insn,
|
||||
final int successor) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a control flow graph edge corresponding to an exception handler.
|
||||
* The default implementation of this method delegates to
|
||||
* {@link #newControlFlowExceptionEdge(int, int)
|
||||
* newControlFlowExceptionEdge(int, int)}. It can be overridden in order to
|
||||
* construct the control flow graph of a method (this method is called by
|
||||
* the {@link #analyze analyze} method during its visit of the method's
|
||||
* code).
|
||||
*
|
||||
* @param insn
|
||||
* an instruction index.
|
||||
* @param tcb
|
||||
* TryCatchBlockNode corresponding to this edge.
|
||||
* @return true if this edge must be considered in the data flow analysis
|
||||
* performed by this analyzer, or false otherwise. The default
|
||||
* implementation of this method delegates to
|
||||
* {@link #newControlFlowExceptionEdge(int, int)
|
||||
* newControlFlowExceptionEdge(int, int)}.
|
||||
*/
|
||||
protected boolean newControlFlowExceptionEdge(final int insn,
|
||||
final TryCatchBlockNode tcb) {
|
||||
return newControlFlowExceptionEdge(insn, insns.indexOf(tcb.handler));
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
private void merge(final int insn, final Frame<V> frame,
|
||||
final Subroutine subroutine) throws AnalyzerException {
|
||||
Frame<V> oldFrame = frames[insn];
|
||||
Subroutine oldSubroutine = subroutines[insn];
|
||||
boolean changes;
|
||||
|
||||
if (oldFrame == null) {
|
||||
frames[insn] = newFrame(frame);
|
||||
changes = true;
|
||||
} else {
|
||||
changes = oldFrame.merge(frame, interpreter);
|
||||
}
|
||||
|
||||
if (oldSubroutine == null) {
|
||||
if (subroutine != null) {
|
||||
subroutines[insn] = subroutine.copy();
|
||||
changes = true;
|
||||
}
|
||||
} else {
|
||||
if (subroutine != null) {
|
||||
changes |= oldSubroutine.merge(subroutine);
|
||||
}
|
||||
}
|
||||
if (changes && !queued[insn]) {
|
||||
queued[insn] = true;
|
||||
queue[top++] = insn;
|
||||
}
|
||||
}
|
||||
|
||||
private void merge(final int insn, final Frame<V> beforeJSR,
|
||||
final Frame<V> afterRET, final Subroutine subroutineBeforeJSR,
|
||||
final boolean[] access) throws AnalyzerException {
|
||||
Frame<V> oldFrame = frames[insn];
|
||||
Subroutine oldSubroutine = subroutines[insn];
|
||||
boolean changes;
|
||||
|
||||
afterRET.merge(beforeJSR, access);
|
||||
|
||||
if (oldFrame == null) {
|
||||
frames[insn] = newFrame(afterRET);
|
||||
changes = true;
|
||||
} else {
|
||||
changes = oldFrame.merge(afterRET, interpreter);
|
||||
}
|
||||
|
||||
if (oldSubroutine != null && subroutineBeforeJSR != null) {
|
||||
changes |= oldSubroutine.merge(subroutineBeforeJSR);
|
||||
}
|
||||
if (changes && !queued[insn]) {
|
||||
queued[insn] = true;
|
||||
queue[top++] = insn;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
/***
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 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.tree.analysis;
|
||||
|
||||
import org.objectweb.asm.tree.AbstractInsnNode;
|
||||
|
||||
/**
|
||||
* Thrown if a problem occurs during the analysis of a method.
|
||||
*
|
||||
* @author Bing Ran
|
||||
* @author Eric Bruneton
|
||||
*/
|
||||
public class AnalyzerException extends Exception {
|
||||
private static final long serialVersionUID = -1788355977291059681L;
|
||||
public final AbstractInsnNode node;
|
||||
|
||||
public AnalyzerException(final AbstractInsnNode node, final String msg) {
|
||||
super(msg);
|
||||
this.node = node;
|
||||
}
|
||||
|
||||
public AnalyzerException(final AbstractInsnNode node, final String msg,
|
||||
final Throwable exception) {
|
||||
super(msg, exception);
|
||||
this.node = node;
|
||||
}
|
||||
|
||||
public AnalyzerException(final AbstractInsnNode node, final String msg,
|
||||
final Object expected, final Value encountered) {
|
||||
super((msg == null ? "Expected " : msg + ": expected ") + expected
|
||||
+ ", but found " + encountered);
|
||||
this.node = node;
|
||||
}
|
||||
}
|
||||
@@ -1,358 +0,0 @@
|
||||
/***
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 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.tree.analysis;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.objectweb.asm.Handle;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.tree.AbstractInsnNode;
|
||||
import org.objectweb.asm.tree.FieldInsnNode;
|
||||
import org.objectweb.asm.tree.IntInsnNode;
|
||||
import org.objectweb.asm.tree.InvokeDynamicInsnNode;
|
||||
import org.objectweb.asm.tree.LdcInsnNode;
|
||||
import org.objectweb.asm.tree.MethodInsnNode;
|
||||
import org.objectweb.asm.tree.MultiANewArrayInsnNode;
|
||||
import org.objectweb.asm.tree.TypeInsnNode;
|
||||
|
||||
/**
|
||||
* An {@link Interpreter} for {@link BasicValue} values.
|
||||
*
|
||||
* @author Eric Bruneton
|
||||
* @author Bing Ran
|
||||
*/
|
||||
public class BasicInterpreter extends Interpreter<BasicValue> implements
|
||||
Opcodes {
|
||||
|
||||
public BasicInterpreter() {
|
||||
super(ASM4);
|
||||
}
|
||||
|
||||
protected BasicInterpreter(final int api) {
|
||||
super(api);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasicValue newValue(final Type type) {
|
||||
if (type == null) {
|
||||
return BasicValue.UNINITIALIZED_VALUE;
|
||||
}
|
||||
switch (type.getSort()) {
|
||||
case Type.VOID:
|
||||
return null;
|
||||
case Type.BOOLEAN:
|
||||
case Type.CHAR:
|
||||
case Type.BYTE:
|
||||
case Type.SHORT:
|
||||
case Type.INT:
|
||||
return BasicValue.INT_VALUE;
|
||||
case Type.FLOAT:
|
||||
return BasicValue.FLOAT_VALUE;
|
||||
case Type.LONG:
|
||||
return BasicValue.LONG_VALUE;
|
||||
case Type.DOUBLE:
|
||||
return BasicValue.DOUBLE_VALUE;
|
||||
case Type.ARRAY:
|
||||
case Type.OBJECT:
|
||||
return BasicValue.REFERENCE_VALUE;
|
||||
default:
|
||||
throw new Error("Internal error");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasicValue newOperation(final AbstractInsnNode insn)
|
||||
throws AnalyzerException {
|
||||
switch (insn.getOpcode()) {
|
||||
case ACONST_NULL:
|
||||
return newValue(Type.getObjectType("null"));
|
||||
case ICONST_M1:
|
||||
case ICONST_0:
|
||||
case ICONST_1:
|
||||
case ICONST_2:
|
||||
case ICONST_3:
|
||||
case ICONST_4:
|
||||
case ICONST_5:
|
||||
return BasicValue.INT_VALUE;
|
||||
case LCONST_0:
|
||||
case LCONST_1:
|
||||
return BasicValue.LONG_VALUE;
|
||||
case FCONST_0:
|
||||
case FCONST_1:
|
||||
case FCONST_2:
|
||||
return BasicValue.FLOAT_VALUE;
|
||||
case DCONST_0:
|
||||
case DCONST_1:
|
||||
return BasicValue.DOUBLE_VALUE;
|
||||
case BIPUSH:
|
||||
case SIPUSH:
|
||||
return BasicValue.INT_VALUE;
|
||||
case LDC:
|
||||
Object cst = ((LdcInsnNode) insn).cst;
|
||||
if (cst instanceof Integer) {
|
||||
return BasicValue.INT_VALUE;
|
||||
} else if (cst instanceof Float) {
|
||||
return BasicValue.FLOAT_VALUE;
|
||||
} else if (cst instanceof Long) {
|
||||
return BasicValue.LONG_VALUE;
|
||||
} else if (cst instanceof Double) {
|
||||
return BasicValue.DOUBLE_VALUE;
|
||||
} else if (cst instanceof String) {
|
||||
return newValue(Type.getObjectType("java/lang/String"));
|
||||
} else if (cst instanceof Type) {
|
||||
int sort = ((Type) cst).getSort();
|
||||
if (sort == Type.OBJECT || sort == Type.ARRAY) {
|
||||
return newValue(Type.getObjectType("java/lang/Class"));
|
||||
} else if (sort == Type.METHOD) {
|
||||
return newValue(Type
|
||||
.getObjectType("java/lang/invoke/MethodType"));
|
||||
} else {
|
||||
throw new IllegalArgumentException("Illegal LDC constant "
|
||||
+ cst);
|
||||
}
|
||||
} else if (cst instanceof Handle) {
|
||||
return newValue(Type
|
||||
.getObjectType("java/lang/invoke/MethodHandle"));
|
||||
} else {
|
||||
throw new IllegalArgumentException("Illegal LDC constant "
|
||||
+ cst);
|
||||
}
|
||||
case JSR:
|
||||
return BasicValue.RETURNADDRESS_VALUE;
|
||||
case GETSTATIC:
|
||||
return newValue(Type.getType(((FieldInsnNode) insn).desc));
|
||||
case NEW:
|
||||
return newValue(Type.getObjectType(((TypeInsnNode) insn).desc));
|
||||
default:
|
||||
throw new Error("Internal error.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasicValue copyOperation(final AbstractInsnNode insn,
|
||||
final BasicValue value) throws AnalyzerException {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasicValue unaryOperation(final AbstractInsnNode insn,
|
||||
final BasicValue value) throws AnalyzerException {
|
||||
switch (insn.getOpcode()) {
|
||||
case INEG:
|
||||
case IINC:
|
||||
case L2I:
|
||||
case F2I:
|
||||
case D2I:
|
||||
case I2B:
|
||||
case I2C:
|
||||
case I2S:
|
||||
return BasicValue.INT_VALUE;
|
||||
case FNEG:
|
||||
case I2F:
|
||||
case L2F:
|
||||
case D2F:
|
||||
return BasicValue.FLOAT_VALUE;
|
||||
case LNEG:
|
||||
case I2L:
|
||||
case F2L:
|
||||
case D2L:
|
||||
return BasicValue.LONG_VALUE;
|
||||
case DNEG:
|
||||
case I2D:
|
||||
case L2D:
|
||||
case F2D:
|
||||
return BasicValue.DOUBLE_VALUE;
|
||||
case IFEQ:
|
||||
case IFNE:
|
||||
case IFLT:
|
||||
case IFGE:
|
||||
case IFGT:
|
||||
case IFLE:
|
||||
case TABLESWITCH:
|
||||
case LOOKUPSWITCH:
|
||||
case IRETURN:
|
||||
case LRETURN:
|
||||
case FRETURN:
|
||||
case DRETURN:
|
||||
case ARETURN:
|
||||
case PUTSTATIC:
|
||||
return null;
|
||||
case GETFIELD:
|
||||
return newValue(Type.getType(((FieldInsnNode) insn).desc));
|
||||
case NEWARRAY:
|
||||
switch (((IntInsnNode) insn).operand) {
|
||||
case T_BOOLEAN:
|
||||
return newValue(Type.getType("[Z"));
|
||||
case T_CHAR:
|
||||
return newValue(Type.getType("[C"));
|
||||
case T_BYTE:
|
||||
return newValue(Type.getType("[B"));
|
||||
case T_SHORT:
|
||||
return newValue(Type.getType("[S"));
|
||||
case T_INT:
|
||||
return newValue(Type.getType("[I"));
|
||||
case T_FLOAT:
|
||||
return newValue(Type.getType("[F"));
|
||||
case T_DOUBLE:
|
||||
return newValue(Type.getType("[D"));
|
||||
case T_LONG:
|
||||
return newValue(Type.getType("[J"));
|
||||
default:
|
||||
throw new AnalyzerException(insn, "Invalid array type");
|
||||
}
|
||||
case ANEWARRAY:
|
||||
String desc = ((TypeInsnNode) insn).desc;
|
||||
return newValue(Type.getType("[" + Type.getObjectType(desc)));
|
||||
case ARRAYLENGTH:
|
||||
return BasicValue.INT_VALUE;
|
||||
case ATHROW:
|
||||
return null;
|
||||
case CHECKCAST:
|
||||
desc = ((TypeInsnNode) insn).desc;
|
||||
return newValue(Type.getObjectType(desc));
|
||||
case INSTANCEOF:
|
||||
return BasicValue.INT_VALUE;
|
||||
case MONITORENTER:
|
||||
case MONITOREXIT:
|
||||
case IFNULL:
|
||||
case IFNONNULL:
|
||||
return null;
|
||||
default:
|
||||
throw new Error("Internal error.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasicValue binaryOperation(final AbstractInsnNode insn,
|
||||
final BasicValue value1, final BasicValue value2)
|
||||
throws AnalyzerException {
|
||||
switch (insn.getOpcode()) {
|
||||
case IALOAD:
|
||||
case BALOAD:
|
||||
case CALOAD:
|
||||
case SALOAD:
|
||||
case IADD:
|
||||
case ISUB:
|
||||
case IMUL:
|
||||
case IDIV:
|
||||
case IREM:
|
||||
case ISHL:
|
||||
case ISHR:
|
||||
case IUSHR:
|
||||
case IAND:
|
||||
case IOR:
|
||||
case IXOR:
|
||||
return BasicValue.INT_VALUE;
|
||||
case FALOAD:
|
||||
case FADD:
|
||||
case FSUB:
|
||||
case FMUL:
|
||||
case FDIV:
|
||||
case FREM:
|
||||
return BasicValue.FLOAT_VALUE;
|
||||
case LALOAD:
|
||||
case LADD:
|
||||
case LSUB:
|
||||
case LMUL:
|
||||
case LDIV:
|
||||
case LREM:
|
||||
case LSHL:
|
||||
case LSHR:
|
||||
case LUSHR:
|
||||
case LAND:
|
||||
case LOR:
|
||||
case LXOR:
|
||||
return BasicValue.LONG_VALUE;
|
||||
case DALOAD:
|
||||
case DADD:
|
||||
case DSUB:
|
||||
case DMUL:
|
||||
case DDIV:
|
||||
case DREM:
|
||||
return BasicValue.DOUBLE_VALUE;
|
||||
case AALOAD:
|
||||
return BasicValue.REFERENCE_VALUE;
|
||||
case LCMP:
|
||||
case FCMPL:
|
||||
case FCMPG:
|
||||
case DCMPL:
|
||||
case DCMPG:
|
||||
return BasicValue.INT_VALUE;
|
||||
case IF_ICMPEQ:
|
||||
case IF_ICMPNE:
|
||||
case IF_ICMPLT:
|
||||
case IF_ICMPGE:
|
||||
case IF_ICMPGT:
|
||||
case IF_ICMPLE:
|
||||
case IF_ACMPEQ:
|
||||
case IF_ACMPNE:
|
||||
case PUTFIELD:
|
||||
return null;
|
||||
default:
|
||||
throw new Error("Internal error.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasicValue ternaryOperation(final AbstractInsnNode insn,
|
||||
final BasicValue value1, final BasicValue value2,
|
||||
final BasicValue value3) throws AnalyzerException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasicValue naryOperation(final AbstractInsnNode insn,
|
||||
final List<? extends BasicValue> values) throws AnalyzerException {
|
||||
int opcode = insn.getOpcode();
|
||||
if (opcode == MULTIANEWARRAY) {
|
||||
return newValue(Type.getType(((MultiANewArrayInsnNode) insn).desc));
|
||||
} else if (opcode == INVOKEDYNAMIC) {
|
||||
return newValue(Type
|
||||
.getReturnType(((InvokeDynamicInsnNode) insn).desc));
|
||||
} else {
|
||||
return newValue(Type.getReturnType(((MethodInsnNode) insn).desc));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void returnOperation(final AbstractInsnNode insn,
|
||||
final BasicValue value, final BasicValue expected)
|
||||
throws AnalyzerException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasicValue merge(final BasicValue v, final BasicValue w) {
|
||||
if (!v.equals(w)) {
|
||||
return BasicValue.UNINITIALIZED_VALUE;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
}
|
||||
@@ -1,111 +0,0 @@
|
||||
/***
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 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.tree.analysis;
|
||||
|
||||
import org.objectweb.asm.Type;
|
||||
|
||||
/**
|
||||
* A {@link Value} that is represented by its type in a seven types type system.
|
||||
* This type system distinguishes the UNINITIALZED, INT, FLOAT, LONG, DOUBLE,
|
||||
* REFERENCE and RETURNADDRESS types.
|
||||
*
|
||||
* @author Eric Bruneton
|
||||
*/
|
||||
public class BasicValue implements Value {
|
||||
|
||||
public static final BasicValue UNINITIALIZED_VALUE = new BasicValue(null);
|
||||
|
||||
public static final BasicValue INT_VALUE = new BasicValue(Type.INT_TYPE);
|
||||
|
||||
public static final BasicValue FLOAT_VALUE = new BasicValue(Type.FLOAT_TYPE);
|
||||
|
||||
public static final BasicValue LONG_VALUE = new BasicValue(Type.LONG_TYPE);
|
||||
|
||||
public static final BasicValue DOUBLE_VALUE = new BasicValue(
|
||||
Type.DOUBLE_TYPE);
|
||||
|
||||
public static final BasicValue REFERENCE_VALUE = new BasicValue(
|
||||
Type.getObjectType("java/lang/Object"));
|
||||
|
||||
public static final BasicValue RETURNADDRESS_VALUE = new BasicValue(
|
||||
Type.VOID_TYPE);
|
||||
|
||||
private final Type type;
|
||||
|
||||
public BasicValue(final Type type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public Type getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public int getSize() {
|
||||
return type == Type.LONG_TYPE || type == Type.DOUBLE_TYPE ? 2 : 1;
|
||||
}
|
||||
|
||||
public boolean isReference() {
|
||||
return type != null
|
||||
&& (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object value) {
|
||||
if (value == this) {
|
||||
return true;
|
||||
} else if (value instanceof BasicValue) {
|
||||
if (type == null) {
|
||||
return ((BasicValue) value).type == null;
|
||||
} else {
|
||||
return type.equals(((BasicValue) value).type);
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return type == null ? 0 : type.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (this == UNINITIALIZED_VALUE) {
|
||||
return ".";
|
||||
} else if (this == RETURNADDRESS_VALUE) {
|
||||
return "A";
|
||||
} else if (this == REFERENCE_VALUE) {
|
||||
return "R";
|
||||
} else {
|
||||
return type.getDescriptor();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,433 +0,0 @@
|
||||
/***
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 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.tree.analysis;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.tree.AbstractInsnNode;
|
||||
import org.objectweb.asm.tree.FieldInsnNode;
|
||||
import org.objectweb.asm.tree.InvokeDynamicInsnNode;
|
||||
import org.objectweb.asm.tree.MethodInsnNode;
|
||||
|
||||
/**
|
||||
* An extended {@link org.objectweb.asm.tree.analysis.BasicInterpreter} that checks that bytecode instructions
|
||||
* are correctly used.
|
||||
*
|
||||
* @author Eric Bruneton
|
||||
* @author Bing Ran
|
||||
*/
|
||||
public class BasicVerifier extends BasicInterpreter {
|
||||
|
||||
public BasicVerifier() {
|
||||
super(ASM4);
|
||||
}
|
||||
|
||||
protected BasicVerifier(final int api) {
|
||||
super(api);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasicValue copyOperation(final AbstractInsnNode insn,
|
||||
final BasicValue value) throws AnalyzerException {
|
||||
Value expected;
|
||||
switch (insn.getOpcode()) {
|
||||
case ILOAD:
|
||||
case ISTORE:
|
||||
expected = BasicValue.INT_VALUE;
|
||||
break;
|
||||
case FLOAD:
|
||||
case FSTORE:
|
||||
expected = BasicValue.FLOAT_VALUE;
|
||||
break;
|
||||
case LLOAD:
|
||||
case LSTORE:
|
||||
expected = BasicValue.LONG_VALUE;
|
||||
break;
|
||||
case DLOAD:
|
||||
case DSTORE:
|
||||
expected = BasicValue.DOUBLE_VALUE;
|
||||
break;
|
||||
case ALOAD:
|
||||
if (!value.isReference()) {
|
||||
throw new AnalyzerException(insn, null, "an object reference",
|
||||
value);
|
||||
}
|
||||
return value;
|
||||
case ASTORE:
|
||||
if (!value.isReference()
|
||||
&& !BasicValue.RETURNADDRESS_VALUE.equals(value)) {
|
||||
throw new AnalyzerException(insn, null,
|
||||
"an object reference or a return address", value);
|
||||
}
|
||||
return value;
|
||||
default:
|
||||
return value;
|
||||
}
|
||||
if (!expected.equals(value)) {
|
||||
throw new AnalyzerException(insn, null, expected, value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasicValue unaryOperation(final AbstractInsnNode insn,
|
||||
final BasicValue value) throws AnalyzerException {
|
||||
BasicValue expected;
|
||||
switch (insn.getOpcode()) {
|
||||
case INEG:
|
||||
case IINC:
|
||||
case I2F:
|
||||
case I2L:
|
||||
case I2D:
|
||||
case I2B:
|
||||
case I2C:
|
||||
case I2S:
|
||||
case IFEQ:
|
||||
case IFNE:
|
||||
case IFLT:
|
||||
case IFGE:
|
||||
case IFGT:
|
||||
case IFLE:
|
||||
case TABLESWITCH:
|
||||
case LOOKUPSWITCH:
|
||||
case IRETURN:
|
||||
case NEWARRAY:
|
||||
case ANEWARRAY:
|
||||
expected = BasicValue.INT_VALUE;
|
||||
break;
|
||||
case FNEG:
|
||||
case F2I:
|
||||
case F2L:
|
||||
case F2D:
|
||||
case FRETURN:
|
||||
expected = BasicValue.FLOAT_VALUE;
|
||||
break;
|
||||
case LNEG:
|
||||
case L2I:
|
||||
case L2F:
|
||||
case L2D:
|
||||
case LRETURN:
|
||||
expected = BasicValue.LONG_VALUE;
|
||||
break;
|
||||
case DNEG:
|
||||
case D2I:
|
||||
case D2F:
|
||||
case D2L:
|
||||
case DRETURN:
|
||||
expected = BasicValue.DOUBLE_VALUE;
|
||||
break;
|
||||
case GETFIELD:
|
||||
expected = newValue(Type
|
||||
.getObjectType(((FieldInsnNode) insn).owner));
|
||||
break;
|
||||
case CHECKCAST:
|
||||
if (!value.isReference()) {
|
||||
throw new AnalyzerException(insn, null, "an object reference",
|
||||
value);
|
||||
}
|
||||
return super.unaryOperation(insn, value);
|
||||
case ARRAYLENGTH:
|
||||
if (!isArrayValue(value)) {
|
||||
throw new AnalyzerException(insn, null, "an array reference",
|
||||
value);
|
||||
}
|
||||
return super.unaryOperation(insn, value);
|
||||
case ARETURN:
|
||||
case ATHROW:
|
||||
case INSTANCEOF:
|
||||
case MONITORENTER:
|
||||
case MONITOREXIT:
|
||||
case IFNULL:
|
||||
case IFNONNULL:
|
||||
if (!value.isReference()) {
|
||||
throw new AnalyzerException(insn, null, "an object reference",
|
||||
value);
|
||||
}
|
||||
return super.unaryOperation(insn, value);
|
||||
case PUTSTATIC:
|
||||
expected = newValue(Type.getType(((FieldInsnNode) insn).desc));
|
||||
break;
|
||||
default:
|
||||
throw new Error("Internal error.");
|
||||
}
|
||||
if (!isSubTypeOf(value, expected)) {
|
||||
throw new AnalyzerException(insn, null, expected, value);
|
||||
}
|
||||
return super.unaryOperation(insn, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasicValue binaryOperation(final AbstractInsnNode insn,
|
||||
final BasicValue value1, final BasicValue value2)
|
||||
throws AnalyzerException {
|
||||
BasicValue expected1;
|
||||
BasicValue expected2;
|
||||
switch (insn.getOpcode()) {
|
||||
case IALOAD:
|
||||
expected1 = newValue(Type.getType("[I"));
|
||||
expected2 = BasicValue.INT_VALUE;
|
||||
break;
|
||||
case BALOAD:
|
||||
if (isSubTypeOf(value1, newValue(Type.getType("[Z")))) {
|
||||
expected1 = newValue(Type.getType("[Z"));
|
||||
} else {
|
||||
expected1 = newValue(Type.getType("[B"));
|
||||
}
|
||||
expected2 = BasicValue.INT_VALUE;
|
||||
break;
|
||||
case CALOAD:
|
||||
expected1 = newValue(Type.getType("[C"));
|
||||
expected2 = BasicValue.INT_VALUE;
|
||||
break;
|
||||
case SALOAD:
|
||||
expected1 = newValue(Type.getType("[S"));
|
||||
expected2 = BasicValue.INT_VALUE;
|
||||
break;
|
||||
case LALOAD:
|
||||
expected1 = newValue(Type.getType("[J"));
|
||||
expected2 = BasicValue.INT_VALUE;
|
||||
break;
|
||||
case FALOAD:
|
||||
expected1 = newValue(Type.getType("[F"));
|
||||
expected2 = BasicValue.INT_VALUE;
|
||||
break;
|
||||
case DALOAD:
|
||||
expected1 = newValue(Type.getType("[D"));
|
||||
expected2 = BasicValue.INT_VALUE;
|
||||
break;
|
||||
case AALOAD:
|
||||
expected1 = newValue(Type.getType("[Ljava/lang/Object;"));
|
||||
expected2 = BasicValue.INT_VALUE;
|
||||
break;
|
||||
case IADD:
|
||||
case ISUB:
|
||||
case IMUL:
|
||||
case IDIV:
|
||||
case IREM:
|
||||
case ISHL:
|
||||
case ISHR:
|
||||
case IUSHR:
|
||||
case IAND:
|
||||
case IOR:
|
||||
case IXOR:
|
||||
case IF_ICMPEQ:
|
||||
case IF_ICMPNE:
|
||||
case IF_ICMPLT:
|
||||
case IF_ICMPGE:
|
||||
case IF_ICMPGT:
|
||||
case IF_ICMPLE:
|
||||
expected1 = BasicValue.INT_VALUE;
|
||||
expected2 = BasicValue.INT_VALUE;
|
||||
break;
|
||||
case FADD:
|
||||
case FSUB:
|
||||
case FMUL:
|
||||
case FDIV:
|
||||
case FREM:
|
||||
case FCMPL:
|
||||
case FCMPG:
|
||||
expected1 = BasicValue.FLOAT_VALUE;
|
||||
expected2 = BasicValue.FLOAT_VALUE;
|
||||
break;
|
||||
case LADD:
|
||||
case LSUB:
|
||||
case LMUL:
|
||||
case LDIV:
|
||||
case LREM:
|
||||
case LAND:
|
||||
case LOR:
|
||||
case LXOR:
|
||||
case LCMP:
|
||||
expected1 = BasicValue.LONG_VALUE;
|
||||
expected2 = BasicValue.LONG_VALUE;
|
||||
break;
|
||||
case LSHL:
|
||||
case LSHR:
|
||||
case LUSHR:
|
||||
expected1 = BasicValue.LONG_VALUE;
|
||||
expected2 = BasicValue.INT_VALUE;
|
||||
break;
|
||||
case DADD:
|
||||
case DSUB:
|
||||
case DMUL:
|
||||
case DDIV:
|
||||
case DREM:
|
||||
case DCMPL:
|
||||
case DCMPG:
|
||||
expected1 = BasicValue.DOUBLE_VALUE;
|
||||
expected2 = BasicValue.DOUBLE_VALUE;
|
||||
break;
|
||||
case IF_ACMPEQ:
|
||||
case IF_ACMPNE:
|
||||
expected1 = BasicValue.REFERENCE_VALUE;
|
||||
expected2 = BasicValue.REFERENCE_VALUE;
|
||||
break;
|
||||
case PUTFIELD:
|
||||
FieldInsnNode fin = (FieldInsnNode) insn;
|
||||
expected1 = newValue(Type.getObjectType(fin.owner));
|
||||
expected2 = newValue(Type.getType(fin.desc));
|
||||
break;
|
||||
default:
|
||||
throw new Error("Internal error.");
|
||||
}
|
||||
if (!isSubTypeOf(value1, expected1)) {
|
||||
throw new AnalyzerException(insn, "First argument", expected1,
|
||||
value1);
|
||||
} else if (!isSubTypeOf(value2, expected2)) {
|
||||
throw new AnalyzerException(insn, "Second argument", expected2,
|
||||
value2);
|
||||
}
|
||||
if (insn.getOpcode() == AALOAD) {
|
||||
return getElementValue(value1);
|
||||
} else {
|
||||
return super.binaryOperation(insn, value1, value2);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasicValue ternaryOperation(final AbstractInsnNode insn,
|
||||
final BasicValue value1, final BasicValue value2,
|
||||
final BasicValue value3) throws AnalyzerException {
|
||||
BasicValue expected1;
|
||||
BasicValue expected3;
|
||||
switch (insn.getOpcode()) {
|
||||
case IASTORE:
|
||||
expected1 = newValue(Type.getType("[I"));
|
||||
expected3 = BasicValue.INT_VALUE;
|
||||
break;
|
||||
case BASTORE:
|
||||
if (isSubTypeOf(value1, newValue(Type.getType("[Z")))) {
|
||||
expected1 = newValue(Type.getType("[Z"));
|
||||
} else {
|
||||
expected1 = newValue(Type.getType("[B"));
|
||||
}
|
||||
expected3 = BasicValue.INT_VALUE;
|
||||
break;
|
||||
case CASTORE:
|
||||
expected1 = newValue(Type.getType("[C"));
|
||||
expected3 = BasicValue.INT_VALUE;
|
||||
break;
|
||||
case SASTORE:
|
||||
expected1 = newValue(Type.getType("[S"));
|
||||
expected3 = BasicValue.INT_VALUE;
|
||||
break;
|
||||
case LASTORE:
|
||||
expected1 = newValue(Type.getType("[J"));
|
||||
expected3 = BasicValue.LONG_VALUE;
|
||||
break;
|
||||
case FASTORE:
|
||||
expected1 = newValue(Type.getType("[F"));
|
||||
expected3 = BasicValue.FLOAT_VALUE;
|
||||
break;
|
||||
case DASTORE:
|
||||
expected1 = newValue(Type.getType("[D"));
|
||||
expected3 = BasicValue.DOUBLE_VALUE;
|
||||
break;
|
||||
case AASTORE:
|
||||
expected1 = value1;
|
||||
expected3 = BasicValue.REFERENCE_VALUE;
|
||||
break;
|
||||
default:
|
||||
throw new Error("Internal error.");
|
||||
}
|
||||
if (!isSubTypeOf(value1, expected1)) {
|
||||
throw new AnalyzerException(insn, "First argument", "a "
|
||||
+ expected1 + " array reference", value1);
|
||||
} else if (!BasicValue.INT_VALUE.equals(value2)) {
|
||||
throw new AnalyzerException(insn, "Second argument",
|
||||
BasicValue.INT_VALUE, value2);
|
||||
} else if (!isSubTypeOf(value3, expected3)) {
|
||||
throw new AnalyzerException(insn, "Third argument", expected3,
|
||||
value3);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasicValue naryOperation(final AbstractInsnNode insn,
|
||||
final List<? extends BasicValue> values) throws AnalyzerException {
|
||||
int opcode = insn.getOpcode();
|
||||
if (opcode == MULTIANEWARRAY) {
|
||||
for (int i = 0; i < values.size(); ++i) {
|
||||
if (!BasicValue.INT_VALUE.equals(values.get(i))) {
|
||||
throw new AnalyzerException(insn, null,
|
||||
BasicValue.INT_VALUE, values.get(i));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
if (opcode != INVOKESTATIC && opcode != INVOKEDYNAMIC) {
|
||||
Type owner = Type.getObjectType(((MethodInsnNode) insn).owner);
|
||||
if (!isSubTypeOf(values.get(i++), newValue(owner))) {
|
||||
throw new AnalyzerException(insn, "Method owner",
|
||||
newValue(owner), values.get(0));
|
||||
}
|
||||
}
|
||||
String desc = (opcode == INVOKEDYNAMIC) ? ((InvokeDynamicInsnNode) insn).desc
|
||||
: ((MethodInsnNode) insn).desc;
|
||||
Type[] args = Type.getArgumentTypes(desc);
|
||||
while (i < values.size()) {
|
||||
BasicValue expected = newValue(args[j++]);
|
||||
BasicValue encountered = values.get(i++);
|
||||
if (!isSubTypeOf(encountered, expected)) {
|
||||
throw new AnalyzerException(insn, "Argument " + j,
|
||||
expected, encountered);
|
||||
}
|
||||
}
|
||||
}
|
||||
return super.naryOperation(insn, values);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void returnOperation(final AbstractInsnNode insn,
|
||||
final BasicValue value, final BasicValue expected)
|
||||
throws AnalyzerException {
|
||||
if (!isSubTypeOf(value, expected)) {
|
||||
throw new AnalyzerException(insn, "Incompatible return type",
|
||||
expected, value);
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean isArrayValue(final BasicValue value) {
|
||||
return value.isReference();
|
||||
}
|
||||
|
||||
protected BasicValue getElementValue(final BasicValue objectArrayValue)
|
||||
throws AnalyzerException {
|
||||
return BasicValue.REFERENCE_VALUE;
|
||||
}
|
||||
|
||||
protected boolean isSubTypeOf(final BasicValue value,
|
||||
final BasicValue expected) {
|
||||
return value.equals(expected);
|
||||
}
|
||||
}
|
||||
@@ -1,730 +0,0 @@
|
||||
/***
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 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.tree.analysis;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.tree.AbstractInsnNode;
|
||||
import org.objectweb.asm.tree.IincInsnNode;
|
||||
import org.objectweb.asm.tree.InvokeDynamicInsnNode;
|
||||
import org.objectweb.asm.tree.MethodInsnNode;
|
||||
import org.objectweb.asm.tree.MultiANewArrayInsnNode;
|
||||
import org.objectweb.asm.tree.VarInsnNode;
|
||||
|
||||
/**
|
||||
* A symbolic execution stack frame. A stack frame contains a set of local
|
||||
* variable slots, and an operand stack. Warning: long and double values are
|
||||
* represented by <i>two</i> slots in local variables, and by <i>one</i> slot in
|
||||
* the operand stack.
|
||||
*
|
||||
* @param <V>
|
||||
* type of the Value used for the analysis.
|
||||
*
|
||||
* @author Eric Bruneton
|
||||
*/
|
||||
public class Frame<V extends Value> {
|
||||
|
||||
/**
|
||||
* The expected return type of the analyzed method, or <tt>null</tt> if the
|
||||
* method returns void.
|
||||
*/
|
||||
private V returnValue;
|
||||
|
||||
/**
|
||||
* The local variables and operand stack of this frame.
|
||||
*/
|
||||
private V[] values;
|
||||
|
||||
/**
|
||||
* The number of local variables of this frame.
|
||||
*/
|
||||
private int locals;
|
||||
|
||||
/**
|
||||
* The number of elements in the operand stack.
|
||||
*/
|
||||
private int top;
|
||||
|
||||
/**
|
||||
* Constructs a new frame with the given size.
|
||||
*
|
||||
* @param nLocals
|
||||
* the maximum number of local variables of the frame.
|
||||
* @param nStack
|
||||
* the maximum stack size of the frame.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public Frame(final int nLocals, final int nStack) {
|
||||
this.values = (V[]) new Value[nLocals + nStack];
|
||||
this.locals = nLocals;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new frame that is identical to the given frame.
|
||||
*
|
||||
* @param src
|
||||
* a frame.
|
||||
*/
|
||||
public Frame(final Frame<? extends V> src) {
|
||||
this(src.locals, src.values.length - src.locals);
|
||||
init(src);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the state of the given frame into this frame.
|
||||
*
|
||||
* @param src
|
||||
* a frame.
|
||||
* @return this frame.
|
||||
*/
|
||||
public Frame<V> init(final Frame<? extends V> src) {
|
||||
returnValue = src.returnValue;
|
||||
System.arraycopy(src.values, 0, values, 0, values.length);
|
||||
top = src.top;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the expected return type of the analyzed method.
|
||||
*
|
||||
* @param v
|
||||
* the expected return type of the analyzed method, or
|
||||
* <tt>null</tt> if the method returns void.
|
||||
*/
|
||||
public void setReturn(final V v) {
|
||||
returnValue = v;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximum number of local variables of this frame.
|
||||
*
|
||||
* @return the maximum number of local variables of this frame.
|
||||
*/
|
||||
public int getLocals() {
|
||||
return locals;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the given local variable.
|
||||
*
|
||||
* @param i
|
||||
* a local variable index.
|
||||
* @return the value of the given local variable.
|
||||
* @throws IndexOutOfBoundsException
|
||||
* if the variable does not exist.
|
||||
*/
|
||||
public V getLocal(final int i) throws IndexOutOfBoundsException {
|
||||
if (i >= locals) {
|
||||
throw new IndexOutOfBoundsException(
|
||||
"Trying to access an inexistant local variable");
|
||||
}
|
||||
return values[i];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the given local variable.
|
||||
*
|
||||
* @param i
|
||||
* a local variable index.
|
||||
* @param value
|
||||
* the new value of this local variable.
|
||||
* @throws IndexOutOfBoundsException
|
||||
* if the variable does not exist.
|
||||
*/
|
||||
public void setLocal(final int i, final V value)
|
||||
throws IndexOutOfBoundsException {
|
||||
if (i >= locals) {
|
||||
throw new IndexOutOfBoundsException(
|
||||
"Trying to access an inexistant local variable " + i);
|
||||
}
|
||||
values[i] = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of values in the operand stack of this frame. Long and
|
||||
* double values are treated as single values.
|
||||
*
|
||||
* @return the number of values in the operand stack of this frame.
|
||||
*/
|
||||
public int getStackSize() {
|
||||
return top;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the given operand stack slot.
|
||||
*
|
||||
* @param i
|
||||
* the index of an operand stack slot.
|
||||
* @return the value of the given operand stack slot.
|
||||
* @throws IndexOutOfBoundsException
|
||||
* if the operand stack slot does not exist.
|
||||
*/
|
||||
public V getStack(final int i) throws IndexOutOfBoundsException {
|
||||
return values[i + locals];
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the operand stack of this frame.
|
||||
*/
|
||||
public void clearStack() {
|
||||
top = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pops a value from the operand stack of this frame.
|
||||
*
|
||||
* @return the value that has been popped from the stack.
|
||||
* @throws IndexOutOfBoundsException
|
||||
* if the operand stack is empty.
|
||||
*/
|
||||
public V pop() throws IndexOutOfBoundsException {
|
||||
if (top == 0) {
|
||||
throw new IndexOutOfBoundsException(
|
||||
"Cannot pop operand off an empty stack.");
|
||||
}
|
||||
return values[--top + locals];
|
||||
}
|
||||
|
||||
/**
|
||||
* Pushes a value into the operand stack of this frame.
|
||||
*
|
||||
* @param value
|
||||
* the value that must be pushed into the stack.
|
||||
* @throws IndexOutOfBoundsException
|
||||
* if the operand stack is full.
|
||||
*/
|
||||
public void push(final V value) throws IndexOutOfBoundsException {
|
||||
if (top + locals >= values.length) {
|
||||
throw new IndexOutOfBoundsException(
|
||||
"Insufficient maximum stack size.");
|
||||
}
|
||||
values[top++ + locals] = value;
|
||||
}
|
||||
|
||||
public void execute(final AbstractInsnNode insn,
|
||||
final Interpreter<V> interpreter) throws AnalyzerException {
|
||||
V value1, value2, value3, value4;
|
||||
List<V> values;
|
||||
int var;
|
||||
|
||||
switch (insn.getOpcode()) {
|
||||
case Opcodes.NOP:
|
||||
break;
|
||||
case Opcodes.ACONST_NULL:
|
||||
case Opcodes.ICONST_M1:
|
||||
case Opcodes.ICONST_0:
|
||||
case Opcodes.ICONST_1:
|
||||
case Opcodes.ICONST_2:
|
||||
case Opcodes.ICONST_3:
|
||||
case Opcodes.ICONST_4:
|
||||
case Opcodes.ICONST_5:
|
||||
case Opcodes.LCONST_0:
|
||||
case Opcodes.LCONST_1:
|
||||
case Opcodes.FCONST_0:
|
||||
case Opcodes.FCONST_1:
|
||||
case Opcodes.FCONST_2:
|
||||
case Opcodes.DCONST_0:
|
||||
case Opcodes.DCONST_1:
|
||||
case Opcodes.BIPUSH:
|
||||
case Opcodes.SIPUSH:
|
||||
case Opcodes.LDC:
|
||||
push(interpreter.newOperation(insn));
|
||||
break;
|
||||
case Opcodes.ILOAD:
|
||||
case Opcodes.LLOAD:
|
||||
case Opcodes.FLOAD:
|
||||
case Opcodes.DLOAD:
|
||||
case Opcodes.ALOAD:
|
||||
push(interpreter.copyOperation(insn,
|
||||
getLocal(((VarInsnNode) insn).var)));
|
||||
break;
|
||||
case Opcodes.IALOAD:
|
||||
case Opcodes.LALOAD:
|
||||
case Opcodes.FALOAD:
|
||||
case Opcodes.DALOAD:
|
||||
case Opcodes.AALOAD:
|
||||
case Opcodes.BALOAD:
|
||||
case Opcodes.CALOAD:
|
||||
case Opcodes.SALOAD:
|
||||
value2 = pop();
|
||||
value1 = pop();
|
||||
push(interpreter.binaryOperation(insn, value1, value2));
|
||||
break;
|
||||
case Opcodes.ISTORE:
|
||||
case Opcodes.LSTORE:
|
||||
case Opcodes.FSTORE:
|
||||
case Opcodes.DSTORE:
|
||||
case Opcodes.ASTORE:
|
||||
value1 = interpreter.copyOperation(insn, pop());
|
||||
var = ((VarInsnNode) insn).var;
|
||||
setLocal(var, value1);
|
||||
if (value1.getSize() == 2) {
|
||||
setLocal(var + 1, interpreter.newValue(null));
|
||||
}
|
||||
if (var > 0) {
|
||||
Value local = getLocal(var - 1);
|
||||
if (local != null && local.getSize() == 2) {
|
||||
setLocal(var - 1, interpreter.newValue(null));
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Opcodes.IASTORE:
|
||||
case Opcodes.LASTORE:
|
||||
case Opcodes.FASTORE:
|
||||
case Opcodes.DASTORE:
|
||||
case Opcodes.AASTORE:
|
||||
case Opcodes.BASTORE:
|
||||
case Opcodes.CASTORE:
|
||||
case Opcodes.SASTORE:
|
||||
value3 = pop();
|
||||
value2 = pop();
|
||||
value1 = pop();
|
||||
interpreter.ternaryOperation(insn, value1, value2, value3);
|
||||
break;
|
||||
case Opcodes.POP:
|
||||
if (pop().getSize() == 2) {
|
||||
throw new AnalyzerException(insn, "Illegal use of POP");
|
||||
}
|
||||
break;
|
||||
case Opcodes.POP2:
|
||||
if (pop().getSize() == 1) {
|
||||
if (pop().getSize() != 1) {
|
||||
throw new AnalyzerException(insn, "Illegal use of POP2");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Opcodes.DUP:
|
||||
value1 = pop();
|
||||
if (value1.getSize() != 1) {
|
||||
throw new AnalyzerException(insn, "Illegal use of DUP");
|
||||
}
|
||||
push(value1);
|
||||
push(interpreter.copyOperation(insn, value1));
|
||||
break;
|
||||
case Opcodes.DUP_X1:
|
||||
value1 = pop();
|
||||
value2 = pop();
|
||||
if (value1.getSize() != 1 || value2.getSize() != 1) {
|
||||
throw new AnalyzerException(insn, "Illegal use of DUP_X1");
|
||||
}
|
||||
push(interpreter.copyOperation(insn, value1));
|
||||
push(value2);
|
||||
push(value1);
|
||||
break;
|
||||
case Opcodes.DUP_X2:
|
||||
value1 = pop();
|
||||
if (value1.getSize() == 1) {
|
||||
value2 = pop();
|
||||
if (value2.getSize() == 1) {
|
||||
value3 = pop();
|
||||
if (value3.getSize() == 1) {
|
||||
push(interpreter.copyOperation(insn, value1));
|
||||
push(value3);
|
||||
push(value2);
|
||||
push(value1);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
push(interpreter.copyOperation(insn, value1));
|
||||
push(value2);
|
||||
push(value1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
throw new AnalyzerException(insn, "Illegal use of DUP_X2");
|
||||
case Opcodes.DUP2:
|
||||
value1 = pop();
|
||||
if (value1.getSize() == 1) {
|
||||
value2 = pop();
|
||||
if (value2.getSize() == 1) {
|
||||
push(value2);
|
||||
push(value1);
|
||||
push(interpreter.copyOperation(insn, value2));
|
||||
push(interpreter.copyOperation(insn, value1));
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
push(value1);
|
||||
push(interpreter.copyOperation(insn, value1));
|
||||
break;
|
||||
}
|
||||
throw new AnalyzerException(insn, "Illegal use of DUP2");
|
||||
case Opcodes.DUP2_X1:
|
||||
value1 = pop();
|
||||
if (value1.getSize() == 1) {
|
||||
value2 = pop();
|
||||
if (value2.getSize() == 1) {
|
||||
value3 = pop();
|
||||
if (value3.getSize() == 1) {
|
||||
push(interpreter.copyOperation(insn, value2));
|
||||
push(interpreter.copyOperation(insn, value1));
|
||||
push(value3);
|
||||
push(value2);
|
||||
push(value1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
value2 = pop();
|
||||
if (value2.getSize() == 1) {
|
||||
push(interpreter.copyOperation(insn, value1));
|
||||
push(value2);
|
||||
push(value1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
throw new AnalyzerException(insn, "Illegal use of DUP2_X1");
|
||||
case Opcodes.DUP2_X2:
|
||||
value1 = pop();
|
||||
if (value1.getSize() == 1) {
|
||||
value2 = pop();
|
||||
if (value2.getSize() == 1) {
|
||||
value3 = pop();
|
||||
if (value3.getSize() == 1) {
|
||||
value4 = pop();
|
||||
if (value4.getSize() == 1) {
|
||||
push(interpreter.copyOperation(insn, value2));
|
||||
push(interpreter.copyOperation(insn, value1));
|
||||
push(value4);
|
||||
push(value3);
|
||||
push(value2);
|
||||
push(value1);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
push(interpreter.copyOperation(insn, value2));
|
||||
push(interpreter.copyOperation(insn, value1));
|
||||
push(value3);
|
||||
push(value2);
|
||||
push(value1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
value2 = pop();
|
||||
if (value2.getSize() == 1) {
|
||||
value3 = pop();
|
||||
if (value3.getSize() == 1) {
|
||||
push(interpreter.copyOperation(insn, value1));
|
||||
push(value3);
|
||||
push(value2);
|
||||
push(value1);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
push(interpreter.copyOperation(insn, value1));
|
||||
push(value2);
|
||||
push(value1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
throw new AnalyzerException(insn, "Illegal use of DUP2_X2");
|
||||
case Opcodes.SWAP:
|
||||
value2 = pop();
|
||||
value1 = pop();
|
||||
if (value1.getSize() != 1 || value2.getSize() != 1) {
|
||||
throw new AnalyzerException(insn, "Illegal use of SWAP");
|
||||
}
|
||||
push(interpreter.copyOperation(insn, value2));
|
||||
push(interpreter.copyOperation(insn, value1));
|
||||
break;
|
||||
case Opcodes.IADD:
|
||||
case Opcodes.LADD:
|
||||
case Opcodes.FADD:
|
||||
case Opcodes.DADD:
|
||||
case Opcodes.ISUB:
|
||||
case Opcodes.LSUB:
|
||||
case Opcodes.FSUB:
|
||||
case Opcodes.DSUB:
|
||||
case Opcodes.IMUL:
|
||||
case Opcodes.LMUL:
|
||||
case Opcodes.FMUL:
|
||||
case Opcodes.DMUL:
|
||||
case Opcodes.IDIV:
|
||||
case Opcodes.LDIV:
|
||||
case Opcodes.FDIV:
|
||||
case Opcodes.DDIV:
|
||||
case Opcodes.IREM:
|
||||
case Opcodes.LREM:
|
||||
case Opcodes.FREM:
|
||||
case Opcodes.DREM:
|
||||
value2 = pop();
|
||||
value1 = pop();
|
||||
push(interpreter.binaryOperation(insn, value1, value2));
|
||||
break;
|
||||
case Opcodes.INEG:
|
||||
case Opcodes.LNEG:
|
||||
case Opcodes.FNEG:
|
||||
case Opcodes.DNEG:
|
||||
push(interpreter.unaryOperation(insn, pop()));
|
||||
break;
|
||||
case Opcodes.ISHL:
|
||||
case Opcodes.LSHL:
|
||||
case Opcodes.ISHR:
|
||||
case Opcodes.LSHR:
|
||||
case Opcodes.IUSHR:
|
||||
case Opcodes.LUSHR:
|
||||
case Opcodes.IAND:
|
||||
case Opcodes.LAND:
|
||||
case Opcodes.IOR:
|
||||
case Opcodes.LOR:
|
||||
case Opcodes.IXOR:
|
||||
case Opcodes.LXOR:
|
||||
value2 = pop();
|
||||
value1 = pop();
|
||||
push(interpreter.binaryOperation(insn, value1, value2));
|
||||
break;
|
||||
case Opcodes.IINC:
|
||||
var = ((IincInsnNode) insn).var;
|
||||
setLocal(var, interpreter.unaryOperation(insn, getLocal(var)));
|
||||
break;
|
||||
case Opcodes.I2L:
|
||||
case Opcodes.I2F:
|
||||
case Opcodes.I2D:
|
||||
case Opcodes.L2I:
|
||||
case Opcodes.L2F:
|
||||
case Opcodes.L2D:
|
||||
case Opcodes.F2I:
|
||||
case Opcodes.F2L:
|
||||
case Opcodes.F2D:
|
||||
case Opcodes.D2I:
|
||||
case Opcodes.D2L:
|
||||
case Opcodes.D2F:
|
||||
case Opcodes.I2B:
|
||||
case Opcodes.I2C:
|
||||
case Opcodes.I2S:
|
||||
push(interpreter.unaryOperation(insn, pop()));
|
||||
break;
|
||||
case Opcodes.LCMP:
|
||||
case Opcodes.FCMPL:
|
||||
case Opcodes.FCMPG:
|
||||
case Opcodes.DCMPL:
|
||||
case Opcodes.DCMPG:
|
||||
value2 = pop();
|
||||
value1 = pop();
|
||||
push(interpreter.binaryOperation(insn, value1, value2));
|
||||
break;
|
||||
case Opcodes.IFEQ:
|
||||
case Opcodes.IFNE:
|
||||
case Opcodes.IFLT:
|
||||
case Opcodes.IFGE:
|
||||
case Opcodes.IFGT:
|
||||
case Opcodes.IFLE:
|
||||
interpreter.unaryOperation(insn, pop());
|
||||
break;
|
||||
case Opcodes.IF_ICMPEQ:
|
||||
case Opcodes.IF_ICMPNE:
|
||||
case Opcodes.IF_ICMPLT:
|
||||
case Opcodes.IF_ICMPGE:
|
||||
case Opcodes.IF_ICMPGT:
|
||||
case Opcodes.IF_ICMPLE:
|
||||
case Opcodes.IF_ACMPEQ:
|
||||
case Opcodes.IF_ACMPNE:
|
||||
value2 = pop();
|
||||
value1 = pop();
|
||||
interpreter.binaryOperation(insn, value1, value2);
|
||||
break;
|
||||
case Opcodes.GOTO:
|
||||
break;
|
||||
case Opcodes.JSR:
|
||||
push(interpreter.newOperation(insn));
|
||||
break;
|
||||
case Opcodes.RET:
|
||||
break;
|
||||
case Opcodes.TABLESWITCH:
|
||||
case Opcodes.LOOKUPSWITCH:
|
||||
interpreter.unaryOperation(insn, pop());
|
||||
break;
|
||||
case Opcodes.IRETURN:
|
||||
case Opcodes.LRETURN:
|
||||
case Opcodes.FRETURN:
|
||||
case Opcodes.DRETURN:
|
||||
case Opcodes.ARETURN:
|
||||
value1 = pop();
|
||||
interpreter.unaryOperation(insn, value1);
|
||||
interpreter.returnOperation(insn, value1, returnValue);
|
||||
break;
|
||||
case Opcodes.RETURN:
|
||||
if (returnValue != null) {
|
||||
throw new AnalyzerException(insn, "Incompatible return type");
|
||||
}
|
||||
break;
|
||||
case Opcodes.GETSTATIC:
|
||||
push(interpreter.newOperation(insn));
|
||||
break;
|
||||
case Opcodes.PUTSTATIC:
|
||||
interpreter.unaryOperation(insn, pop());
|
||||
break;
|
||||
case Opcodes.GETFIELD:
|
||||
push(interpreter.unaryOperation(insn, pop()));
|
||||
break;
|
||||
case Opcodes.PUTFIELD:
|
||||
value2 = pop();
|
||||
value1 = pop();
|
||||
interpreter.binaryOperation(insn, value1, value2);
|
||||
break;
|
||||
case Opcodes.INVOKEVIRTUAL:
|
||||
case Opcodes.INVOKESPECIAL:
|
||||
case Opcodes.INVOKESTATIC:
|
||||
case Opcodes.INVOKEINTERFACE: {
|
||||
values = new ArrayList<V>();
|
||||
String desc = ((MethodInsnNode) insn).desc;
|
||||
for (int i = Type.getArgumentTypes(desc).length; i > 0; --i) {
|
||||
values.add(0, pop());
|
||||
}
|
||||
if (insn.getOpcode() != Opcodes.INVOKESTATIC) {
|
||||
values.add(0, pop());
|
||||
}
|
||||
if (Type.getReturnType(desc) == Type.VOID_TYPE) {
|
||||
interpreter.naryOperation(insn, values);
|
||||
} else {
|
||||
push(interpreter.naryOperation(insn, values));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Opcodes.INVOKEDYNAMIC: {
|
||||
values = new ArrayList<V>();
|
||||
String desc = ((InvokeDynamicInsnNode) insn).desc;
|
||||
for (int i = Type.getArgumentTypes(desc).length; i > 0; --i) {
|
||||
values.add(0, pop());
|
||||
}
|
||||
if (Type.getReturnType(desc) == Type.VOID_TYPE) {
|
||||
interpreter.naryOperation(insn, values);
|
||||
} else {
|
||||
push(interpreter.naryOperation(insn, values));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Opcodes.NEW:
|
||||
push(interpreter.newOperation(insn));
|
||||
break;
|
||||
case Opcodes.NEWARRAY:
|
||||
case Opcodes.ANEWARRAY:
|
||||
case Opcodes.ARRAYLENGTH:
|
||||
push(interpreter.unaryOperation(insn, pop()));
|
||||
break;
|
||||
case Opcodes.ATHROW:
|
||||
interpreter.unaryOperation(insn, pop());
|
||||
break;
|
||||
case Opcodes.CHECKCAST:
|
||||
case Opcodes.INSTANCEOF:
|
||||
push(interpreter.unaryOperation(insn, pop()));
|
||||
break;
|
||||
case Opcodes.MONITORENTER:
|
||||
case Opcodes.MONITOREXIT:
|
||||
interpreter.unaryOperation(insn, pop());
|
||||
break;
|
||||
case Opcodes.MULTIANEWARRAY:
|
||||
values = new ArrayList<V>();
|
||||
for (int i = ((MultiANewArrayInsnNode) insn).dims; i > 0; --i) {
|
||||
values.add(0, pop());
|
||||
}
|
||||
push(interpreter.naryOperation(insn, values));
|
||||
break;
|
||||
case Opcodes.IFNULL:
|
||||
case Opcodes.IFNONNULL:
|
||||
interpreter.unaryOperation(insn, pop());
|
||||
break;
|
||||
default:
|
||||
throw new RuntimeException("Illegal opcode " + insn.getOpcode());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges this frame with the given frame.
|
||||
*
|
||||
* @param frame
|
||||
* a frame.
|
||||
* @param interpreter
|
||||
* the interpreter used to merge values.
|
||||
* @return <tt>true</tt> if this frame has been changed as a result of the
|
||||
* merge operation, or <tt>false</tt> otherwise.
|
||||
* @throws org.objectweb.asm.tree.analysis.AnalyzerException
|
||||
* if the frames have incompatible sizes.
|
||||
*/
|
||||
public boolean merge(final Frame<? extends V> frame,
|
||||
final Interpreter<V> interpreter) throws AnalyzerException {
|
||||
if (top != frame.top) {
|
||||
throw new AnalyzerException(null, "Incompatible stack heights");
|
||||
}
|
||||
boolean changes = false;
|
||||
for (int i = 0; i < locals + top; ++i) {
|
||||
V v = interpreter.merge(values[i], frame.values[i]);
|
||||
if (!v.equals(values[i])) {
|
||||
values[i] = v;
|
||||
changes = true;
|
||||
}
|
||||
}
|
||||
return changes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges this frame with the given frame (case of a RET instruction).
|
||||
*
|
||||
* @param frame
|
||||
* a frame
|
||||
* @param access
|
||||
* the local variables that have been accessed by the subroutine
|
||||
* to which the RET instruction corresponds.
|
||||
* @return <tt>true</tt> if this frame has been changed as a result of the
|
||||
* merge operation, or <tt>false</tt> otherwise.
|
||||
*/
|
||||
public boolean merge(final Frame<? extends V> frame, final boolean[] access) {
|
||||
boolean changes = false;
|
||||
for (int i = 0; i < locals; ++i) {
|
||||
if (!access[i] && !values[i].equals(frame.values[i])) {
|
||||
values[i] = frame.values[i];
|
||||
changes = true;
|
||||
}
|
||||
}
|
||||
return changes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of this frame.
|
||||
*
|
||||
* @return a string representation of this frame.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuffer b = new StringBuffer();
|
||||
for (int i = 0; i < getLocals(); ++i) {
|
||||
b.append(getLocal(i));
|
||||
}
|
||||
b.append(' ');
|
||||
for (int i = 0; i < getStackSize(); ++i) {
|
||||
b.append(getStack(i).toString());
|
||||
}
|
||||
return b.toString();
|
||||
}
|
||||
}
|
||||
@@ -1,226 +0,0 @@
|
||||
/***
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 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.tree.analysis;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.tree.AbstractInsnNode;
|
||||
|
||||
/**
|
||||
* A semantic bytecode interpreter. More precisely, this interpreter only
|
||||
* manages the computation of values from other values: it does not manage the
|
||||
* transfer of values to or from the stack, and to or from the local variables.
|
||||
* This separation allows a generic bytecode {@link org.objectweb.asm.tree.analysis.Analyzer} to work with
|
||||
* various semantic interpreters, without needing to duplicate the code to
|
||||
* simulate the transfer of values.
|
||||
*
|
||||
* @param <V>
|
||||
* type of the Value used for the analysis.
|
||||
*
|
||||
* @author Eric Bruneton
|
||||
*/
|
||||
public abstract class Interpreter<V extends Value> {
|
||||
|
||||
protected final int api;
|
||||
|
||||
protected Interpreter(final int api) {
|
||||
this.api = api;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new value that represents the given type.
|
||||
*
|
||||
* Called for method parameters (including <code>this</code>), exception
|
||||
* handler variable and with <code>null</code> type for variables reserved
|
||||
* by long and double types.
|
||||
*
|
||||
* @param type
|
||||
* a primitive or reference type, or <tt>null</tt> to represent
|
||||
* an uninitialized value.
|
||||
* @return a value that represents the given type. The size of the returned
|
||||
* value must be equal to the size of the given type.
|
||||
*/
|
||||
public abstract V newValue(Type type);
|
||||
|
||||
/**
|
||||
* Interprets a bytecode instruction without arguments. This method is
|
||||
* called for the following opcodes:
|
||||
*
|
||||
* ACONST_NULL, ICONST_M1, ICONST_0, ICONST_1, ICONST_2, ICONST_3, ICONST_4,
|
||||
* ICONST_5, LCONST_0, LCONST_1, FCONST_0, FCONST_1, FCONST_2, DCONST_0,
|
||||
* DCONST_1, BIPUSH, SIPUSH, LDC, JSR, GETSTATIC, NEW
|
||||
*
|
||||
* @param insn
|
||||
* the bytecode instruction to be interpreted.
|
||||
* @return the result of the interpretation of the given instruction.
|
||||
* @throws org.objectweb.asm.tree.analysis.AnalyzerException
|
||||
* if an error occured during the interpretation.
|
||||
*/
|
||||
public abstract V newOperation(AbstractInsnNode insn)
|
||||
throws AnalyzerException;
|
||||
|
||||
/**
|
||||
* Interprets a bytecode instruction that moves a value on the stack or to
|
||||
* or from local variables. This method is called for the following opcodes:
|
||||
*
|
||||
* ILOAD, LLOAD, FLOAD, DLOAD, ALOAD, ISTORE, LSTORE, FSTORE, DSTORE,
|
||||
* ASTORE, DUP, DUP_X1, DUP_X2, DUP2, DUP2_X1, DUP2_X2, SWAP
|
||||
*
|
||||
* @param insn
|
||||
* the bytecode instruction to be interpreted.
|
||||
* @param value
|
||||
* the value that must be moved by the instruction.
|
||||
* @return the result of the interpretation of the given instruction. The
|
||||
* returned value must be <tt>equal</tt> to the given value.
|
||||
* @throws org.objectweb.asm.tree.analysis.AnalyzerException
|
||||
* if an error occured during the interpretation.
|
||||
*/
|
||||
public abstract V copyOperation(AbstractInsnNode insn, V value)
|
||||
throws AnalyzerException;
|
||||
|
||||
/**
|
||||
* Interprets a bytecode instruction with a single argument. This method is
|
||||
* called for the following opcodes:
|
||||
*
|
||||
* INEG, LNEG, FNEG, DNEG, IINC, I2L, I2F, I2D, L2I, L2F, L2D, F2I, F2L,
|
||||
* F2D, D2I, D2L, D2F, I2B, I2C, I2S, IFEQ, IFNE, IFLT, IFGE, IFGT, IFLE,
|
||||
* TABLESWITCH, LOOKUPSWITCH, IRETURN, LRETURN, FRETURN, DRETURN, ARETURN,
|
||||
* PUTSTATIC, GETFIELD, NEWARRAY, ANEWARRAY, ARRAYLENGTH, ATHROW, CHECKCAST,
|
||||
* INSTANCEOF, MONITORENTER, MONITOREXIT, IFNULL, IFNONNULL
|
||||
*
|
||||
* @param insn
|
||||
* the bytecode instruction to be interpreted.
|
||||
* @param value
|
||||
* the argument of the instruction to be interpreted.
|
||||
* @return the result of the interpretation of the given instruction.
|
||||
* @throws org.objectweb.asm.tree.analysis.AnalyzerException
|
||||
* if an error occured during the interpretation.
|
||||
*/
|
||||
public abstract V unaryOperation(AbstractInsnNode insn, V value)
|
||||
throws AnalyzerException;
|
||||
|
||||
/**
|
||||
* Interprets a bytecode instruction with two arguments. This method is
|
||||
* called for the following opcodes:
|
||||
*
|
||||
* IALOAD, LALOAD, FALOAD, DALOAD, AALOAD, BALOAD, CALOAD, SALOAD, IADD,
|
||||
* LADD, FADD, DADD, ISUB, LSUB, FSUB, DSUB, IMUL, LMUL, FMUL, DMUL, IDIV,
|
||||
* LDIV, FDIV, DDIV, IREM, LREM, FREM, DREM, ISHL, LSHL, ISHR, LSHR, IUSHR,
|
||||
* LUSHR, IAND, LAND, IOR, LOR, IXOR, LXOR, LCMP, FCMPL, FCMPG, DCMPL,
|
||||
* DCMPG, IF_ICMPEQ, IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE,
|
||||
* IF_ACMPEQ, IF_ACMPNE, PUTFIELD
|
||||
*
|
||||
* @param insn
|
||||
* the bytecode instruction to be interpreted.
|
||||
* @param value1
|
||||
* the first argument of the instruction to be interpreted.
|
||||
* @param value2
|
||||
* the second argument of the instruction to be interpreted.
|
||||
* @return the result of the interpretation of the given instruction.
|
||||
* @throws org.objectweb.asm.tree.analysis.AnalyzerException
|
||||
* if an error occured during the interpretation.
|
||||
*/
|
||||
public abstract V binaryOperation(AbstractInsnNode insn, V value1, V value2)
|
||||
throws AnalyzerException;
|
||||
|
||||
/**
|
||||
* Interprets a bytecode instruction with three arguments. This method is
|
||||
* called for the following opcodes:
|
||||
*
|
||||
* IASTORE, LASTORE, FASTORE, DASTORE, AASTORE, BASTORE, CASTORE, SASTORE
|
||||
*
|
||||
* @param insn
|
||||
* the bytecode instruction to be interpreted.
|
||||
* @param value1
|
||||
* the first argument of the instruction to be interpreted.
|
||||
* @param value2
|
||||
* the second argument of the instruction to be interpreted.
|
||||
* @param value3
|
||||
* the third argument of the instruction to be interpreted.
|
||||
* @return the result of the interpretation of the given instruction.
|
||||
* @throws org.objectweb.asm.tree.analysis.AnalyzerException
|
||||
* if an error occured during the interpretation.
|
||||
*/
|
||||
public abstract V ternaryOperation(AbstractInsnNode insn, V value1,
|
||||
V value2, V value3) throws AnalyzerException;
|
||||
|
||||
/**
|
||||
* Interprets a bytecode instruction with a variable number of arguments.
|
||||
* This method is called for the following opcodes:
|
||||
*
|
||||
* INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC, INVOKEINTERFACE,
|
||||
* MULTIANEWARRAY and INVOKEDYNAMIC
|
||||
*
|
||||
* @param insn
|
||||
* the bytecode instruction to be interpreted.
|
||||
* @param values
|
||||
* the arguments of the instruction to be interpreted.
|
||||
* @return the result of the interpretation of the given instruction.
|
||||
* @throws org.objectweb.asm.tree.analysis.AnalyzerException
|
||||
* if an error occured during the interpretation.
|
||||
*/
|
||||
public abstract V naryOperation(AbstractInsnNode insn,
|
||||
List<? extends V> values) throws AnalyzerException;
|
||||
|
||||
/**
|
||||
* Interprets a bytecode return instruction. This method is called for the
|
||||
* following opcodes:
|
||||
*
|
||||
* IRETURN, LRETURN, FRETURN, DRETURN, ARETURN
|
||||
*
|
||||
* @param insn
|
||||
* the bytecode instruction to be interpreted.
|
||||
* @param value
|
||||
* the argument of the instruction to be interpreted.
|
||||
* @param expected
|
||||
* the expected return type of the analyzed method.
|
||||
* @throws org.objectweb.asm.tree.analysis.AnalyzerException
|
||||
* if an error occured during the interpretation.
|
||||
*/
|
||||
public abstract void returnOperation(AbstractInsnNode insn, V value,
|
||||
V expected) throws AnalyzerException;
|
||||
|
||||
/**
|
||||
* Merges two values. The merge operation must return a value that
|
||||
* represents both values (for instance, if the two values are two types,
|
||||
* the merged value must be a common super type of the two types. If the two
|
||||
* values are integer intervals, the merged value must be an interval that
|
||||
* contains the previous ones. Likewise for other types of values).
|
||||
*
|
||||
* @param v
|
||||
* a value.
|
||||
* @param w
|
||||
* another value.
|
||||
* @return the merged value. If the merged value is equal to <tt>v</tt>,
|
||||
* this method <i>must</i> return <tt>v</tt>.
|
||||
*/
|
||||
public abstract V merge(V v, V w);
|
||||
}
|
||||
@@ -1,320 +0,0 @@
|
||||
/***
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 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.tree.analysis;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.objectweb.asm.Type;
|
||||
|
||||
/**
|
||||
* An extended {@link org.objectweb.asm.tree.analysis.BasicVerifier} that performs more precise verifications.
|
||||
* This verifier computes exact class types, instead of using a single "object
|
||||
* reference" type (as done in the {@link org.objectweb.asm.tree.analysis.BasicVerifier}).
|
||||
*
|
||||
* @author Eric Bruneton
|
||||
* @author Bing Ran
|
||||
*/
|
||||
public class SimpleVerifier extends BasicVerifier {
|
||||
|
||||
/**
|
||||
* The class that is verified.
|
||||
*/
|
||||
private final Type currentClass;
|
||||
|
||||
/**
|
||||
* The super class of the class that is verified.
|
||||
*/
|
||||
private final Type currentSuperClass;
|
||||
|
||||
/**
|
||||
* The interfaces implemented by the class that is verified.
|
||||
*/
|
||||
private final List<Type> currentClassInterfaces;
|
||||
|
||||
/**
|
||||
* If the class that is verified is an interface.
|
||||
*/
|
||||
private final boolean isInterface;
|
||||
|
||||
/**
|
||||
* The loader to use for referenced classes.
|
||||
*/
|
||||
private ClassLoader loader = getClass().getClassLoader();
|
||||
|
||||
/**
|
||||
* Constructs a new {@link org.objectweb.asm.tree.analysis.SimpleVerifier}.
|
||||
*/
|
||||
public SimpleVerifier() {
|
||||
this(null, null, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@link org.objectweb.asm.tree.analysis.SimpleVerifier} to verify a specific class. This
|
||||
* class will not be loaded into the JVM since it may be incorrect.
|
||||
*
|
||||
* @param currentClass
|
||||
* the class that is verified.
|
||||
* @param currentSuperClass
|
||||
* the super class of the class that is verified.
|
||||
* @param isInterface
|
||||
* if the class that is verified is an interface.
|
||||
*/
|
||||
public SimpleVerifier(final Type currentClass,
|
||||
final Type currentSuperClass, final boolean isInterface) {
|
||||
this(currentClass, currentSuperClass, null, isInterface);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@link org.objectweb.asm.tree.analysis.SimpleVerifier} to verify a specific class. This
|
||||
* class will not be loaded into the JVM since it may be incorrect.
|
||||
*
|
||||
* @param currentClass
|
||||
* the class that is verified.
|
||||
* @param currentSuperClass
|
||||
* the super class of the class that is verified.
|
||||
* @param currentClassInterfaces
|
||||
* the interfaces implemented by the class that is verified.
|
||||
* @param isInterface
|
||||
* if the class that is verified is an interface.
|
||||
*/
|
||||
public SimpleVerifier(final Type currentClass,
|
||||
final Type currentSuperClass,
|
||||
final List<Type> currentClassInterfaces, final boolean isInterface) {
|
||||
this(ASM4, currentClass, currentSuperClass, currentClassInterfaces,
|
||||
isInterface);
|
||||
}
|
||||
|
||||
protected SimpleVerifier(final int api, final Type currentClass,
|
||||
final Type currentSuperClass,
|
||||
final List<Type> currentClassInterfaces, final boolean isInterface) {
|
||||
super(api);
|
||||
this.currentClass = currentClass;
|
||||
this.currentSuperClass = currentSuperClass;
|
||||
this.currentClassInterfaces = currentClassInterfaces;
|
||||
this.isInterface = isInterface;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the <code>ClassLoader</code> which will be used to load referenced
|
||||
* classes. This is useful if you are verifying multiple interdependent
|
||||
* classes.
|
||||
*
|
||||
* @param loader
|
||||
* a <code>ClassLoader</code> to use
|
||||
*/
|
||||
public void setClassLoader(final ClassLoader loader) {
|
||||
this.loader = loader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasicValue newValue(final Type type) {
|
||||
if (type == null) {
|
||||
return BasicValue.UNINITIALIZED_VALUE;
|
||||
}
|
||||
|
||||
boolean isArray = type.getSort() == Type.ARRAY;
|
||||
if (isArray) {
|
||||
switch (type.getElementType().getSort()) {
|
||||
case Type.BOOLEAN:
|
||||
case Type.CHAR:
|
||||
case Type.BYTE:
|
||||
case Type.SHORT:
|
||||
return new BasicValue(type);
|
||||
}
|
||||
}
|
||||
|
||||
BasicValue v = super.newValue(type);
|
||||
if (BasicValue.REFERENCE_VALUE.equals(v)) {
|
||||
if (isArray) {
|
||||
v = newValue(type.getElementType());
|
||||
String desc = v.getType().getDescriptor();
|
||||
for (int i = 0; i < type.getDimensions(); ++i) {
|
||||
desc = '[' + desc;
|
||||
}
|
||||
v = new BasicValue(Type.getType(desc));
|
||||
} else {
|
||||
v = new BasicValue(type);
|
||||
}
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isArrayValue(final BasicValue value) {
|
||||
Type t = value.getType();
|
||||
return t != null
|
||||
&& ("Lnull;".equals(t.getDescriptor()) || t.getSort() == Type.ARRAY);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BasicValue getElementValue(final BasicValue objectArrayValue)
|
||||
throws AnalyzerException {
|
||||
Type arrayType = objectArrayValue.getType();
|
||||
if (arrayType != null) {
|
||||
if (arrayType.getSort() == Type.ARRAY) {
|
||||
return newValue(Type.getType(arrayType.getDescriptor()
|
||||
.substring(1)));
|
||||
} else if ("Lnull;".equals(arrayType.getDescriptor())) {
|
||||
return objectArrayValue;
|
||||
}
|
||||
}
|
||||
throw new Error("Internal error");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isSubTypeOf(final BasicValue value,
|
||||
final BasicValue expected) {
|
||||
Type expectedType = expected.getType();
|
||||
Type type = value.getType();
|
||||
switch (expectedType.getSort()) {
|
||||
case Type.INT:
|
||||
case Type.FLOAT:
|
||||
case Type.LONG:
|
||||
case Type.DOUBLE:
|
||||
return type.equals(expectedType);
|
||||
case Type.ARRAY:
|
||||
case Type.OBJECT:
|
||||
if ("Lnull;".equals(type.getDescriptor())) {
|
||||
return true;
|
||||
} else if (type.getSort() == Type.OBJECT
|
||||
|| type.getSort() == Type.ARRAY) {
|
||||
return isAssignableFrom(expectedType, type);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
default:
|
||||
throw new Error("Internal error");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasicValue merge(final BasicValue v, final BasicValue w) {
|
||||
if (!v.equals(w)) {
|
||||
Type t = v.getType();
|
||||
Type u = w.getType();
|
||||
if (t != null
|
||||
&& (t.getSort() == Type.OBJECT || t.getSort() == Type.ARRAY)) {
|
||||
if (u != null
|
||||
&& (u.getSort() == Type.OBJECT || u.getSort() == Type.ARRAY)) {
|
||||
if ("Lnull;".equals(t.getDescriptor())) {
|
||||
return w;
|
||||
}
|
||||
if ("Lnull;".equals(u.getDescriptor())) {
|
||||
return v;
|
||||
}
|
||||
if (isAssignableFrom(t, u)) {
|
||||
return v;
|
||||
}
|
||||
if (isAssignableFrom(u, t)) {
|
||||
return w;
|
||||
}
|
||||
// TODO case of array classes of the same dimension
|
||||
// TODO should we look also for a common super interface?
|
||||
// problem: there may be several possible common super
|
||||
// interfaces
|
||||
do {
|
||||
if (t == null || isInterface(t)) {
|
||||
return BasicValue.REFERENCE_VALUE;
|
||||
}
|
||||
t = getSuperClass(t);
|
||||
if (isAssignableFrom(t, u)) {
|
||||
return newValue(t);
|
||||
}
|
||||
} while (true);
|
||||
}
|
||||
}
|
||||
return BasicValue.UNINITIALIZED_VALUE;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
protected boolean isInterface(final Type t) {
|
||||
if (currentClass != null && t.equals(currentClass)) {
|
||||
return isInterface;
|
||||
}
|
||||
return getClass(t).isInterface();
|
||||
}
|
||||
|
||||
protected Type getSuperClass(final Type t) {
|
||||
if (currentClass != null && t.equals(currentClass)) {
|
||||
return currentSuperClass;
|
||||
}
|
||||
Class<?> c = getClass(t).getSuperclass();
|
||||
return c == null ? null : Type.getType(c);
|
||||
}
|
||||
|
||||
protected boolean isAssignableFrom(final Type t, final Type u) {
|
||||
if (t.equals(u)) {
|
||||
return true;
|
||||
}
|
||||
if (currentClass != null && t.equals(currentClass)) {
|
||||
if (getSuperClass(u) == null) {
|
||||
return false;
|
||||
} else {
|
||||
if (isInterface) {
|
||||
return u.getSort() == Type.OBJECT
|
||||
|| u.getSort() == Type.ARRAY;
|
||||
}
|
||||
return isAssignableFrom(t, getSuperClass(u));
|
||||
}
|
||||
}
|
||||
if (currentClass != null && u.equals(currentClass)) {
|
||||
if (isAssignableFrom(t, currentSuperClass)) {
|
||||
return true;
|
||||
}
|
||||
if (currentClassInterfaces != null) {
|
||||
for (int i = 0; i < currentClassInterfaces.size(); ++i) {
|
||||
Type v = currentClassInterfaces.get(i);
|
||||
if (isAssignableFrom(t, v)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
Class<?> tc = getClass(t);
|
||||
if (tc.isInterface()) {
|
||||
tc = Object.class;
|
||||
}
|
||||
return tc.isAssignableFrom(getClass(u));
|
||||
}
|
||||
|
||||
protected Class<?> getClass(final Type t) {
|
||||
try {
|
||||
if (t.getSort() == Type.ARRAY) {
|
||||
return Class.forName(t.getDescriptor().replace('/', '.'),
|
||||
false, loader);
|
||||
}
|
||||
return Class.forName(t.getClassName(), false, loader);
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new RuntimeException(e.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,134 +0,0 @@
|
||||
/***
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 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.tree.analysis;
|
||||
|
||||
import java.util.AbstractSet;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* A set of at most two elements.
|
||||
*
|
||||
* @author Eric Bruneton
|
||||
*/
|
||||
class SmallSet<E> extends AbstractSet<E> implements Iterator<E> {
|
||||
|
||||
// if e1 is null, e2 must be null; otherwise e2 must be different from e1
|
||||
|
||||
E e1, e2;
|
||||
|
||||
static final <T> Set<T> emptySet() {
|
||||
return new SmallSet<T>(null, null);
|
||||
}
|
||||
|
||||
SmallSet(final E e1, final E e2) {
|
||||
this.e1 = e1;
|
||||
this.e2 = e2;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Implementation of inherited abstract methods
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public Iterator<E> iterator() {
|
||||
return new SmallSet<E>(e1, e2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return e1 == null ? 0 : (e2 == null ? 1 : 2);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Implementation of the Iterator interface
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
public boolean hasNext() {
|
||||
return e1 != null;
|
||||
}
|
||||
|
||||
public E next() {
|
||||
if (e1 == null) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
E e = e1;
|
||||
e1 = e2;
|
||||
e2 = null;
|
||||
return e;
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Utility methods
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
Set<E> union(final SmallSet<E> s) {
|
||||
if ((s.e1 == e1 && s.e2 == e2) || (s.e1 == e2 && s.e2 == e1)) {
|
||||
return this; // if the two sets are equal, return this
|
||||
}
|
||||
if (s.e1 == null) {
|
||||
return this; // if s is empty, return this
|
||||
}
|
||||
if (e1 == null) {
|
||||
return s; // if this is empty, return s
|
||||
}
|
||||
if (s.e2 == null) { // s contains exactly one element
|
||||
if (e2 == null) {
|
||||
return new SmallSet<E>(e1, s.e1); // necessarily e1 != s.e1
|
||||
} else if (s.e1 == e1 || s.e1 == e2) { // s is included in this
|
||||
return this;
|
||||
}
|
||||
}
|
||||
if (e2 == null) { // this contains exactly one element
|
||||
// if (s.e2 == null) { // cannot happen
|
||||
// return new SmallSet(e1, s.e1); // necessarily e1 != s.e1
|
||||
// } else
|
||||
if (e1 == s.e1 || e1 == s.e2) { // this in included in s
|
||||
return s;
|
||||
}
|
||||
}
|
||||
// here we know that there are at least 3 distinct elements
|
||||
HashSet<E> r = new HashSet<E>(4);
|
||||
r.add(e1);
|
||||
if (e2 != null) {
|
||||
r.add(e2);
|
||||
}
|
||||
r.add(s.e1);
|
||||
if (s.e2 != null) {
|
||||
r.add(s.e2);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
}
|
||||
@@ -1,198 +0,0 @@
|
||||
/***
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 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.tree.analysis;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.tree.AbstractInsnNode;
|
||||
import org.objectweb.asm.tree.FieldInsnNode;
|
||||
import org.objectweb.asm.tree.InvokeDynamicInsnNode;
|
||||
import org.objectweb.asm.tree.LdcInsnNode;
|
||||
import org.objectweb.asm.tree.MethodInsnNode;
|
||||
|
||||
/**
|
||||
* An {@link org.objectweb.asm.tree.analysis.Interpreter} for {@link SourceValue} values.
|
||||
*
|
||||
* @author Eric Bruneton
|
||||
*/
|
||||
public class SourceInterpreter extends Interpreter<SourceValue> implements
|
||||
Opcodes {
|
||||
|
||||
public SourceInterpreter() {
|
||||
super(ASM4);
|
||||
}
|
||||
|
||||
protected SourceInterpreter(final int api) {
|
||||
super(api);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourceValue newValue(final Type type) {
|
||||
if (type == Type.VOID_TYPE) {
|
||||
return null;
|
||||
}
|
||||
return new SourceValue(type == null ? 1 : type.getSize());
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourceValue newOperation(final AbstractInsnNode insn) {
|
||||
int size;
|
||||
switch (insn.getOpcode()) {
|
||||
case LCONST_0:
|
||||
case LCONST_1:
|
||||
case DCONST_0:
|
||||
case DCONST_1:
|
||||
size = 2;
|
||||
break;
|
||||
case LDC:
|
||||
Object cst = ((LdcInsnNode) insn).cst;
|
||||
size = cst instanceof Long || cst instanceof Double ? 2 : 1;
|
||||
break;
|
||||
case GETSTATIC:
|
||||
size = Type.getType(((FieldInsnNode) insn).desc).getSize();
|
||||
break;
|
||||
default:
|
||||
size = 1;
|
||||
}
|
||||
return new SourceValue(size, insn);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourceValue copyOperation(final AbstractInsnNode insn,
|
||||
final SourceValue value) {
|
||||
return new SourceValue(value.getSize(), insn);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourceValue unaryOperation(final AbstractInsnNode insn,
|
||||
final SourceValue value) {
|
||||
int size;
|
||||
switch (insn.getOpcode()) {
|
||||
case LNEG:
|
||||
case DNEG:
|
||||
case I2L:
|
||||
case I2D:
|
||||
case L2D:
|
||||
case F2L:
|
||||
case F2D:
|
||||
case D2L:
|
||||
size = 2;
|
||||
break;
|
||||
case GETFIELD:
|
||||
size = Type.getType(((FieldInsnNode) insn).desc).getSize();
|
||||
break;
|
||||
default:
|
||||
size = 1;
|
||||
}
|
||||
return new SourceValue(size, insn);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourceValue binaryOperation(final AbstractInsnNode insn,
|
||||
final SourceValue value1, final SourceValue value2) {
|
||||
int size;
|
||||
switch (insn.getOpcode()) {
|
||||
case LALOAD:
|
||||
case DALOAD:
|
||||
case LADD:
|
||||
case DADD:
|
||||
case LSUB:
|
||||
case DSUB:
|
||||
case LMUL:
|
||||
case DMUL:
|
||||
case LDIV:
|
||||
case DDIV:
|
||||
case LREM:
|
||||
case DREM:
|
||||
case LSHL:
|
||||
case LSHR:
|
||||
case LUSHR:
|
||||
case LAND:
|
||||
case LOR:
|
||||
case LXOR:
|
||||
size = 2;
|
||||
break;
|
||||
default:
|
||||
size = 1;
|
||||
}
|
||||
return new SourceValue(size, insn);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourceValue ternaryOperation(final AbstractInsnNode insn,
|
||||
final SourceValue value1, final SourceValue value2,
|
||||
final SourceValue value3) {
|
||||
return new SourceValue(1, insn);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourceValue naryOperation(final AbstractInsnNode insn,
|
||||
final List<? extends SourceValue> values) {
|
||||
int size;
|
||||
int opcode = insn.getOpcode();
|
||||
if (opcode == MULTIANEWARRAY) {
|
||||
size = 1;
|
||||
} else {
|
||||
String desc = (opcode == INVOKEDYNAMIC) ? ((InvokeDynamicInsnNode) insn).desc
|
||||
: ((MethodInsnNode) insn).desc;
|
||||
size = Type.getReturnType(desc).getSize();
|
||||
}
|
||||
return new SourceValue(size, insn);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void returnOperation(final AbstractInsnNode insn,
|
||||
final SourceValue value, final SourceValue expected) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourceValue merge(final SourceValue d, final SourceValue w) {
|
||||
if (d.insns instanceof SmallSet && w.insns instanceof SmallSet) {
|
||||
Set<AbstractInsnNode> s = ((SmallSet<AbstractInsnNode>) d.insns)
|
||||
.union((SmallSet<AbstractInsnNode>) w.insns);
|
||||
if (s == d.insns && d.size == w.size) {
|
||||
return d;
|
||||
} else {
|
||||
return new SourceValue(Math.min(d.size, w.size), s);
|
||||
}
|
||||
}
|
||||
if (d.size != w.size || !d.insns.containsAll(w.insns)) {
|
||||
HashSet<AbstractInsnNode> s = new HashSet<AbstractInsnNode>();
|
||||
s.addAll(d.insns);
|
||||
s.addAll(w.insns);
|
||||
return new SourceValue(Math.min(d.size, w.size), s);
|
||||
}
|
||||
return d;
|
||||
}
|
||||
}
|
||||
@@ -1,97 +0,0 @@
|
||||
/***
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 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.tree.analysis;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.objectweb.asm.tree.AbstractInsnNode;
|
||||
|
||||
/**
|
||||
* A {@link Value} that is represented by its type in a two types type system.
|
||||
* This type system distinguishes the ONEWORD and TWOWORDS types.
|
||||
*
|
||||
* @author Eric Bruneton
|
||||
*/
|
||||
public class SourceValue implements Value {
|
||||
|
||||
/**
|
||||
* The size of this value.
|
||||
*/
|
||||
public final int size;
|
||||
|
||||
/**
|
||||
* The instructions that can produce this value. For example, for the Java
|
||||
* code below, the instructions that can produce the value of <tt>i</tt> at
|
||||
* line 5 are the txo ISTORE instructions at line 1 and 3:
|
||||
*
|
||||
* <pre>
|
||||
* 1: i = 0;
|
||||
* 2: if (...) {
|
||||
* 3: i = 1;
|
||||
* 4: }
|
||||
* 5: return i;
|
||||
* </pre>
|
||||
*
|
||||
* This field is a set of {@link org.objectweb.asm.tree.AbstractInsnNode} objects.
|
||||
*/
|
||||
public final Set<AbstractInsnNode> insns;
|
||||
|
||||
public SourceValue(final int size) {
|
||||
this(size, SmallSet.<AbstractInsnNode> emptySet());
|
||||
}
|
||||
|
||||
public SourceValue(final int size, final AbstractInsnNode insn) {
|
||||
this.size = size;
|
||||
this.insns = new SmallSet<AbstractInsnNode>(insn, null);
|
||||
}
|
||||
|
||||
public SourceValue(final int size, final Set<AbstractInsnNode> insns) {
|
||||
this.size = size;
|
||||
this.insns = insns;
|
||||
}
|
||||
|
||||
public int getSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object value) {
|
||||
if (!(value instanceof SourceValue)) {
|
||||
return false;
|
||||
}
|
||||
SourceValue v = (SourceValue) value;
|
||||
return size == v.size && insns.equals(v.insns);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return insns.hashCode();
|
||||
}
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
/***
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 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.tree.analysis;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.objectweb.asm.tree.JumpInsnNode;
|
||||
import org.objectweb.asm.tree.LabelNode;
|
||||
|
||||
/**
|
||||
* A method subroutine (corresponds to a JSR instruction).
|
||||
*
|
||||
* @author Eric Bruneton
|
||||
*/
|
||||
class Subroutine {
|
||||
|
||||
LabelNode start;
|
||||
|
||||
boolean[] access;
|
||||
|
||||
List<JumpInsnNode> callers;
|
||||
|
||||
private Subroutine() {
|
||||
}
|
||||
|
||||
Subroutine(final LabelNode start, final int maxLocals,
|
||||
final JumpInsnNode caller) {
|
||||
this.start = start;
|
||||
this.access = new boolean[maxLocals];
|
||||
this.callers = new ArrayList<JumpInsnNode>();
|
||||
callers.add(caller);
|
||||
}
|
||||
|
||||
public Subroutine copy() {
|
||||
Subroutine result = new Subroutine();
|
||||
result.start = start;
|
||||
result.access = new boolean[access.length];
|
||||
System.arraycopy(access, 0, result.access, 0, access.length);
|
||||
result.callers = new ArrayList<JumpInsnNode>(callers);
|
||||
return result;
|
||||
}
|
||||
|
||||
public boolean merge(final Subroutine subroutine) throws AnalyzerException {
|
||||
boolean changes = false;
|
||||
for (int i = 0; i < access.length; ++i) {
|
||||
if (subroutine.access[i] && !access[i]) {
|
||||
access[i] = true;
|
||||
changes = true;
|
||||
}
|
||||
}
|
||||
if (subroutine.start == start) {
|
||||
for (int i = 0; i < subroutine.callers.size(); ++i) {
|
||||
JumpInsnNode caller = subroutine.callers.get(i);
|
||||
if (!callers.contains(caller)) {
|
||||
callers.add(caller);
|
||||
changes = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return changes;
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
/***
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 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.tree.analysis;
|
||||
|
||||
/**
|
||||
* An immutable symbolic value for semantic interpretation of bytecode.
|
||||
*
|
||||
* @author Eric Bruneton
|
||||
*/
|
||||
public interface Value {
|
||||
|
||||
/**
|
||||
* Returns the size of this value in words.
|
||||
*
|
||||
* @return either 1 or 2.
|
||||
*/
|
||||
int getSize();
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
<html>
|
||||
<!--
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 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.
|
||||
-->
|
||||
<body>
|
||||
|
||||
<p>
|
||||
Provides a framework for static code analysis based on the asm.tree package.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Basic usage:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
ClassReader cr = new ClassReader(bytecode);
|
||||
ClassNode cn = new ClassNode();
|
||||
cr.accept(cn, ClassReader.SKIP_DEBUG);
|
||||
|
||||
List methods = cn.methods;
|
||||
for (int i = 0; i < methods.size(); ++i) {
|
||||
MethodNode method = (MethodNode) methods.get(i);
|
||||
if (method.instructions.size() > 0) {
|
||||
Analyzer a = new Analyzer(new BasicInterpreter());
|
||||
a.analyze(cn.name, method);
|
||||
Frame[] frames = a.getFrames();
|
||||
// Elements of the frames arrray now contains info for each instruction
|
||||
// from the analyzed method. BasicInterpreter creates BasicValue, that
|
||||
// is using simplified type system that distinguishes the UNINITIALZED,
|
||||
// INT, FLOAT, LONG, DOUBLE, REFERENCE and RETURNADDRESS types.
|
||||
...
|
||||
}
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
@since ASM 1.4.3
|
||||
</p>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,56 +0,0 @@
|
||||
/**
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 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.util;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.objectweb.asm.Label;
|
||||
|
||||
/**
|
||||
* An {@link org.objectweb.asm.Attribute Attribute} that can print the ASM code
|
||||
* to create an equivalent attribute.
|
||||
*
|
||||
* @author Eugene Kuleshov
|
||||
*/
|
||||
public interface ASMifiable {
|
||||
|
||||
/**
|
||||
* Prints the ASM code to create an attribute equal to this attribute.
|
||||
*
|
||||
* @param buf
|
||||
* a buffer used for printing Java code.
|
||||
* @param varName
|
||||
* name of the variable in a printed code used to store attribute
|
||||
* instance.
|
||||
* @param labelNames
|
||||
* map of label instances to their names.
|
||||
*/
|
||||
void asmify(StringBuffer buf, String varName, Map<Label, String> labelNames);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,136 +0,0 @@
|
||||
/***
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 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.util;
|
||||
|
||||
import org.objectweb.asm.AnnotationVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.Type;
|
||||
|
||||
/**
|
||||
* An {@link org.objectweb.asm.AnnotationVisitor} that checks that its methods are properly used.
|
||||
*
|
||||
* @author Eric Bruneton
|
||||
*/
|
||||
public class CheckAnnotationAdapter extends AnnotationVisitor {
|
||||
|
||||
private final boolean named;
|
||||
|
||||
private boolean end;
|
||||
|
||||
public CheckAnnotationAdapter(final AnnotationVisitor av) {
|
||||
this(av, true);
|
||||
}
|
||||
|
||||
CheckAnnotationAdapter(final AnnotationVisitor av, final boolean named) {
|
||||
super(Opcodes.ASM4, av);
|
||||
this.named = named;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(final String name, final Object value) {
|
||||
checkEnd();
|
||||
checkName(name);
|
||||
if (!(value instanceof Byte || value instanceof Boolean
|
||||
|| value instanceof Character || value instanceof Short
|
||||
|| value instanceof Integer || value instanceof Long
|
||||
|| value instanceof Float || value instanceof Double
|
||||
|| value instanceof String || value instanceof Type
|
||||
|| value instanceof byte[] || value instanceof boolean[]
|
||||
|| value instanceof char[] || value instanceof short[]
|
||||
|| value instanceof int[] || value instanceof long[]
|
||||
|| value instanceof float[] || value instanceof double[])) {
|
||||
throw new IllegalArgumentException("Invalid annotation value");
|
||||
}
|
||||
if (value instanceof Type) {
|
||||
int sort = ((Type) value).getSort();
|
||||
if (sort != Type.OBJECT && sort != Type.ARRAY) {
|
||||
throw new IllegalArgumentException("Invalid annotation value");
|
||||
}
|
||||
}
|
||||
if (av != null) {
|
||||
av.visit(name, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnum(final String name, final String desc,
|
||||
final String value) {
|
||||
checkEnd();
|
||||
checkName(name);
|
||||
CheckMethodAdapter.checkDesc(desc, false);
|
||||
if (value == null) {
|
||||
throw new IllegalArgumentException("Invalid enum value");
|
||||
}
|
||||
if (av != null) {
|
||||
av.visitEnum(name, desc, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitAnnotation(final String name,
|
||||
final String desc) {
|
||||
checkEnd();
|
||||
checkName(name);
|
||||
CheckMethodAdapter.checkDesc(desc, false);
|
||||
return new CheckAnnotationAdapter(av == null ? null
|
||||
: av.visitAnnotation(name, desc));
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitArray(final String name) {
|
||||
checkEnd();
|
||||
checkName(name);
|
||||
return new CheckAnnotationAdapter(av == null ? null
|
||||
: av.visitArray(name), false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
checkEnd();
|
||||
end = true;
|
||||
if (av != null) {
|
||||
av.visitEnd();
|
||||
}
|
||||
}
|
||||
|
||||
private void checkEnd() {
|
||||
if (end) {
|
||||
throw new IllegalStateException(
|
||||
"Cannot call a visit method after visitEnd has been called");
|
||||
}
|
||||
}
|
||||
|
||||
private void checkName(final String name) {
|
||||
if (named && name == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Annotation value name must not be null");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,906 +0,0 @@
|
||||
/***
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 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.util;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.objectweb.asm.AnnotationVisitor;
|
||||
import org.objectweb.asm.Attribute;
|
||||
import org.objectweb.asm.ClassReader;
|
||||
import org.objectweb.asm.ClassVisitor;
|
||||
import org.objectweb.asm.FieldVisitor;
|
||||
import org.objectweb.asm.Label;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import org.objectweb.asm.tree.MethodNode;
|
||||
import org.objectweb.asm.tree.analysis.Analyzer;
|
||||
import org.objectweb.asm.tree.analysis.BasicValue;
|
||||
import org.objectweb.asm.tree.analysis.Frame;
|
||||
import org.objectweb.asm.tree.analysis.SimpleVerifier;
|
||||
|
||||
/**
|
||||
* A {@link org.objectweb.asm.ClassVisitor} that checks that its methods are properly used. More
|
||||
* precisely this class adapter checks each method call individually, based
|
||||
* <i>only</i> on its arguments, but does <i>not</i> check the <i>sequence</i>
|
||||
* of method calls. For example, the invalid sequence
|
||||
* <tt>visitField(ACC_PUBLIC, "i", "I", null)</tt> <tt>visitField(ACC_PUBLIC,
|
||||
* "i", "D", null)</tt> will <i>not</i> be detected by this class adapter.
|
||||
*
|
||||
* <p>
|
||||
* <code>CheckClassAdapter</code> can be also used to verify bytecode
|
||||
* transformations in order to make sure transformed bytecode is sane. For
|
||||
* example:
|
||||
*
|
||||
* <pre>
|
||||
* InputStream is = ...; // get bytes for the source class
|
||||
* ClassReader cr = new ClassReader(is);
|
||||
* ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS);
|
||||
* ClassVisitor cv = new <b>MyClassAdapter</b>(new CheckClassAdapter(cw));
|
||||
* cr.accept(cv, 0);
|
||||
*
|
||||
* StringWriter sw = new StringWriter();
|
||||
* PrintWriter pw = new PrintWriter(sw);
|
||||
* CheckClassAdapter.verify(new ClassReader(cw.toByteArray()), false, pw);
|
||||
* assertTrue(sw.toString(), sw.toString().length()==0);
|
||||
* </pre>
|
||||
*
|
||||
* Above code runs transformed bytecode trough the
|
||||
* <code>CheckClassAdapter</code>. It won't be exactly the same verification as
|
||||
* JVM does, but it run data flow analysis for the code of each method and
|
||||
* checks that expectations are met for each method instruction.
|
||||
*
|
||||
* <p>
|
||||
* If method bytecode has errors, assertion text will show the erroneous
|
||||
* instruction number and dump of the failed method with information about
|
||||
* locals and stack slot for each instruction. For example (format is -
|
||||
* insnNumber locals : stack):
|
||||
*
|
||||
* <pre>
|
||||
* org.objectweb.asm.tree.analysis.AnalyzerException: Error at instruction 71: Expected I, but found .
|
||||
* at org.objectweb.asm.tree.analysis.Analyzer.analyze(Analyzer.java:289)
|
||||
* at org.objectweb.asm.util.CheckClassAdapter.verify(CheckClassAdapter.java:135)
|
||||
* ...
|
||||
* remove()V
|
||||
* 00000 LinkedBlockingQueue$Itr . . . . . . . . :
|
||||
* ICONST_0
|
||||
* 00001 LinkedBlockingQueue$Itr . . . . . . . . : I
|
||||
* ISTORE 2
|
||||
* 00001 LinkedBlockingQueue$Itr <b>.</b> I . . . . . . :
|
||||
* ...
|
||||
*
|
||||
* 00071 LinkedBlockingQueue$Itr <b>.</b> I . . . . . . :
|
||||
* ILOAD 1
|
||||
* 00072 <b>?</b>
|
||||
* INVOKESPECIAL java/lang/Integer.<init> (I)V
|
||||
* ...
|
||||
* </pre>
|
||||
*
|
||||
* In the above output you can see that variable 1 loaded by
|
||||
* <code>ILOAD 1</code> instruction at position <code>00071</code> is not
|
||||
* initialized. You can also see that at the beginning of the method (code
|
||||
* inserted by the transformation) variable 2 is initialized.
|
||||
*
|
||||
* <p>
|
||||
* Note that when used like that, <code>CheckClassAdapter.verify()</code> can
|
||||
* trigger additional class loading, because it is using
|
||||
* <code>SimpleVerifier</code>.
|
||||
*
|
||||
* @author Eric Bruneton
|
||||
*/
|
||||
public class CheckClassAdapter extends ClassVisitor {
|
||||
|
||||
/**
|
||||
* The class version number.
|
||||
*/
|
||||
private int version;
|
||||
|
||||
/**
|
||||
* <tt>true</tt> if the visit method has been called.
|
||||
*/
|
||||
private boolean start;
|
||||
|
||||
/**
|
||||
* <tt>true</tt> if the visitSource method has been called.
|
||||
*/
|
||||
private boolean source;
|
||||
|
||||
/**
|
||||
* <tt>true</tt> if the visitOuterClass method has been called.
|
||||
*/
|
||||
private boolean outer;
|
||||
|
||||
/**
|
||||
* <tt>true</tt> if the visitEnd method has been called.
|
||||
*/
|
||||
private boolean end;
|
||||
|
||||
/**
|
||||
* The already visited labels. This map associate Integer values to Label
|
||||
* keys.
|
||||
*/
|
||||
private Map<Label, Integer> labels;
|
||||
|
||||
/**
|
||||
* <tt>true</tt> if the method code must be checked with a BasicVerifier.
|
||||
*/
|
||||
private boolean checkDataFlow;
|
||||
|
||||
/**
|
||||
* Checks a given class.
|
||||
* <p>
|
||||
* Usage: CheckClassAdapter <binary class name or class file name>
|
||||
*
|
||||
* @param args
|
||||
* the command line arguments.
|
||||
*
|
||||
* @throws Exception
|
||||
* if the class cannot be found, or if an IO exception occurs.
|
||||
*/
|
||||
public static void main(final String[] args) throws Exception {
|
||||
if (args.length != 1) {
|
||||
System.err.println("Verifies the given class.");
|
||||
System.err.println("Usage: CheckClassAdapter "
|
||||
+ "<fully qualified class name or class file name>");
|
||||
return;
|
||||
}
|
||||
ClassReader cr;
|
||||
if (args[0].endsWith(".class")) {
|
||||
cr = new ClassReader(new FileInputStream(args[0]));
|
||||
} else {
|
||||
cr = new ClassReader(args[0]);
|
||||
}
|
||||
|
||||
verify(cr, false, new PrintWriter(System.err));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks a given class.
|
||||
*
|
||||
* @param cr
|
||||
* a <code>ClassReader</code> that contains bytecode for the
|
||||
* analysis.
|
||||
* @param loader
|
||||
* a <code>ClassLoader</code> which will be used to load
|
||||
* referenced classes. This is useful if you are verifiying
|
||||
* multiple interdependent classes.
|
||||
* @param dump
|
||||
* true if bytecode should be printed out not only when errors
|
||||
* are found.
|
||||
* @param pw
|
||||
* write where results going to be printed
|
||||
*/
|
||||
public static void verify(final ClassReader cr, final ClassLoader loader,
|
||||
final boolean dump, final PrintWriter pw) {
|
||||
ClassNode cn = new ClassNode();
|
||||
cr.accept(new CheckClassAdapter(cn, false), ClassReader.SKIP_DEBUG);
|
||||
|
||||
Type syperType = cn.superName == null ? null : Type
|
||||
.getObjectType(cn.superName);
|
||||
List<MethodNode> methods = cn.methods;
|
||||
|
||||
List<Type> interfaces = new ArrayList<Type>();
|
||||
for (Iterator<String> i = cn.interfaces.iterator(); i.hasNext();) {
|
||||
interfaces.add(Type.getObjectType(i.next().toString()));
|
||||
}
|
||||
|
||||
for (int i = 0; i < methods.size(); ++i) {
|
||||
MethodNode method = methods.get(i);
|
||||
SimpleVerifier verifier = new SimpleVerifier(
|
||||
Type.getObjectType(cn.name), syperType, interfaces,
|
||||
(cn.access & Opcodes.ACC_INTERFACE) != 0);
|
||||
Analyzer<BasicValue> a = new Analyzer<BasicValue>(verifier);
|
||||
if (loader != null) {
|
||||
verifier.setClassLoader(loader);
|
||||
}
|
||||
try {
|
||||
a.analyze(cn.name, method);
|
||||
if (!dump) {
|
||||
continue;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace(pw);
|
||||
}
|
||||
printAnalyzerResult(method, a, pw);
|
||||
}
|
||||
pw.flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks a given class
|
||||
*
|
||||
* @param cr
|
||||
* a <code>ClassReader</code> that contains bytecode for the
|
||||
* analysis.
|
||||
* @param dump
|
||||
* true if bytecode should be printed out not only when errors
|
||||
* are found.
|
||||
* @param pw
|
||||
* write where results going to be printed
|
||||
*/
|
||||
public static void verify(final ClassReader cr, final boolean dump,
|
||||
final PrintWriter pw) {
|
||||
verify(cr, null, dump, pw);
|
||||
}
|
||||
|
||||
static void printAnalyzerResult(MethodNode method, Analyzer<BasicValue> a,
|
||||
final PrintWriter pw) {
|
||||
Frame<BasicValue>[] frames = a.getFrames();
|
||||
Textifier t = new Textifier();
|
||||
TraceMethodVisitor mv = new TraceMethodVisitor(t);
|
||||
|
||||
pw.println(method.name + method.desc);
|
||||
for (int j = 0; j < method.instructions.size(); ++j) {
|
||||
method.instructions.get(j).accept(mv);
|
||||
|
||||
StringBuffer s = new StringBuffer();
|
||||
Frame<BasicValue> f = frames[j];
|
||||
if (f == null) {
|
||||
s.append('?');
|
||||
} else {
|
||||
for (int k = 0; k < f.getLocals(); ++k) {
|
||||
s.append(getShortName(f.getLocal(k).toString()))
|
||||
.append(' ');
|
||||
}
|
||||
s.append(" : ");
|
||||
for (int k = 0; k < f.getStackSize(); ++k) {
|
||||
s.append(getShortName(f.getStack(k).toString()))
|
||||
.append(' ');
|
||||
}
|
||||
}
|
||||
while (s.length() < method.maxStack + method.maxLocals + 1) {
|
||||
s.append(' ');
|
||||
}
|
||||
pw.print(Integer.toString(j + 100000).substring(1));
|
||||
pw.print(" " + s + " : " + t.text.get(t.text.size() - 1));
|
||||
}
|
||||
for (int j = 0; j < method.tryCatchBlocks.size(); ++j) {
|
||||
method.tryCatchBlocks.get(j).accept(mv);
|
||||
pw.print(" " + t.text.get(t.text.size() - 1));
|
||||
}
|
||||
pw.println();
|
||||
}
|
||||
|
||||
private static String getShortName(final String name) {
|
||||
int n = name.lastIndexOf('/');
|
||||
int k = name.length();
|
||||
if (name.charAt(k - 1) == ';') {
|
||||
k--;
|
||||
}
|
||||
return n == -1 ? name : name.substring(n + 1, k);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@link org.objectweb.asm.util.CheckClassAdapter}. <i>Subclasses must not use
|
||||
* this constructor</i>. Instead, they must use the
|
||||
* {@link #CheckClassAdapter(int, org.objectweb.asm.ClassVisitor, boolean)} version.
|
||||
*
|
||||
* @param cv
|
||||
* the class visitor to which this adapter must delegate calls.
|
||||
*/
|
||||
public CheckClassAdapter(final ClassVisitor cv) {
|
||||
this(cv, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@link org.objectweb.asm.util.CheckClassAdapter}. <i>Subclasses must not use
|
||||
* this constructor</i>. Instead, they must use the
|
||||
* {@link #CheckClassAdapter(int, org.objectweb.asm.ClassVisitor, boolean)} version.
|
||||
*
|
||||
* @param cv
|
||||
* the class visitor to which this adapter must delegate calls.
|
||||
* @param checkDataFlow
|
||||
* <tt>true</tt> to perform basic data flow checks, or
|
||||
* <tt>false</tt> to not perform any data flow check (see
|
||||
* {@link CheckMethodAdapter}). This option requires valid
|
||||
* maxLocals and maxStack values.
|
||||
*/
|
||||
public CheckClassAdapter(final ClassVisitor cv, final boolean checkDataFlow) {
|
||||
this(Opcodes.ASM4, cv, checkDataFlow);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@link org.objectweb.asm.util.CheckClassAdapter}.
|
||||
*
|
||||
* @param api
|
||||
* the ASM API version implemented by this visitor. Must be one
|
||||
* of {@link org.objectweb.asm.Opcodes#ASM4}.
|
||||
* @param cv
|
||||
* the class visitor to which this adapter must delegate calls.
|
||||
* @param checkDataFlow
|
||||
* <tt>true</tt> to perform basic data flow checks, or
|
||||
* <tt>false</tt> to not perform any data flow check (see
|
||||
* {@link CheckMethodAdapter}). This option requires valid
|
||||
* maxLocals and maxStack values.
|
||||
*/
|
||||
protected CheckClassAdapter(final int api, final ClassVisitor cv,
|
||||
final boolean checkDataFlow) {
|
||||
super(api, cv);
|
||||
this.labels = new HashMap<Label, Integer>();
|
||||
this.checkDataFlow = checkDataFlow;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Implementation of the ClassVisitor interface
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public void visit(final int version, final int access, final String name,
|
||||
final String signature, final String superName,
|
||||
final String[] interfaces) {
|
||||
if (start) {
|
||||
throw new IllegalStateException("visit must be called only once");
|
||||
}
|
||||
start = true;
|
||||
checkState();
|
||||
checkAccess(access, Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL
|
||||
+ Opcodes.ACC_SUPER + Opcodes.ACC_INTERFACE
|
||||
+ Opcodes.ACC_ABSTRACT + Opcodes.ACC_SYNTHETIC
|
||||
+ Opcodes.ACC_ANNOTATION + Opcodes.ACC_ENUM
|
||||
+ Opcodes.ACC_DEPRECATED + 0x40000); // ClassWriter.ACC_SYNTHETIC_ATTRIBUTE
|
||||
if (name == null || !name.endsWith("package-info")) {
|
||||
CheckMethodAdapter.checkInternalName(name, "class name");
|
||||
}
|
||||
if ("java/lang/Object".equals(name)) {
|
||||
if (superName != null) {
|
||||
throw new IllegalArgumentException(
|
||||
"The super class name of the Object class must be 'null'");
|
||||
}
|
||||
} else {
|
||||
CheckMethodAdapter.checkInternalName(superName, "super class name");
|
||||
}
|
||||
if (signature != null) {
|
||||
checkClassSignature(signature);
|
||||
}
|
||||
if ((access & Opcodes.ACC_INTERFACE) != 0) {
|
||||
if (!"java/lang/Object".equals(superName)) {
|
||||
throw new IllegalArgumentException(
|
||||
"The super class name of interfaces must be 'java/lang/Object'");
|
||||
}
|
||||
}
|
||||
if (interfaces != null) {
|
||||
for (int i = 0; i < interfaces.length; ++i) {
|
||||
CheckMethodAdapter.checkInternalName(interfaces[i],
|
||||
"interface name at index " + i);
|
||||
}
|
||||
}
|
||||
this.version = version;
|
||||
super.visit(version, access, name, signature, superName, interfaces);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitSource(final String file, final String debug) {
|
||||
checkState();
|
||||
if (source) {
|
||||
throw new IllegalStateException(
|
||||
"visitSource can be called only once.");
|
||||
}
|
||||
source = true;
|
||||
super.visitSource(file, debug);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitOuterClass(final String owner, final String name,
|
||||
final String desc) {
|
||||
checkState();
|
||||
if (outer) {
|
||||
throw new IllegalStateException(
|
||||
"visitOuterClass can be called only once.");
|
||||
}
|
||||
outer = true;
|
||||
if (owner == null) {
|
||||
throw new IllegalArgumentException("Illegal outer class owner");
|
||||
}
|
||||
if (desc != null) {
|
||||
CheckMethodAdapter.checkMethodDesc(desc);
|
||||
}
|
||||
super.visitOuterClass(owner, name, desc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitInnerClass(final String name, final String outerName,
|
||||
final String innerName, final int access) {
|
||||
checkState();
|
||||
CheckMethodAdapter.checkInternalName(name, "class name");
|
||||
if (outerName != null) {
|
||||
CheckMethodAdapter.checkInternalName(outerName, "outer class name");
|
||||
}
|
||||
if (innerName != null) {
|
||||
CheckMethodAdapter.checkIdentifier(innerName, "inner class name");
|
||||
}
|
||||
checkAccess(access, Opcodes.ACC_PUBLIC + Opcodes.ACC_PRIVATE
|
||||
+ Opcodes.ACC_PROTECTED + Opcodes.ACC_STATIC
|
||||
+ Opcodes.ACC_FINAL + Opcodes.ACC_INTERFACE
|
||||
+ Opcodes.ACC_ABSTRACT + Opcodes.ACC_SYNTHETIC
|
||||
+ Opcodes.ACC_ANNOTATION + Opcodes.ACC_ENUM);
|
||||
super.visitInnerClass(name, outerName, innerName, access);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FieldVisitor visitField(final int access, final String name,
|
||||
final String desc, final String signature, final Object value) {
|
||||
checkState();
|
||||
checkAccess(access, Opcodes.ACC_PUBLIC + Opcodes.ACC_PRIVATE
|
||||
+ Opcodes.ACC_PROTECTED + Opcodes.ACC_STATIC
|
||||
+ Opcodes.ACC_FINAL + Opcodes.ACC_VOLATILE
|
||||
+ Opcodes.ACC_TRANSIENT + Opcodes.ACC_SYNTHETIC
|
||||
+ Opcodes.ACC_ENUM + Opcodes.ACC_DEPRECATED + 0x40000); // ClassWriter.ACC_SYNTHETIC_ATTRIBUTE
|
||||
CheckMethodAdapter.checkUnqualifiedName(version, name, "field name");
|
||||
CheckMethodAdapter.checkDesc(desc, false);
|
||||
if (signature != null) {
|
||||
checkFieldSignature(signature);
|
||||
}
|
||||
if (value != null) {
|
||||
CheckMethodAdapter.checkConstant(value);
|
||||
}
|
||||
FieldVisitor av = super
|
||||
.visitField(access, name, desc, signature, value);
|
||||
return new CheckFieldAdapter(av);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodVisitor visitMethod(final int access, final String name,
|
||||
final String desc, final String signature, final String[] exceptions) {
|
||||
checkState();
|
||||
checkAccess(access, Opcodes.ACC_PUBLIC + Opcodes.ACC_PRIVATE
|
||||
+ Opcodes.ACC_PROTECTED + Opcodes.ACC_STATIC
|
||||
+ Opcodes.ACC_FINAL + Opcodes.ACC_SYNCHRONIZED
|
||||
+ Opcodes.ACC_BRIDGE + Opcodes.ACC_VARARGS + Opcodes.ACC_NATIVE
|
||||
+ Opcodes.ACC_ABSTRACT + Opcodes.ACC_STRICT
|
||||
+ Opcodes.ACC_SYNTHETIC + Opcodes.ACC_DEPRECATED + 0x40000); // ClassWriter.ACC_SYNTHETIC_ATTRIBUTE
|
||||
if (!"<init>".equals(name) && !"<clinit>".equals(name)) {
|
||||
CheckMethodAdapter.checkMethodIdentifier(version, name,
|
||||
"method name");
|
||||
}
|
||||
CheckMethodAdapter.checkMethodDesc(desc);
|
||||
if (signature != null) {
|
||||
checkMethodSignature(signature);
|
||||
}
|
||||
if (exceptions != null) {
|
||||
for (int i = 0; i < exceptions.length; ++i) {
|
||||
CheckMethodAdapter.checkInternalName(exceptions[i],
|
||||
"exception name at index " + i);
|
||||
}
|
||||
}
|
||||
CheckMethodAdapter cma;
|
||||
if (checkDataFlow) {
|
||||
cma = new CheckMethodAdapter(access, name, desc, super.visitMethod(
|
||||
access, name, desc, signature, exceptions), labels);
|
||||
} else {
|
||||
cma = new CheckMethodAdapter(super.visitMethod(access, name, desc,
|
||||
signature, exceptions), labels);
|
||||
}
|
||||
cma.version = version;
|
||||
return cma;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitAnnotation(final String desc,
|
||||
final boolean visible) {
|
||||
checkState();
|
||||
CheckMethodAdapter.checkDesc(desc, false);
|
||||
return new CheckAnnotationAdapter(super.visitAnnotation(desc, visible));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitAttribute(final Attribute attr) {
|
||||
checkState();
|
||||
if (attr == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Invalid attribute (must not be null)");
|
||||
}
|
||||
super.visitAttribute(attr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
checkState();
|
||||
end = true;
|
||||
super.visitEnd();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Utility methods
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Checks that the visit method has been called and that visitEnd has not
|
||||
* been called.
|
||||
*/
|
||||
private void checkState() {
|
||||
if (!start) {
|
||||
throw new IllegalStateException(
|
||||
"Cannot visit member before visit has been called.");
|
||||
}
|
||||
if (end) {
|
||||
throw new IllegalStateException(
|
||||
"Cannot visit member after visitEnd has been called.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the given access flags do not contain invalid flags. This
|
||||
* method also checks that mutually incompatible flags are not set
|
||||
* simultaneously.
|
||||
*
|
||||
* @param access
|
||||
* the access flags to be checked
|
||||
* @param possibleAccess
|
||||
* the valid access flags.
|
||||
*/
|
||||
static void checkAccess(final int access, final int possibleAccess) {
|
||||
if ((access & ~possibleAccess) != 0) {
|
||||
throw new IllegalArgumentException("Invalid access flags: "
|
||||
+ access);
|
||||
}
|
||||
int pub = (access & Opcodes.ACC_PUBLIC) == 0 ? 0 : 1;
|
||||
int pri = (access & Opcodes.ACC_PRIVATE) == 0 ? 0 : 1;
|
||||
int pro = (access & Opcodes.ACC_PROTECTED) == 0 ? 0 : 1;
|
||||
if (pub + pri + pro > 1) {
|
||||
throw new IllegalArgumentException(
|
||||
"public private and protected are mutually exclusive: "
|
||||
+ access);
|
||||
}
|
||||
int fin = (access & Opcodes.ACC_FINAL) == 0 ? 0 : 1;
|
||||
int abs = (access & Opcodes.ACC_ABSTRACT) == 0 ? 0 : 1;
|
||||
if (fin + abs > 1) {
|
||||
throw new IllegalArgumentException(
|
||||
"final and abstract are mutually exclusive: " + access);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks a class signature.
|
||||
*
|
||||
* @param signature
|
||||
* a string containing the signature that must be checked.
|
||||
*/
|
||||
public static void checkClassSignature(final String signature) {
|
||||
// ClassSignature:
|
||||
// FormalTypeParameters? ClassTypeSignature ClassTypeSignature*
|
||||
|
||||
int pos = 0;
|
||||
if (getChar(signature, 0) == '<') {
|
||||
pos = checkFormalTypeParameters(signature, pos);
|
||||
}
|
||||
pos = checkClassTypeSignature(signature, pos);
|
||||
while (getChar(signature, pos) == 'L') {
|
||||
pos = checkClassTypeSignature(signature, pos);
|
||||
}
|
||||
if (pos != signature.length()) {
|
||||
throw new IllegalArgumentException(signature + ": error at index "
|
||||
+ pos);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks a method signature.
|
||||
*
|
||||
* @param signature
|
||||
* a string containing the signature that must be checked.
|
||||
*/
|
||||
public static void checkMethodSignature(final String signature) {
|
||||
// MethodTypeSignature:
|
||||
// FormalTypeParameters? ( TypeSignature* ) ( TypeSignature | V ) (
|
||||
// ^ClassTypeSignature | ^TypeVariableSignature )*
|
||||
|
||||
int pos = 0;
|
||||
if (getChar(signature, 0) == '<') {
|
||||
pos = checkFormalTypeParameters(signature, pos);
|
||||
}
|
||||
pos = checkChar('(', signature, pos);
|
||||
while ("ZCBSIFJDL[T".indexOf(getChar(signature, pos)) != -1) {
|
||||
pos = checkTypeSignature(signature, pos);
|
||||
}
|
||||
pos = checkChar(')', signature, pos);
|
||||
if (getChar(signature, pos) == 'V') {
|
||||
++pos;
|
||||
} else {
|
||||
pos = checkTypeSignature(signature, pos);
|
||||
}
|
||||
while (getChar(signature, pos) == '^') {
|
||||
++pos;
|
||||
if (getChar(signature, pos) == 'L') {
|
||||
pos = checkClassTypeSignature(signature, pos);
|
||||
} else {
|
||||
pos = checkTypeVariableSignature(signature, pos);
|
||||
}
|
||||
}
|
||||
if (pos != signature.length()) {
|
||||
throw new IllegalArgumentException(signature + ": error at index "
|
||||
+ pos);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks a field signature.
|
||||
*
|
||||
* @param signature
|
||||
* a string containing the signature that must be checked.
|
||||
*/
|
||||
public static void checkFieldSignature(final String signature) {
|
||||
int pos = checkFieldTypeSignature(signature, 0);
|
||||
if (pos != signature.length()) {
|
||||
throw new IllegalArgumentException(signature + ": error at index "
|
||||
+ pos);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the formal type parameters of a class or method signature.
|
||||
*
|
||||
* @param signature
|
||||
* a string containing the signature that must be checked.
|
||||
* @param pos
|
||||
* index of first character to be checked.
|
||||
* @return the index of the first character after the checked part.
|
||||
*/
|
||||
private static int checkFormalTypeParameters(final String signature, int pos) {
|
||||
// FormalTypeParameters:
|
||||
// < FormalTypeParameter+ >
|
||||
|
||||
pos = checkChar('<', signature, pos);
|
||||
pos = checkFormalTypeParameter(signature, pos);
|
||||
while (getChar(signature, pos) != '>') {
|
||||
pos = checkFormalTypeParameter(signature, pos);
|
||||
}
|
||||
return pos + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks a formal type parameter of a class or method signature.
|
||||
*
|
||||
* @param signature
|
||||
* a string containing the signature that must be checked.
|
||||
* @param pos
|
||||
* index of first character to be checked.
|
||||
* @return the index of the first character after the checked part.
|
||||
*/
|
||||
private static int checkFormalTypeParameter(final String signature, int pos) {
|
||||
// FormalTypeParameter:
|
||||
// Identifier : FieldTypeSignature? (: FieldTypeSignature)*
|
||||
|
||||
pos = checkIdentifier(signature, pos);
|
||||
pos = checkChar(':', signature, pos);
|
||||
if ("L[T".indexOf(getChar(signature, pos)) != -1) {
|
||||
pos = checkFieldTypeSignature(signature, pos);
|
||||
}
|
||||
while (getChar(signature, pos) == ':') {
|
||||
pos = checkFieldTypeSignature(signature, pos + 1);
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks a field type signature.
|
||||
*
|
||||
* @param signature
|
||||
* a string containing the signature that must be checked.
|
||||
* @param pos
|
||||
* index of first character to be checked.
|
||||
* @return the index of the first character after the checked part.
|
||||
*/
|
||||
private static int checkFieldTypeSignature(final String signature, int pos) {
|
||||
// FieldTypeSignature:
|
||||
// ClassTypeSignature | ArrayTypeSignature | TypeVariableSignature
|
||||
//
|
||||
// ArrayTypeSignature:
|
||||
// [ TypeSignature
|
||||
|
||||
switch (getChar(signature, pos)) {
|
||||
case 'L':
|
||||
return checkClassTypeSignature(signature, pos);
|
||||
case '[':
|
||||
return checkTypeSignature(signature, pos + 1);
|
||||
default:
|
||||
return checkTypeVariableSignature(signature, pos);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks a class type signature.
|
||||
*
|
||||
* @param signature
|
||||
* a string containing the signature that must be checked.
|
||||
* @param pos
|
||||
* index of first character to be checked.
|
||||
* @return the index of the first character after the checked part.
|
||||
*/
|
||||
private static int checkClassTypeSignature(final String signature, int pos) {
|
||||
// ClassTypeSignature:
|
||||
// L Identifier ( / Identifier )* TypeArguments? ( . Identifier
|
||||
// TypeArguments? )* ;
|
||||
|
||||
pos = checkChar('L', signature, pos);
|
||||
pos = checkIdentifier(signature, pos);
|
||||
while (getChar(signature, pos) == '/') {
|
||||
pos = checkIdentifier(signature, pos + 1);
|
||||
}
|
||||
if (getChar(signature, pos) == '<') {
|
||||
pos = checkTypeArguments(signature, pos);
|
||||
}
|
||||
while (getChar(signature, pos) == '.') {
|
||||
pos = checkIdentifier(signature, pos + 1);
|
||||
if (getChar(signature, pos) == '<') {
|
||||
pos = checkTypeArguments(signature, pos);
|
||||
}
|
||||
}
|
||||
return checkChar(';', signature, pos);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the type arguments in a class type signature.
|
||||
*
|
||||
* @param signature
|
||||
* a string containing the signature that must be checked.
|
||||
* @param pos
|
||||
* index of first character to be checked.
|
||||
* @return the index of the first character after the checked part.
|
||||
*/
|
||||
private static int checkTypeArguments(final String signature, int pos) {
|
||||
// TypeArguments:
|
||||
// < TypeArgument+ >
|
||||
|
||||
pos = checkChar('<', signature, pos);
|
||||
pos = checkTypeArgument(signature, pos);
|
||||
while (getChar(signature, pos) != '>') {
|
||||
pos = checkTypeArgument(signature, pos);
|
||||
}
|
||||
return pos + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks a type argument in a class type signature.
|
||||
*
|
||||
* @param signature
|
||||
* a string containing the signature that must be checked.
|
||||
* @param pos
|
||||
* index of first character to be checked.
|
||||
* @return the index of the first character after the checked part.
|
||||
*/
|
||||
private static int checkTypeArgument(final String signature, int pos) {
|
||||
// TypeArgument:
|
||||
// * | ( ( + | - )? FieldTypeSignature )
|
||||
|
||||
char c = getChar(signature, pos);
|
||||
if (c == '*') {
|
||||
return pos + 1;
|
||||
} else if (c == '+' || c == '-') {
|
||||
pos++;
|
||||
}
|
||||
return checkFieldTypeSignature(signature, pos);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks a type variable signature.
|
||||
*
|
||||
* @param signature
|
||||
* a string containing the signature that must be checked.
|
||||
* @param pos
|
||||
* index of first character to be checked.
|
||||
* @return the index of the first character after the checked part.
|
||||
*/
|
||||
private static int checkTypeVariableSignature(final String signature,
|
||||
int pos) {
|
||||
// TypeVariableSignature:
|
||||
// T Identifier ;
|
||||
|
||||
pos = checkChar('T', signature, pos);
|
||||
pos = checkIdentifier(signature, pos);
|
||||
return checkChar(';', signature, pos);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks a type signature.
|
||||
*
|
||||
* @param signature
|
||||
* a string containing the signature that must be checked.
|
||||
* @param pos
|
||||
* index of first character to be checked.
|
||||
* @return the index of the first character after the checked part.
|
||||
*/
|
||||
private static int checkTypeSignature(final String signature, int pos) {
|
||||
// TypeSignature:
|
||||
// Z | C | B | S | I | F | J | D | FieldTypeSignature
|
||||
|
||||
switch (getChar(signature, pos)) {
|
||||
case 'Z':
|
||||
case 'C':
|
||||
case 'B':
|
||||
case 'S':
|
||||
case 'I':
|
||||
case 'F':
|
||||
case 'J':
|
||||
case 'D':
|
||||
return pos + 1;
|
||||
default:
|
||||
return checkFieldTypeSignature(signature, pos);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks an identifier.
|
||||
*
|
||||
* @param signature
|
||||
* a string containing the signature that must be checked.
|
||||
* @param pos
|
||||
* index of first character to be checked.
|
||||
* @return the index of the first character after the checked part.
|
||||
*/
|
||||
private static int checkIdentifier(final String signature, int pos) {
|
||||
if (!Character.isJavaIdentifierStart(getChar(signature, pos))) {
|
||||
throw new IllegalArgumentException(signature
|
||||
+ ": identifier expected at index " + pos);
|
||||
}
|
||||
++pos;
|
||||
while (Character.isJavaIdentifierPart(getChar(signature, pos))) {
|
||||
++pos;
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks a single character.
|
||||
*
|
||||
* @param signature
|
||||
* a string containing the signature that must be checked.
|
||||
* @param pos
|
||||
* index of first character to be checked.
|
||||
* @return the index of the first character after the checked part.
|
||||
*/
|
||||
private static int checkChar(final char c, final String signature, int pos) {
|
||||
if (getChar(signature, pos) == c) {
|
||||
return pos + 1;
|
||||
}
|
||||
throw new IllegalArgumentException(signature + ": '" + c
|
||||
+ "' expected at index " + pos);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the signature car at the given index.
|
||||
*
|
||||
* @param signature
|
||||
* a signature.
|
||||
* @param pos
|
||||
* an index in signature.
|
||||
* @return the character at the given index, or 0 if there is no such
|
||||
* character.
|
||||
*/
|
||||
private static char getChar(final String signature, int pos) {
|
||||
return pos < signature.length() ? signature.charAt(pos) : (char) 0;
|
||||
}
|
||||
}
|
||||
@@ -1,100 +0,0 @@
|
||||
/***
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 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.util;
|
||||
|
||||
import org.objectweb.asm.AnnotationVisitor;
|
||||
import org.objectweb.asm.Attribute;
|
||||
import org.objectweb.asm.FieldVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
|
||||
/**
|
||||
* A {@link org.objectweb.asm.FieldVisitor} that checks that its methods are properly used.
|
||||
*/
|
||||
public class CheckFieldAdapter extends FieldVisitor {
|
||||
|
||||
private boolean end;
|
||||
|
||||
/**
|
||||
* Constructs a new {@link org.objectweb.asm.util.CheckFieldAdapter}. <i>Subclasses must not use
|
||||
* this constructor</i>. Instead, they must use the
|
||||
* {@link #CheckFieldAdapter(int, org.objectweb.asm.FieldVisitor)} version.
|
||||
*
|
||||
* @param fv
|
||||
* the field visitor to which this adapter must delegate calls.
|
||||
*/
|
||||
public CheckFieldAdapter(final FieldVisitor fv) {
|
||||
this(Opcodes.ASM4, fv);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@link org.objectweb.asm.util.CheckFieldAdapter}.
|
||||
*
|
||||
* @param api
|
||||
* the ASM API version implemented by this visitor. Must be one
|
||||
* of {@link org.objectweb.asm.Opcodes#ASM4}.
|
||||
* @param fv
|
||||
* the field visitor to which this adapter must delegate calls.
|
||||
*/
|
||||
protected CheckFieldAdapter(final int api, final FieldVisitor fv) {
|
||||
super(api, fv);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitAnnotation(final String desc,
|
||||
final boolean visible) {
|
||||
checkEnd();
|
||||
CheckMethodAdapter.checkDesc(desc, false);
|
||||
return new CheckAnnotationAdapter(super.visitAnnotation(desc, visible));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitAttribute(final Attribute attr) {
|
||||
checkEnd();
|
||||
if (attr == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Invalid attribute (must not be null)");
|
||||
}
|
||||
super.visitAttribute(attr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
checkEnd();
|
||||
end = true;
|
||||
super.visitEnd();
|
||||
}
|
||||
|
||||
private void checkEnd() {
|
||||
if (end) {
|
||||
throw new IllegalStateException(
|
||||
"Cannot call a visit method after visitEnd has been called");
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,330 +0,0 @@
|
||||
/***
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 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.util;
|
||||
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.signature.SignatureVisitor;
|
||||
|
||||
/**
|
||||
* A {@link org.objectweb.asm.signature.SignatureVisitor} that checks that its methods are properly used.
|
||||
*
|
||||
* @author Eric Bruneton
|
||||
*/
|
||||
public class CheckSignatureAdapter extends SignatureVisitor {
|
||||
|
||||
/**
|
||||
* Type to be used to check class signatures. See
|
||||
* {@link #CheckSignatureAdapter(int, org.objectweb.asm.signature.SignatureVisitor)
|
||||
* CheckSignatureAdapter}.
|
||||
*/
|
||||
public static final int CLASS_SIGNATURE = 0;
|
||||
|
||||
/**
|
||||
* Type to be used to check method signatures. See
|
||||
* {@link #CheckSignatureAdapter(int, org.objectweb.asm.signature.SignatureVisitor)
|
||||
* CheckSignatureAdapter}.
|
||||
*/
|
||||
public static final int METHOD_SIGNATURE = 1;
|
||||
|
||||
/**
|
||||
* Type to be used to check type signatures.See
|
||||
* {@link #CheckSignatureAdapter(int, org.objectweb.asm.signature.SignatureVisitor)
|
||||
* CheckSignatureAdapter}.
|
||||
*/
|
||||
public static final int TYPE_SIGNATURE = 2;
|
||||
|
||||
private static final int EMPTY = 1;
|
||||
|
||||
private static final int FORMAL = 2;
|
||||
|
||||
private static final int BOUND = 4;
|
||||
|
||||
private static final int SUPER = 8;
|
||||
|
||||
private static final int PARAM = 16;
|
||||
|
||||
private static final int RETURN = 32;
|
||||
|
||||
private static final int SIMPLE_TYPE = 64;
|
||||
|
||||
private static final int CLASS_TYPE = 128;
|
||||
|
||||
private static final int END = 256;
|
||||
|
||||
/**
|
||||
* Type of the signature to be checked.
|
||||
*/
|
||||
private final int type;
|
||||
|
||||
/**
|
||||
* State of the automaton used to check the order of method calls.
|
||||
*/
|
||||
private int state;
|
||||
|
||||
/**
|
||||
* <tt>true</tt> if the checked type signature can be 'V'.
|
||||
*/
|
||||
private boolean canBeVoid;
|
||||
|
||||
/**
|
||||
* The visitor to which this adapter must delegate calls. May be
|
||||
* <tt>null</tt>.
|
||||
*/
|
||||
private final SignatureVisitor sv;
|
||||
|
||||
/**
|
||||
* Creates a new {@link org.objectweb.asm.util.CheckSignatureAdapter} object. <i>Subclasses must
|
||||
* not use this constructor</i>. Instead, they must use the
|
||||
* {@link #CheckSignatureAdapter(int, int, org.objectweb.asm.signature.SignatureVisitor)} version.
|
||||
*
|
||||
* @param type
|
||||
* the type of signature to be checked. See
|
||||
* {@link #CLASS_SIGNATURE}, {@link #METHOD_SIGNATURE} and
|
||||
* {@link #TYPE_SIGNATURE}.
|
||||
* @param sv
|
||||
* the visitor to which this adapter must delegate calls. May be
|
||||
* <tt>null</tt>.
|
||||
*/
|
||||
public CheckSignatureAdapter(final int type, final SignatureVisitor sv) {
|
||||
this(Opcodes.ASM4, type, sv);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link org.objectweb.asm.util.CheckSignatureAdapter} object.
|
||||
*
|
||||
* @param api
|
||||
* the ASM API version implemented by this visitor. Must be one
|
||||
* of {@link org.objectweb.asm.Opcodes#ASM4}.
|
||||
* @param type
|
||||
* the type of signature to be checked. See
|
||||
* {@link #CLASS_SIGNATURE}, {@link #METHOD_SIGNATURE} and
|
||||
* {@link #TYPE_SIGNATURE}.
|
||||
* @param sv
|
||||
* the visitor to which this adapter must delegate calls. May be
|
||||
* <tt>null</tt>.
|
||||
*/
|
||||
protected CheckSignatureAdapter(final int api, final int type,
|
||||
final SignatureVisitor sv) {
|
||||
super(api);
|
||||
this.type = type;
|
||||
this.state = EMPTY;
|
||||
this.sv = sv;
|
||||
}
|
||||
|
||||
// class and method signatures
|
||||
|
||||
@Override
|
||||
public void visitFormalTypeParameter(final String name) {
|
||||
if (type == TYPE_SIGNATURE
|
||||
|| (state != EMPTY && state != FORMAL && state != BOUND)) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
CheckMethodAdapter.checkIdentifier(name, "formal type parameter");
|
||||
state = FORMAL;
|
||||
if (sv != null) {
|
||||
sv.visitFormalTypeParameter(name);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureVisitor visitClassBound() {
|
||||
if (state != FORMAL) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
state = BOUND;
|
||||
SignatureVisitor v = sv == null ? null : sv.visitClassBound();
|
||||
return new CheckSignatureAdapter(TYPE_SIGNATURE, v);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureVisitor visitInterfaceBound() {
|
||||
if (state != FORMAL && state != BOUND) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
SignatureVisitor v = sv == null ? null : sv.visitInterfaceBound();
|
||||
return new CheckSignatureAdapter(TYPE_SIGNATURE, v);
|
||||
}
|
||||
|
||||
// class signatures
|
||||
|
||||
@Override
|
||||
public SignatureVisitor visitSuperclass() {
|
||||
if (type != CLASS_SIGNATURE || (state & (EMPTY | FORMAL | BOUND)) == 0) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
state = SUPER;
|
||||
SignatureVisitor v = sv == null ? null : sv.visitSuperclass();
|
||||
return new CheckSignatureAdapter(TYPE_SIGNATURE, v);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureVisitor visitInterface() {
|
||||
if (state != SUPER) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
SignatureVisitor v = sv == null ? null : sv.visitInterface();
|
||||
return new CheckSignatureAdapter(TYPE_SIGNATURE, v);
|
||||
}
|
||||
|
||||
// method signatures
|
||||
|
||||
@Override
|
||||
public SignatureVisitor visitParameterType() {
|
||||
if (type != METHOD_SIGNATURE
|
||||
|| (state & (EMPTY | FORMAL | BOUND | PARAM)) == 0) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
state = PARAM;
|
||||
SignatureVisitor v = sv == null ? null : sv.visitParameterType();
|
||||
return new CheckSignatureAdapter(TYPE_SIGNATURE, v);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureVisitor visitReturnType() {
|
||||
if (type != METHOD_SIGNATURE
|
||||
|| (state & (EMPTY | FORMAL | BOUND | PARAM)) == 0) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
state = RETURN;
|
||||
SignatureVisitor v = sv == null ? null : sv.visitReturnType();
|
||||
CheckSignatureAdapter cv = new CheckSignatureAdapter(TYPE_SIGNATURE, v);
|
||||
cv.canBeVoid = true;
|
||||
return cv;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureVisitor visitExceptionType() {
|
||||
if (state != RETURN) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
SignatureVisitor v = sv == null ? null : sv.visitExceptionType();
|
||||
return new CheckSignatureAdapter(TYPE_SIGNATURE, v);
|
||||
}
|
||||
|
||||
// type signatures
|
||||
|
||||
@Override
|
||||
public void visitBaseType(final char descriptor) {
|
||||
if (type != TYPE_SIGNATURE || state != EMPTY) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
if (descriptor == 'V') {
|
||||
if (!canBeVoid) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
} else {
|
||||
if ("ZCBSIFJD".indexOf(descriptor) == -1) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
state = SIMPLE_TYPE;
|
||||
if (sv != null) {
|
||||
sv.visitBaseType(descriptor);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTypeVariable(final String name) {
|
||||
if (type != TYPE_SIGNATURE || state != EMPTY) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
CheckMethodAdapter.checkIdentifier(name, "type variable");
|
||||
state = SIMPLE_TYPE;
|
||||
if (sv != null) {
|
||||
sv.visitTypeVariable(name);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureVisitor visitArrayType() {
|
||||
if (type != TYPE_SIGNATURE || state != EMPTY) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
state = SIMPLE_TYPE;
|
||||
SignatureVisitor v = sv == null ? null : sv.visitArrayType();
|
||||
return new CheckSignatureAdapter(TYPE_SIGNATURE, v);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitClassType(final String name) {
|
||||
if (type != TYPE_SIGNATURE || state != EMPTY) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
CheckMethodAdapter.checkInternalName(name, "class name");
|
||||
state = CLASS_TYPE;
|
||||
if (sv != null) {
|
||||
sv.visitClassType(name);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitInnerClassType(final String name) {
|
||||
if (state != CLASS_TYPE) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
CheckMethodAdapter.checkIdentifier(name, "inner class name");
|
||||
if (sv != null) {
|
||||
sv.visitInnerClassType(name);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTypeArgument() {
|
||||
if (state != CLASS_TYPE) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
if (sv != null) {
|
||||
sv.visitTypeArgument();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureVisitor visitTypeArgument(final char wildcard) {
|
||||
if (state != CLASS_TYPE) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
if ("+-=".indexOf(wildcard) == -1) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
SignatureVisitor v = sv == null ? null : sv.visitTypeArgument(wildcard);
|
||||
return new CheckSignatureAdapter(TYPE_SIGNATURE, v);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
if (state != CLASS_TYPE) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
state = END;
|
||||
if (sv != null) {
|
||||
sv.visitEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,499 +0,0 @@
|
||||
/***
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 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.util;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.objectweb.asm.Attribute;
|
||||
import org.objectweb.asm.Handle;
|
||||
import org.objectweb.asm.Label;
|
||||
|
||||
/**
|
||||
* An abstract converter from visit events to text.
|
||||
*
|
||||
* @author Eric Bruneton
|
||||
*/
|
||||
public abstract class Printer {
|
||||
|
||||
/**
|
||||
* The names of the Java Virtual Machine opcodes.
|
||||
*/
|
||||
public static final String[] OPCODES;
|
||||
|
||||
/**
|
||||
* The names of the for <code>operand</code> parameter values of the
|
||||
* {@link org.objectweb.asm.MethodVisitor#visitIntInsn} method when
|
||||
* <code>opcode</code> is <code>NEWARRAY</code>.
|
||||
*/
|
||||
public static final String[] TYPES;
|
||||
|
||||
/**
|
||||
* The names of the <code>tag</code> field values for
|
||||
* {@link org.objectweb.asm.Handle}.
|
||||
*/
|
||||
public static final String[] HANDLE_TAG;
|
||||
|
||||
static {
|
||||
String s = "NOP,ACONST_NULL,ICONST_M1,ICONST_0,ICONST_1,ICONST_2,"
|
||||
+ "ICONST_3,ICONST_4,ICONST_5,LCONST_0,LCONST_1,FCONST_0,"
|
||||
+ "FCONST_1,FCONST_2,DCONST_0,DCONST_1,BIPUSH,SIPUSH,LDC,,,"
|
||||
+ "ILOAD,LLOAD,FLOAD,DLOAD,ALOAD,,,,,,,,,,,,,,,,,,,,,IALOAD,"
|
||||
+ "LALOAD,FALOAD,DALOAD,AALOAD,BALOAD,CALOAD,SALOAD,ISTORE,"
|
||||
+ "LSTORE,FSTORE,DSTORE,ASTORE,,,,,,,,,,,,,,,,,,,,,IASTORE,"
|
||||
+ "LASTORE,FASTORE,DASTORE,AASTORE,BASTORE,CASTORE,SASTORE,POP,"
|
||||
+ "POP2,DUP,DUP_X1,DUP_X2,DUP2,DUP2_X1,DUP2_X2,SWAP,IADD,LADD,"
|
||||
+ "FADD,DADD,ISUB,LSUB,FSUB,DSUB,IMUL,LMUL,FMUL,DMUL,IDIV,LDIV,"
|
||||
+ "FDIV,DDIV,IREM,LREM,FREM,DREM,INEG,LNEG,FNEG,DNEG,ISHL,LSHL,"
|
||||
+ "ISHR,LSHR,IUSHR,LUSHR,IAND,LAND,IOR,LOR,IXOR,LXOR,IINC,I2L,"
|
||||
+ "I2F,I2D,L2I,L2F,L2D,F2I,F2L,F2D,D2I,D2L,D2F,I2B,I2C,I2S,LCMP,"
|
||||
+ "FCMPL,FCMPG,DCMPL,DCMPG,IFEQ,IFNE,IFLT,IFGE,IFGT,IFLE,"
|
||||
+ "IF_ICMPEQ,IF_ICMPNE,IF_ICMPLT,IF_ICMPGE,IF_ICMPGT,IF_ICMPLE,"
|
||||
+ "IF_ACMPEQ,IF_ACMPNE,GOTO,JSR,RET,TABLESWITCH,LOOKUPSWITCH,"
|
||||
+ "IRETURN,LRETURN,FRETURN,DRETURN,ARETURN,RETURN,GETSTATIC,"
|
||||
+ "PUTSTATIC,GETFIELD,PUTFIELD,INVOKEVIRTUAL,INVOKESPECIAL,"
|
||||
+ "INVOKESTATIC,INVOKEINTERFACE,INVOKEDYNAMIC,NEW,NEWARRAY,"
|
||||
+ "ANEWARRAY,ARRAYLENGTH,ATHROW,CHECKCAST,INSTANCEOF,"
|
||||
+ "MONITORENTER,MONITOREXIT,,MULTIANEWARRAY,IFNULL,IFNONNULL,";
|
||||
OPCODES = new String[200];
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
int l;
|
||||
while ((l = s.indexOf(',', j)) > 0) {
|
||||
OPCODES[i++] = j + 1 == l ? null : s.substring(j, l);
|
||||
j = l + 1;
|
||||
}
|
||||
|
||||
s = "T_BOOLEAN,T_CHAR,T_FLOAT,T_DOUBLE,T_BYTE,T_SHORT,T_INT,T_LONG,";
|
||||
TYPES = new String[12];
|
||||
j = 0;
|
||||
i = 4;
|
||||
while ((l = s.indexOf(',', j)) > 0) {
|
||||
TYPES[i++] = s.substring(j, l);
|
||||
j = l + 1;
|
||||
}
|
||||
|
||||
s = "H_GETFIELD,H_GETSTATIC,H_PUTFIELD,H_PUTSTATIC,"
|
||||
+ "H_INVOKEVIRTUAL,H_INVOKESTATIC,H_INVOKESPECIAL,"
|
||||
+ "H_NEWINVOKESPECIAL,H_INVOKEINTERFACE,";
|
||||
HANDLE_TAG = new String[10];
|
||||
j = 0;
|
||||
i = 1;
|
||||
while ((l = s.indexOf(',', j)) > 0) {
|
||||
HANDLE_TAG[i++] = s.substring(j, l);
|
||||
j = l + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The ASM API version implemented by this class. The value of this field
|
||||
* must be one of {@link org.objectweb.asm.Opcodes#ASM4}.
|
||||
*/
|
||||
protected final int api;
|
||||
|
||||
/**
|
||||
* A buffer that can be used to create strings.
|
||||
*/
|
||||
protected final StringBuffer buf;
|
||||
|
||||
/**
|
||||
* The text to be printed. Since the code of methods is not necessarily
|
||||
* visited in sequential order, one method after the other, but can be
|
||||
* interlaced (some instructions from method one, then some instructions
|
||||
* from method two, then some instructions from method one again...), it is
|
||||
* not possible to print the visited instructions directly to a sequential
|
||||
* stream. A class is therefore printed in a two steps process: a string
|
||||
* tree is constructed during the visit, and printed to a sequential stream
|
||||
* at the end of the visit. This string tree is stored in this field, as a
|
||||
* string list that can contain other string lists, which can themselves
|
||||
* contain other string lists, and so on.
|
||||
*/
|
||||
public final List<Object> text;
|
||||
|
||||
/**
|
||||
* Constructs a new {@link org.objectweb.asm.util.Printer}.
|
||||
*/
|
||||
protected Printer(final int api) {
|
||||
this.api = api;
|
||||
this.buf = new StringBuffer();
|
||||
this.text = new ArrayList<Object>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Class header. See {@link org.objectweb.asm.ClassVisitor#visit}.
|
||||
*/
|
||||
public abstract void visit(final int version, final int access,
|
||||
final String name, final String signature, final String superName,
|
||||
final String[] interfaces);
|
||||
|
||||
/**
|
||||
* Class source. See {@link org.objectweb.asm.ClassVisitor#visitSource}.
|
||||
*/
|
||||
public abstract void visitSource(final String file, final String debug);
|
||||
|
||||
/**
|
||||
* Class outer class. See
|
||||
* {@link org.objectweb.asm.ClassVisitor#visitOuterClass}.
|
||||
*/
|
||||
public abstract void visitOuterClass(final String owner, final String name,
|
||||
final String desc);
|
||||
|
||||
/**
|
||||
* Class annotation. See
|
||||
* {@link org.objectweb.asm.ClassVisitor#visitAnnotation}.
|
||||
*/
|
||||
public abstract Printer visitClassAnnotation(final String desc,
|
||||
final boolean visible);
|
||||
|
||||
/**
|
||||
* Class attribute. See
|
||||
* {@link org.objectweb.asm.ClassVisitor#visitAttribute}.
|
||||
*/
|
||||
public abstract void visitClassAttribute(final Attribute attr);
|
||||
|
||||
/**
|
||||
* Class inner name. See
|
||||
* {@link org.objectweb.asm.ClassVisitor#visitInnerClass}.
|
||||
*/
|
||||
public abstract void visitInnerClass(final String name,
|
||||
final String outerName, final String innerName, final int access);
|
||||
|
||||
/**
|
||||
* Class field. See {@link org.objectweb.asm.ClassVisitor#visitField}.
|
||||
*/
|
||||
public abstract Printer visitField(final int access, final String name,
|
||||
final String desc, final String signature, final Object value);
|
||||
|
||||
/**
|
||||
* Class method. See {@link org.objectweb.asm.ClassVisitor#visitMethod}.
|
||||
*/
|
||||
public abstract Printer visitMethod(final int access, final String name,
|
||||
final String desc, final String signature, final String[] exceptions);
|
||||
|
||||
/**
|
||||
* Class end. See {@link org.objectweb.asm.ClassVisitor#visitEnd}.
|
||||
*/
|
||||
public abstract void visitClassEnd();
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Annotations
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Annotation value. See {@link org.objectweb.asm.AnnotationVisitor#visit}.
|
||||
*/
|
||||
public abstract void visit(final String name, final Object value);
|
||||
|
||||
/**
|
||||
* Annotation enum value. See
|
||||
* {@link org.objectweb.asm.AnnotationVisitor#visitEnum}.
|
||||
*/
|
||||
public abstract void visitEnum(final String name, final String desc,
|
||||
final String value);
|
||||
|
||||
/**
|
||||
* Nested annotation value. See
|
||||
* {@link org.objectweb.asm.AnnotationVisitor#visitAnnotation}.
|
||||
*/
|
||||
public abstract Printer visitAnnotation(final String name, final String desc);
|
||||
|
||||
/**
|
||||
* Annotation array value. See
|
||||
* {@link org.objectweb.asm.AnnotationVisitor#visitArray}.
|
||||
*/
|
||||
public abstract Printer visitArray(final String name);
|
||||
|
||||
/**
|
||||
* Annotation end. See {@link org.objectweb.asm.AnnotationVisitor#visitEnd}.
|
||||
*/
|
||||
public abstract void visitAnnotationEnd();
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Fields
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Field annotation. See
|
||||
* {@link org.objectweb.asm.FieldVisitor#visitAnnotation}.
|
||||
*/
|
||||
public abstract Printer visitFieldAnnotation(final String desc,
|
||||
final boolean visible);
|
||||
|
||||
/**
|
||||
* Field attribute. See
|
||||
* {@link org.objectweb.asm.FieldVisitor#visitAttribute}.
|
||||
*/
|
||||
public abstract void visitFieldAttribute(final Attribute attr);
|
||||
|
||||
/**
|
||||
* Field end. See {@link org.objectweb.asm.FieldVisitor#visitEnd}.
|
||||
*/
|
||||
public abstract void visitFieldEnd();
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Methods
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method default annotation. See
|
||||
* {@link org.objectweb.asm.MethodVisitor#visitAnnotationDefault}.
|
||||
*/
|
||||
public abstract Printer visitAnnotationDefault();
|
||||
|
||||
/**
|
||||
* Method annotation. See
|
||||
* {@link org.objectweb.asm.MethodVisitor#visitAnnotation}.
|
||||
*/
|
||||
public abstract Printer visitMethodAnnotation(final String desc,
|
||||
final boolean visible);
|
||||
|
||||
/**
|
||||
* Method parameter annotation. See
|
||||
* {@link org.objectweb.asm.MethodVisitor#visitParameterAnnotation}.
|
||||
*/
|
||||
public abstract Printer visitParameterAnnotation(final int parameter,
|
||||
final String desc, final boolean visible);
|
||||
|
||||
/**
|
||||
* Method attribute. See
|
||||
* {@link org.objectweb.asm.MethodVisitor#visitAttribute}.
|
||||
*/
|
||||
public abstract void visitMethodAttribute(final Attribute attr);
|
||||
|
||||
/**
|
||||
* Method start. See {@link org.objectweb.asm.MethodVisitor#visitCode}.
|
||||
*/
|
||||
public abstract void visitCode();
|
||||
|
||||
/**
|
||||
* Method stack frame. See
|
||||
* {@link org.objectweb.asm.MethodVisitor#visitFrame}.
|
||||
*/
|
||||
public abstract void visitFrame(final int type, final int nLocal,
|
||||
final Object[] local, final int nStack, final Object[] stack);
|
||||
|
||||
/**
|
||||
* Method instruction. See {@link org.objectweb.asm.MethodVisitor#visitInsn}
|
||||
* .
|
||||
*/
|
||||
public abstract void visitInsn(final int opcode);
|
||||
|
||||
/**
|
||||
* Method instruction. See
|
||||
* {@link org.objectweb.asm.MethodVisitor#visitIntInsn}.
|
||||
*/
|
||||
public abstract void visitIntInsn(final int opcode, final int operand);
|
||||
|
||||
/**
|
||||
* Method instruction. See
|
||||
* {@link org.objectweb.asm.MethodVisitor#visitVarInsn}.
|
||||
*/
|
||||
public abstract void visitVarInsn(final int opcode, final int var);
|
||||
|
||||
/**
|
||||
* Method instruction. See
|
||||
* {@link org.objectweb.asm.MethodVisitor#visitTypeInsn}.
|
||||
*/
|
||||
public abstract void visitTypeInsn(final int opcode, final String type);
|
||||
|
||||
/**
|
||||
* Method instruction. See
|
||||
* {@link org.objectweb.asm.MethodVisitor#visitFieldInsn}.
|
||||
*/
|
||||
public abstract void visitFieldInsn(final int opcode, final String owner,
|
||||
final String name, final String desc);
|
||||
|
||||
/**
|
||||
* Method instruction. See
|
||||
* {@link org.objectweb.asm.MethodVisitor#visitMethodInsn}.
|
||||
*/
|
||||
public abstract void visitMethodInsn(final int opcode, final String owner,
|
||||
final String name, final String desc);
|
||||
|
||||
/**
|
||||
* Method instruction. See
|
||||
* {@link org.objectweb.asm.MethodVisitor#visitInvokeDynamicInsn}.
|
||||
*/
|
||||
public abstract void visitInvokeDynamicInsn(String name, String desc,
|
||||
Handle bsm, Object... bsmArgs);
|
||||
|
||||
/**
|
||||
* Method instruction. See
|
||||
* {@link org.objectweb.asm.MethodVisitor#visitJumpInsn}.
|
||||
*/
|
||||
public abstract void visitJumpInsn(final int opcode, final Label label);
|
||||
|
||||
/**
|
||||
* Method label. See {@link org.objectweb.asm.MethodVisitor#visitLabel}.
|
||||
*/
|
||||
public abstract void visitLabel(final Label label);
|
||||
|
||||
/**
|
||||
* Method instruction. See
|
||||
* {@link org.objectweb.asm.MethodVisitor#visitLdcInsn}.
|
||||
*/
|
||||
public abstract void visitLdcInsn(final Object cst);
|
||||
|
||||
/**
|
||||
* Method instruction. See
|
||||
* {@link org.objectweb.asm.MethodVisitor#visitIincInsn}.
|
||||
*/
|
||||
public abstract void visitIincInsn(final int var, final int increment);
|
||||
|
||||
/**
|
||||
* Method instruction. See
|
||||
* {@link org.objectweb.asm.MethodVisitor#visitTableSwitchInsn}.
|
||||
*/
|
||||
public abstract void visitTableSwitchInsn(final int min, final int max,
|
||||
final Label dflt, final Label... labels);
|
||||
|
||||
/**
|
||||
* Method instruction. See
|
||||
* {@link org.objectweb.asm.MethodVisitor#visitLookupSwitchInsn}.
|
||||
*/
|
||||
public abstract void visitLookupSwitchInsn(final Label dflt,
|
||||
final int[] keys, final Label[] labels);
|
||||
|
||||
/**
|
||||
* Method instruction. See
|
||||
* {@link org.objectweb.asm.MethodVisitor#visitMultiANewArrayInsn}.
|
||||
*/
|
||||
public abstract void visitMultiANewArrayInsn(final String desc,
|
||||
final int dims);
|
||||
|
||||
/**
|
||||
* Method exception handler. See
|
||||
* {@link org.objectweb.asm.MethodVisitor#visitTryCatchBlock}.
|
||||
*/
|
||||
public abstract void visitTryCatchBlock(final Label start, final Label end,
|
||||
final Label handler, final String type);
|
||||
|
||||
/**
|
||||
* Method debug info. See
|
||||
* {@link org.objectweb.asm.MethodVisitor#visitLocalVariable}.
|
||||
*/
|
||||
public abstract void visitLocalVariable(final String name,
|
||||
final String desc, final String signature, final Label start,
|
||||
final Label end, final int index);
|
||||
|
||||
/**
|
||||
* Method debug info. See
|
||||
* {@link org.objectweb.asm.MethodVisitor#visitLineNumber}.
|
||||
*/
|
||||
public abstract void visitLineNumber(final int line, final Label start);
|
||||
|
||||
/**
|
||||
* Method max stack and max locals. See
|
||||
* {@link org.objectweb.asm.MethodVisitor#visitMaxs}.
|
||||
*/
|
||||
public abstract void visitMaxs(final int maxStack, final int maxLocals);
|
||||
|
||||
/**
|
||||
* Method end. See {@link org.objectweb.asm.MethodVisitor#visitEnd}.
|
||||
*/
|
||||
public abstract void visitMethodEnd();
|
||||
|
||||
/**
|
||||
* Returns the text constructed by this visitor.
|
||||
*
|
||||
* @return the text constructed by this visitor.
|
||||
*/
|
||||
public List<Object> getText() {
|
||||
return text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints the text constructed by this visitor.
|
||||
*
|
||||
* @param pw
|
||||
* the print writer to be used.
|
||||
*/
|
||||
public void print(final PrintWriter pw) {
|
||||
printList(pw, text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a quoted string to a given buffer.
|
||||
*
|
||||
* @param buf
|
||||
* the buffer where the string must be added.
|
||||
* @param s
|
||||
* the string to be added.
|
||||
*/
|
||||
public static void appendString(final StringBuffer buf, final String s) {
|
||||
buf.append('\"');
|
||||
for (int i = 0; i < s.length(); ++i) {
|
||||
char c = s.charAt(i);
|
||||
if (c == '\n') {
|
||||
buf.append("\\n");
|
||||
} else if (c == '\r') {
|
||||
buf.append("\\r");
|
||||
} else if (c == '\\') {
|
||||
buf.append("\\\\");
|
||||
} else if (c == '"') {
|
||||
buf.append("\\\"");
|
||||
} else if (c < 0x20 || c > 0x7f) {
|
||||
buf.append("\\u");
|
||||
if (c < 0x10) {
|
||||
buf.append("000");
|
||||
} else if (c < 0x100) {
|
||||
buf.append("00");
|
||||
} else if (c < 0x1000) {
|
||||
buf.append('0');
|
||||
}
|
||||
buf.append(Integer.toString(c, 16));
|
||||
} else {
|
||||
buf.append(c);
|
||||
}
|
||||
}
|
||||
buf.append('\"');
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints the given string tree.
|
||||
*
|
||||
* @param pw
|
||||
* the writer to be used to print the tree.
|
||||
* @param l
|
||||
* a string tree, i.e., a string list that can contain other
|
||||
* string lists, and so on recursively.
|
||||
*/
|
||||
static void printList(final PrintWriter pw, final List<?> l) {
|
||||
for (int i = 0; i < l.size(); ++i) {
|
||||
Object o = l.get(i);
|
||||
if (o instanceof List) {
|
||||
printList(pw, (List<?>) o);
|
||||
} else {
|
||||
pw.print(o.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
/**
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 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.util;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.objectweb.asm.Label;
|
||||
|
||||
/**
|
||||
* An {@link org.objectweb.asm.Attribute Attribute} that can print a readable
|
||||
* representation of itself.
|
||||
*
|
||||
* Implementations should construct readable output from an attribute data
|
||||
* structure. Such representation could be used in unit test assertions.
|
||||
*
|
||||
* @author Eugene Kuleshov
|
||||
*/
|
||||
public interface Textifiable {
|
||||
|
||||
/**
|
||||
* Build a human readable representation of this attribute.
|
||||
*
|
||||
* @param buf
|
||||
* a buffer used for printing Java code.
|
||||
* @param labelNames
|
||||
* map of label instances to their names.
|
||||
*/
|
||||
void textify(StringBuffer buf, Map<Label, String> labelNames);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,89 +0,0 @@
|
||||
/***
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 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.util;
|
||||
|
||||
import org.objectweb.asm.AnnotationVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
|
||||
/**
|
||||
* An {@link org.objectweb.asm.AnnotationVisitor} that prints the annotations it visits with a
|
||||
* {@link org.objectweb.asm.util.Printer}.
|
||||
*
|
||||
* @author Eric Bruneton
|
||||
*/
|
||||
public final class TraceAnnotationVisitor extends AnnotationVisitor {
|
||||
|
||||
private final Printer p;
|
||||
|
||||
public TraceAnnotationVisitor(final Printer p) {
|
||||
this(null, p);
|
||||
}
|
||||
|
||||
public TraceAnnotationVisitor(final AnnotationVisitor av, final Printer p) {
|
||||
super(Opcodes.ASM4, av);
|
||||
this.p = p;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(final String name, final Object value) {
|
||||
p.visit(name, value);
|
||||
super.visit(name, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnum(final String name, final String desc,
|
||||
final String value) {
|
||||
p.visitEnum(name, desc, value);
|
||||
super.visitEnum(name, desc, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitAnnotation(final String name,
|
||||
final String desc) {
|
||||
Printer p = this.p.visitAnnotation(name, desc);
|
||||
AnnotationVisitor av = this.av == null ? null : this.av
|
||||
.visitAnnotation(name, desc);
|
||||
return new TraceAnnotationVisitor(av, p);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitArray(final String name) {
|
||||
Printer p = this.p.visitArray(name);
|
||||
AnnotationVisitor av = this.av == null ? null : this.av
|
||||
.visitArray(name);
|
||||
return new TraceAnnotationVisitor(av, p);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
p.visitAnnotationEnd();
|
||||
super.visitEnd();
|
||||
}
|
||||
}
|
||||
@@ -1,209 +0,0 @@
|
||||
/***
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 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.util;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
|
||||
import org.objectweb.asm.AnnotationVisitor;
|
||||
import org.objectweb.asm.Attribute;
|
||||
import org.objectweb.asm.ClassVisitor;
|
||||
import org.objectweb.asm.FieldVisitor;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
|
||||
/**
|
||||
* A {@link org.objectweb.asm.ClassVisitor} that prints the classes it visits with a
|
||||
* {@link org.objectweb.asm.util.Printer}. This class visitor can be used in the middle of a class
|
||||
* visitor chain to trace the class that is visited at a given point in this
|
||||
* chain. This may be useful for debugging purposes.
|
||||
* <p>
|
||||
* The trace printed when visiting the <tt>Hello</tt> class is the following:
|
||||
* <p>
|
||||
* <blockquote>
|
||||
*
|
||||
* <pre>
|
||||
* // class version 49.0 (49) // access flags 0x21 public class Hello {
|
||||
*
|
||||
* // compiled from: Hello.java
|
||||
*
|
||||
* // access flags 0x1 public <init> ()V ALOAD 0 INVOKESPECIAL
|
||||
* java/lang/Object <init> ()V RETURN MAXSTACK = 1 MAXLOCALS = 1
|
||||
*
|
||||
* // access flags 0x9 public static main ([Ljava/lang/String;)V GETSTATIC
|
||||
* java/lang/System out Ljava/io/PrintStream; LDC "hello"
|
||||
* INVOKEVIRTUAL java/io/PrintStream println (Ljava/lang/String;)V RETURN
|
||||
* MAXSTACK = 2 MAXLOCALS = 1 }
|
||||
* </pre>
|
||||
*
|
||||
* </blockquote> where <tt>Hello</tt> is defined by:
|
||||
* <p>
|
||||
* <blockquote>
|
||||
*
|
||||
* <pre>
|
||||
* public class Hello {
|
||||
*
|
||||
* public static void main(String[] args) {
|
||||
* System.out.println("hello");
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* </blockquote>
|
||||
*
|
||||
* @author Eric Bruneton
|
||||
* @author Eugene Kuleshov
|
||||
*/
|
||||
public final class TraceClassVisitor extends ClassVisitor {
|
||||
|
||||
/**
|
||||
* The print writer to be used to print the class. May be null.
|
||||
*/
|
||||
private final PrintWriter pw;
|
||||
|
||||
/**
|
||||
* The object that actually converts visit events into text.
|
||||
*/
|
||||
public final Printer p;
|
||||
|
||||
/**
|
||||
* Constructs a new {@link org.objectweb.asm.util.TraceClassVisitor}.
|
||||
*
|
||||
* @param pw
|
||||
* the print writer to be used to print the class.
|
||||
*/
|
||||
public TraceClassVisitor(final PrintWriter pw) {
|
||||
this(null, pw);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@link org.objectweb.asm.util.TraceClassVisitor}.
|
||||
*
|
||||
* @param cv
|
||||
* the {@link org.objectweb.asm.ClassVisitor} to which this visitor delegates
|
||||
* calls. May be <tt>null</tt>.
|
||||
* @param pw
|
||||
* the print writer to be used to print the class.
|
||||
*/
|
||||
public TraceClassVisitor(final ClassVisitor cv, final PrintWriter pw) {
|
||||
this(cv, new Textifier(), pw);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@link org.objectweb.asm.util.TraceClassVisitor}.
|
||||
*
|
||||
* @param cv
|
||||
* the {@link org.objectweb.asm.ClassVisitor} to which this visitor delegates
|
||||
* calls. May be <tt>null</tt>.
|
||||
* @param p
|
||||
* the object that actually converts visit events into text.
|
||||
* @param pw
|
||||
* the print writer to be used to print the class. May be null if
|
||||
* you simply want to use the result via
|
||||
* {@link org.objectweb.asm.util.Printer#getText()}, instead of printing it.
|
||||
*/
|
||||
public TraceClassVisitor(final ClassVisitor cv, final Printer p,
|
||||
final PrintWriter pw) {
|
||||
super(Opcodes.ASM4, cv);
|
||||
this.pw = pw;
|
||||
this.p = p;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(final int version, final int access, final String name,
|
||||
final String signature, final String superName,
|
||||
final String[] interfaces) {
|
||||
p.visit(version, access, name, signature, superName, interfaces);
|
||||
super.visit(version, access, name, signature, superName, interfaces);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitSource(final String file, final String debug) {
|
||||
p.visitSource(file, debug);
|
||||
super.visitSource(file, debug);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitOuterClass(final String owner, final String name,
|
||||
final String desc) {
|
||||
p.visitOuterClass(owner, name, desc);
|
||||
super.visitOuterClass(owner, name, desc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitAnnotation(final String desc,
|
||||
final boolean visible) {
|
||||
Printer p = this.p.visitClassAnnotation(desc, visible);
|
||||
AnnotationVisitor av = cv == null ? null : cv.visitAnnotation(desc,
|
||||
visible);
|
||||
return new TraceAnnotationVisitor(av, p);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitAttribute(final Attribute attr) {
|
||||
p.visitClassAttribute(attr);
|
||||
super.visitAttribute(attr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitInnerClass(final String name, final String outerName,
|
||||
final String innerName, final int access) {
|
||||
p.visitInnerClass(name, outerName, innerName, access);
|
||||
super.visitInnerClass(name, outerName, innerName, access);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FieldVisitor visitField(final int access, final String name,
|
||||
final String desc, final String signature, final Object value) {
|
||||
Printer p = this.p.visitField(access, name, desc, signature, value);
|
||||
FieldVisitor fv = cv == null ? null : cv.visitField(access, name, desc,
|
||||
signature, value);
|
||||
return new TraceFieldVisitor(fv, p);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodVisitor visitMethod(final int access, final String name,
|
||||
final String desc, final String signature, final String[] exceptions) {
|
||||
Printer p = this.p.visitMethod(access, name, desc, signature,
|
||||
exceptions);
|
||||
MethodVisitor mv = cv == null ? null : cv.visitMethod(access, name,
|
||||
desc, signature, exceptions);
|
||||
return new TraceMethodVisitor(mv, p);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
p.visitClassEnd();
|
||||
if (pw != null) {
|
||||
p.print(pw);
|
||||
pw.flush();
|
||||
}
|
||||
super.visitEnd();
|
||||
}
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
/***
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 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.util;
|
||||
|
||||
import org.objectweb.asm.AnnotationVisitor;
|
||||
import org.objectweb.asm.Attribute;
|
||||
import org.objectweb.asm.FieldVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
|
||||
/**
|
||||
* A {@link org.objectweb.asm.FieldVisitor} that prints the fields it visits with a
|
||||
* {@link org.objectweb.asm.util.Printer}.
|
||||
*
|
||||
* @author Eric Bruneton
|
||||
*/
|
||||
public final class TraceFieldVisitor extends FieldVisitor {
|
||||
|
||||
public final Printer p;
|
||||
|
||||
public TraceFieldVisitor(final Printer p) {
|
||||
this(null, p);
|
||||
}
|
||||
|
||||
public TraceFieldVisitor(final FieldVisitor fv, final Printer p) {
|
||||
super(Opcodes.ASM4, fv);
|
||||
this.p = p;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitAnnotation(final String desc,
|
||||
final boolean visible) {
|
||||
Printer p = this.p.visitFieldAnnotation(desc, visible);
|
||||
AnnotationVisitor av = fv == null ? null : fv.visitAnnotation(desc,
|
||||
visible);
|
||||
return new TraceAnnotationVisitor(av, p);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitAttribute(final Attribute attr) {
|
||||
p.visitFieldAttribute(attr);
|
||||
super.visitAttribute(attr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
p.visitFieldEnd();
|
||||
super.visitEnd();
|
||||
}
|
||||
}
|
||||
@@ -1,223 +0,0 @@
|
||||
/***
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 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.util;
|
||||
|
||||
import org.objectweb.asm.AnnotationVisitor;
|
||||
import org.objectweb.asm.Attribute;
|
||||
import org.objectweb.asm.Handle;
|
||||
import org.objectweb.asm.Label;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
|
||||
/**
|
||||
* A {@link org.objectweb.asm.MethodVisitor} that prints the methods it visits with a
|
||||
* {@link org.objectweb.asm.util.Printer}.
|
||||
*
|
||||
* @author Eric Bruneton
|
||||
*/
|
||||
public final class TraceMethodVisitor extends MethodVisitor {
|
||||
|
||||
public final Printer p;
|
||||
|
||||
public TraceMethodVisitor(final Printer p) {
|
||||
this(null, p);
|
||||
}
|
||||
|
||||
public TraceMethodVisitor(final MethodVisitor mv, final Printer p) {
|
||||
super(Opcodes.ASM4, mv);
|
||||
this.p = p;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitAnnotation(final String desc,
|
||||
final boolean visible) {
|
||||
Printer p = this.p.visitMethodAnnotation(desc, visible);
|
||||
AnnotationVisitor av = mv == null ? null : mv.visitAnnotation(desc,
|
||||
visible);
|
||||
return new TraceAnnotationVisitor(av, p);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitAttribute(final Attribute attr) {
|
||||
p.visitMethodAttribute(attr);
|
||||
super.visitAttribute(attr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitAnnotationDefault() {
|
||||
Printer p = this.p.visitAnnotationDefault();
|
||||
AnnotationVisitor av = mv == null ? null : mv.visitAnnotationDefault();
|
||||
return new TraceAnnotationVisitor(av, p);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitParameterAnnotation(final int parameter,
|
||||
final String desc, final boolean visible) {
|
||||
Printer p = this.p.visitParameterAnnotation(parameter, desc, visible);
|
||||
AnnotationVisitor av = mv == null ? null : mv.visitParameterAnnotation(
|
||||
parameter, desc, visible);
|
||||
return new TraceAnnotationVisitor(av, p);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitCode() {
|
||||
p.visitCode();
|
||||
super.visitCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitFrame(final int type, final int nLocal,
|
||||
final Object[] local, final int nStack, final Object[] stack) {
|
||||
p.visitFrame(type, nLocal, local, nStack, stack);
|
||||
super.visitFrame(type, nLocal, local, nStack, stack);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitInsn(final int opcode) {
|
||||
p.visitInsn(opcode);
|
||||
super.visitInsn(opcode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitIntInsn(final int opcode, final int operand) {
|
||||
p.visitIntInsn(opcode, operand);
|
||||
super.visitIntInsn(opcode, operand);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitVarInsn(final int opcode, final int var) {
|
||||
p.visitVarInsn(opcode, var);
|
||||
super.visitVarInsn(opcode, var);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTypeInsn(final int opcode, final String type) {
|
||||
p.visitTypeInsn(opcode, type);
|
||||
super.visitTypeInsn(opcode, type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitFieldInsn(final int opcode, final String owner,
|
||||
final String name, final String desc) {
|
||||
p.visitFieldInsn(opcode, owner, name, desc);
|
||||
super.visitFieldInsn(opcode, owner, name, desc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMethodInsn(final int opcode, final String owner,
|
||||
final String name, final String desc) {
|
||||
p.visitMethodInsn(opcode, owner, name, desc);
|
||||
super.visitMethodInsn(opcode, owner, name, desc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitInvokeDynamicInsn(String name, String desc, Handle bsm,
|
||||
Object... bsmArgs) {
|
||||
p.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
|
||||
super.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitJumpInsn(final int opcode, final Label label) {
|
||||
p.visitJumpInsn(opcode, label);
|
||||
super.visitJumpInsn(opcode, label);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLabel(final Label label) {
|
||||
p.visitLabel(label);
|
||||
super.visitLabel(label);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLdcInsn(final Object cst) {
|
||||
p.visitLdcInsn(cst);
|
||||
super.visitLdcInsn(cst);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitIincInsn(final int var, final int increment) {
|
||||
p.visitIincInsn(var, increment);
|
||||
super.visitIincInsn(var, increment);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTableSwitchInsn(final int min, final int max,
|
||||
final Label dflt, final Label... labels) {
|
||||
p.visitTableSwitchInsn(min, max, dflt, labels);
|
||||
super.visitTableSwitchInsn(min, max, dflt, labels);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLookupSwitchInsn(final Label dflt, final int[] keys,
|
||||
final Label[] labels) {
|
||||
p.visitLookupSwitchInsn(dflt, keys, labels);
|
||||
super.visitLookupSwitchInsn(dflt, keys, labels);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMultiANewArrayInsn(final String desc, final int dims) {
|
||||
p.visitMultiANewArrayInsn(desc, dims);
|
||||
super.visitMultiANewArrayInsn(desc, dims);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTryCatchBlock(final Label start, final Label end,
|
||||
final Label handler, final String type) {
|
||||
p.visitTryCatchBlock(start, end, handler, type);
|
||||
super.visitTryCatchBlock(start, end, handler, type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLocalVariable(final String name, final String desc,
|
||||
final String signature, final Label start, final Label end,
|
||||
final int index) {
|
||||
p.visitLocalVariable(name, desc, signature, start, end, index);
|
||||
super.visitLocalVariable(name, desc, signature, start, end, index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLineNumber(final int line, final Label start) {
|
||||
p.visitLineNumber(line, start);
|
||||
super.visitLineNumber(line, start);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMaxs(final int maxStack, final int maxLocals) {
|
||||
p.visitMaxs(maxStack, maxLocals);
|
||||
super.visitMaxs(maxStack, maxLocals);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
p.visitMethodEnd();
|
||||
super.visitEnd();
|
||||
}
|
||||
}
|
||||
@@ -1,317 +0,0 @@
|
||||
/***
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 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.util;
|
||||
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.signature.SignatureVisitor;
|
||||
|
||||
/**
|
||||
* A {@link org.objectweb.asm.signature.SignatureVisitor} that prints a disassembled view of the signature
|
||||
* it visits.
|
||||
*
|
||||
* @author Eugene Kuleshov
|
||||
* @author Eric Bruneton
|
||||
*/
|
||||
public final class TraceSignatureVisitor extends SignatureVisitor {
|
||||
|
||||
private final StringBuffer declaration;
|
||||
|
||||
private boolean isInterface;
|
||||
|
||||
private boolean seenFormalParameter;
|
||||
|
||||
private boolean seenInterfaceBound;
|
||||
|
||||
private boolean seenParameter;
|
||||
|
||||
private boolean seenInterface;
|
||||
|
||||
private StringBuffer returnType;
|
||||
|
||||
private StringBuffer exceptions;
|
||||
|
||||
/**
|
||||
* Stack used to keep track of class types that have arguments. Each element
|
||||
* of this stack is a boolean encoded in one bit. The top of the stack is
|
||||
* the lowest order bit. Pushing false = *2, pushing true = *2+1, popping =
|
||||
* /2.
|
||||
*/
|
||||
private int argumentStack;
|
||||
|
||||
/**
|
||||
* Stack used to keep track of array class types. Each element of this stack
|
||||
* is a boolean encoded in one bit. The top of the stack is the lowest order
|
||||
* bit. Pushing false = *2, pushing true = *2+1, popping = /2.
|
||||
*/
|
||||
private int arrayStack;
|
||||
|
||||
private String separator = "";
|
||||
|
||||
public TraceSignatureVisitor(final int access) {
|
||||
super(Opcodes.ASM4);
|
||||
isInterface = (access & Opcodes.ACC_INTERFACE) != 0;
|
||||
this.declaration = new StringBuffer();
|
||||
}
|
||||
|
||||
private TraceSignatureVisitor(final StringBuffer buf) {
|
||||
super(Opcodes.ASM4);
|
||||
this.declaration = buf;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitFormalTypeParameter(final String name) {
|
||||
declaration.append(seenFormalParameter ? ", " : "<").append(name);
|
||||
seenFormalParameter = true;
|
||||
seenInterfaceBound = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureVisitor visitClassBound() {
|
||||
separator = " extends ";
|
||||
startType();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureVisitor visitInterfaceBound() {
|
||||
separator = seenInterfaceBound ? ", " : " extends ";
|
||||
seenInterfaceBound = true;
|
||||
startType();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureVisitor visitSuperclass() {
|
||||
endFormals();
|
||||
separator = " extends ";
|
||||
startType();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureVisitor visitInterface() {
|
||||
separator = seenInterface ? ", " : isInterface ? " extends "
|
||||
: " implements ";
|
||||
seenInterface = true;
|
||||
startType();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureVisitor visitParameterType() {
|
||||
endFormals();
|
||||
if (seenParameter) {
|
||||
declaration.append(", ");
|
||||
} else {
|
||||
seenParameter = true;
|
||||
declaration.append('(');
|
||||
}
|
||||
startType();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureVisitor visitReturnType() {
|
||||
endFormals();
|
||||
if (seenParameter) {
|
||||
seenParameter = false;
|
||||
} else {
|
||||
declaration.append('(');
|
||||
}
|
||||
declaration.append(')');
|
||||
returnType = new StringBuffer();
|
||||
return new TraceSignatureVisitor(returnType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureVisitor visitExceptionType() {
|
||||
if (exceptions == null) {
|
||||
exceptions = new StringBuffer();
|
||||
} else {
|
||||
exceptions.append(", ");
|
||||
}
|
||||
// startType();
|
||||
return new TraceSignatureVisitor(exceptions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitBaseType(final char descriptor) {
|
||||
switch (descriptor) {
|
||||
case 'V':
|
||||
declaration.append("void");
|
||||
break;
|
||||
case 'B':
|
||||
declaration.append("byte");
|
||||
break;
|
||||
case 'J':
|
||||
declaration.append("long");
|
||||
break;
|
||||
case 'Z':
|
||||
declaration.append("boolean");
|
||||
break;
|
||||
case 'I':
|
||||
declaration.append("int");
|
||||
break;
|
||||
case 'S':
|
||||
declaration.append("short");
|
||||
break;
|
||||
case 'C':
|
||||
declaration.append("char");
|
||||
break;
|
||||
case 'F':
|
||||
declaration.append("float");
|
||||
break;
|
||||
// case 'D':
|
||||
default:
|
||||
declaration.append("double");
|
||||
break;
|
||||
}
|
||||
endType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTypeVariable(final String name) {
|
||||
declaration.append(name);
|
||||
endType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureVisitor visitArrayType() {
|
||||
startType();
|
||||
arrayStack |= 1;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitClassType(final String name) {
|
||||
if ("java/lang/Object".equals(name)) {
|
||||
// Map<java.lang.Object,java.util.List>
|
||||
// or
|
||||
// abstract public V get(Object key); (seen in Dictionary.class)
|
||||
// should have Object
|
||||
// but java.lang.String extends java.lang.Object is unnecessary
|
||||
boolean needObjectClass = argumentStack % 2 != 0 || seenParameter;
|
||||
if (needObjectClass) {
|
||||
declaration.append(separator).append(name.replace('/', '.'));
|
||||
}
|
||||
} else {
|
||||
declaration.append(separator).append(name.replace('/', '.'));
|
||||
}
|
||||
separator = "";
|
||||
argumentStack *= 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitInnerClassType(final String name) {
|
||||
if (argumentStack % 2 != 0) {
|
||||
declaration.append('>');
|
||||
}
|
||||
argumentStack /= 2;
|
||||
declaration.append('.');
|
||||
declaration.append(separator).append(name.replace('/', '.'));
|
||||
separator = "";
|
||||
argumentStack *= 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTypeArgument() {
|
||||
if (argumentStack % 2 == 0) {
|
||||
++argumentStack;
|
||||
declaration.append('<');
|
||||
} else {
|
||||
declaration.append(", ");
|
||||
}
|
||||
declaration.append('?');
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureVisitor visitTypeArgument(final char tag) {
|
||||
if (argumentStack % 2 == 0) {
|
||||
++argumentStack;
|
||||
declaration.append('<');
|
||||
} else {
|
||||
declaration.append(", ");
|
||||
}
|
||||
|
||||
if (tag == EXTENDS) {
|
||||
declaration.append("? extends ");
|
||||
} else if (tag == SUPER) {
|
||||
declaration.append("? super ");
|
||||
}
|
||||
|
||||
startType();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
if (argumentStack % 2 != 0) {
|
||||
declaration.append('>');
|
||||
}
|
||||
argumentStack /= 2;
|
||||
endType();
|
||||
}
|
||||
|
||||
public String getDeclaration() {
|
||||
return declaration.toString();
|
||||
}
|
||||
|
||||
public String getReturnType() {
|
||||
return returnType == null ? null : returnType.toString();
|
||||
}
|
||||
|
||||
public String getExceptions() {
|
||||
return exceptions == null ? null : exceptions.toString();
|
||||
}
|
||||
|
||||
// -----------------------------------------------
|
||||
|
||||
private void endFormals() {
|
||||
if (seenFormalParameter) {
|
||||
declaration.append('>');
|
||||
seenFormalParameter = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void startType() {
|
||||
arrayStack *= 2;
|
||||
}
|
||||
|
||||
private void endType() {
|
||||
if (arrayStack % 2 == 0) {
|
||||
arrayStack /= 2;
|
||||
} else {
|
||||
while (arrayStack % 2 != 0) {
|
||||
arrayStack /= 2;
|
||||
declaration.append("[]");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
<html>
|
||||
<!--
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 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.
|
||||
-->
|
||||
<body>
|
||||
Provides ASM visitors that can be useful for programming and
|
||||
debugging purposes. These class visitors are normally not used by applications
|
||||
at runtime. This is why they are bundled in an optional <tt>asm-util.jar</tt>
|
||||
library that is separated from (but requires) the <tt>asm.jar</tt> library,
|
||||
which contains the core ASM framework.
|
||||
|
||||
@since ASM 1.3.2
|
||||
</body>
|
||||
</html>
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,89 +0,0 @@
|
||||
/***
|
||||
* ASM XML Adapter
|
||||
* Copyright (c) 2004-2011, Eugene Kuleshov
|
||||
* 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.xml;
|
||||
|
||||
import org.xml.sax.Attributes;
|
||||
import org.xml.sax.ContentHandler;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
/**
|
||||
* SAXAdapter
|
||||
*
|
||||
* @author Eugene Kuleshov
|
||||
*/
|
||||
public class SAXAdapter {
|
||||
|
||||
private final ContentHandler h;
|
||||
|
||||
protected SAXAdapter(final ContentHandler h) {
|
||||
this.h = h;
|
||||
}
|
||||
|
||||
protected ContentHandler getContentHandler() {
|
||||
return h;
|
||||
}
|
||||
|
||||
protected void addDocumentStart() {
|
||||
try {
|
||||
h.startDocument();
|
||||
} catch (SAXException ex) {
|
||||
throw new RuntimeException(ex.getMessage(), ex.getException());
|
||||
}
|
||||
}
|
||||
|
||||
protected void addDocumentEnd() {
|
||||
try {
|
||||
h.endDocument();
|
||||
} catch (SAXException ex) {
|
||||
throw new RuntimeException(ex.getMessage(), ex.getException());
|
||||
}
|
||||
}
|
||||
|
||||
protected final void addStart(final String name, final Attributes attrs) {
|
||||
try {
|
||||
h.startElement("", name, name, attrs);
|
||||
} catch (SAXException ex) {
|
||||
throw new RuntimeException(ex.getMessage(), ex.getException());
|
||||
}
|
||||
}
|
||||
|
||||
protected final void addEnd(final String name) {
|
||||
try {
|
||||
h.endElement("", name, name);
|
||||
} catch (SAXException ex) {
|
||||
throw new RuntimeException(ex.getMessage(), ex.getException());
|
||||
}
|
||||
}
|
||||
|
||||
protected final void addElement(final String name, final Attributes attrs) {
|
||||
addStart(name, attrs);
|
||||
addEnd(name);
|
||||
}
|
||||
}
|
||||
@@ -1,185 +0,0 @@
|
||||
/***
|
||||
* ASM XML Adapter
|
||||
* Copyright (c) 2004-2011, Eugene Kuleshov
|
||||
* 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.xml;
|
||||
|
||||
import org.objectweb.asm.AnnotationVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.Type;
|
||||
import org.xml.sax.helpers.AttributesImpl;
|
||||
|
||||
/**
|
||||
* SAXAnnotationAdapter
|
||||
*
|
||||
* @author Eugene Kuleshov
|
||||
*/
|
||||
public final class SAXAnnotationAdapter extends AnnotationVisitor {
|
||||
|
||||
SAXAdapter sa;
|
||||
|
||||
private final String elementName;
|
||||
|
||||
public SAXAnnotationAdapter(final SAXAdapter sa, final String elementName,
|
||||
final int visible, final String name, final String desc) {
|
||||
this(Opcodes.ASM4, sa, elementName, visible, desc, name, -1);
|
||||
}
|
||||
|
||||
public SAXAnnotationAdapter(final SAXAdapter sa, final String elementName,
|
||||
final int visible, final int parameter, final String desc) {
|
||||
this(Opcodes.ASM4, sa, elementName, visible, desc, null, parameter);
|
||||
}
|
||||
|
||||
protected SAXAnnotationAdapter(final int api, final SAXAdapter sa,
|
||||
final String elementName, final int visible, final String desc,
|
||||
final String name, final int parameter) {
|
||||
super(api);
|
||||
this.sa = sa;
|
||||
this.elementName = elementName;
|
||||
|
||||
AttributesImpl att = new AttributesImpl();
|
||||
if (name != null) {
|
||||
att.addAttribute("", "name", "name", "", name);
|
||||
}
|
||||
if (visible != 0) {
|
||||
att.addAttribute("", "visible", "visible", "", visible > 0 ? "true"
|
||||
: "false");
|
||||
}
|
||||
if (parameter != -1) {
|
||||
att.addAttribute("", "parameter", "parameter", "",
|
||||
Integer.toString(parameter));
|
||||
}
|
||||
if (desc != null) {
|
||||
att.addAttribute("", "desc", "desc", "", desc);
|
||||
}
|
||||
|
||||
sa.addStart(elementName, att);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(final String name, final Object value) {
|
||||
Class<?> c = value.getClass();
|
||||
if (c.isArray()) {
|
||||
AnnotationVisitor av = visitArray(name);
|
||||
if (value instanceof byte[]) {
|
||||
byte[] b = (byte[]) value;
|
||||
for (int i = 0; i < b.length; i++) {
|
||||
av.visit(null, new Byte(b[i]));
|
||||
}
|
||||
|
||||
} else if (value instanceof char[]) {
|
||||
char[] b = (char[]) value;
|
||||
for (int i = 0; i < b.length; i++) {
|
||||
av.visit(null, new Character(b[i]));
|
||||
}
|
||||
|
||||
} else if (value instanceof short[]) {
|
||||
short[] b = (short[]) value;
|
||||
for (int i = 0; i < b.length; i++) {
|
||||
av.visit(null, new Short(b[i]));
|
||||
}
|
||||
|
||||
} else if (value instanceof boolean[]) {
|
||||
boolean[] b = (boolean[]) value;
|
||||
for (int i = 0; i < b.length; i++) {
|
||||
av.visit(null, Boolean.valueOf(b[i]));
|
||||
}
|
||||
|
||||
} else if (value instanceof int[]) {
|
||||
int[] b = (int[]) value;
|
||||
for (int i = 0; i < b.length; i++) {
|
||||
av.visit(null, new Integer(b[i]));
|
||||
}
|
||||
|
||||
} else if (value instanceof long[]) {
|
||||
long[] b = (long[]) value;
|
||||
for (int i = 0; i < b.length; i++) {
|
||||
av.visit(null, new Long(b[i]));
|
||||
}
|
||||
|
||||
} else if (value instanceof float[]) {
|
||||
float[] b = (float[]) value;
|
||||
for (int i = 0; i < b.length; i++) {
|
||||
av.visit(null, new Float(b[i]));
|
||||
}
|
||||
|
||||
} else if (value instanceof double[]) {
|
||||
double[] b = (double[]) value;
|
||||
for (int i = 0; i < b.length; i++) {
|
||||
av.visit(null, new Double(b[i]));
|
||||
}
|
||||
|
||||
}
|
||||
av.visitEnd();
|
||||
} else {
|
||||
addValueElement("annotationValue", name, Type.getDescriptor(c),
|
||||
value.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnum(final String name, final String desc,
|
||||
final String value) {
|
||||
addValueElement("annotationValueEnum", name, desc, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitAnnotation(final String name,
|
||||
final String desc) {
|
||||
return new SAXAnnotationAdapter(sa, "annotationValueAnnotation", 0,
|
||||
name, desc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitArray(final String name) {
|
||||
return new SAXAnnotationAdapter(sa, "annotationValueArray", 0, name,
|
||||
null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
sa.addEnd(elementName);
|
||||
}
|
||||
|
||||
private void addValueElement(final String element, final String name,
|
||||
final String desc, final String value) {
|
||||
AttributesImpl att = new AttributesImpl();
|
||||
if (name != null) {
|
||||
att.addAttribute("", "name", "name", "", name);
|
||||
}
|
||||
if (desc != null) {
|
||||
att.addAttribute("", "desc", "desc", "", desc);
|
||||
}
|
||||
if (value != null) {
|
||||
att.addAttribute("", "value", "value", "",
|
||||
SAXClassAdapter.encode(value));
|
||||
}
|
||||
|
||||
sa.addElement(element, att);
|
||||
}
|
||||
}
|
||||
@@ -1,324 +0,0 @@
|
||||
/***
|
||||
* ASM XML Adapter
|
||||
* Copyright (c) 2004-2011, Eugene Kuleshov
|
||||
* 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.xml;
|
||||
|
||||
import org.objectweb.asm.AnnotationVisitor;
|
||||
import org.objectweb.asm.ClassVisitor;
|
||||
import org.objectweb.asm.FieldVisitor;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.xml.sax.ContentHandler;
|
||||
import org.xml.sax.helpers.AttributesImpl;
|
||||
|
||||
/**
|
||||
* A {@link org.objectweb.asm.ClassVisitor ClassVisitor} that generates SAX 2.0
|
||||
* events from the visited class. It can feed any kind of
|
||||
* {@link org.xml.sax.ContentHandler ContentHandler}, e.g. XML serializer, XSLT
|
||||
* or XQuery engines.
|
||||
*
|
||||
* @see Processor
|
||||
* @see ASMContentHandler
|
||||
*
|
||||
* @author Eugene Kuleshov
|
||||
*/
|
||||
public final class SAXClassAdapter extends ClassVisitor {
|
||||
|
||||
SAXAdapter sa;
|
||||
|
||||
private final boolean singleDocument;
|
||||
|
||||
/**
|
||||
* Pseudo access flag used to distinguish class access flags.
|
||||
*/
|
||||
private static final int ACCESS_CLASS = 262144;
|
||||
|
||||
/**
|
||||
* Pseudo access flag used to distinguish field access flags.
|
||||
*/
|
||||
private static final int ACCESS_FIELD = 524288;
|
||||
|
||||
/**
|
||||
* Pseudo access flag used to distinguish inner class flags.
|
||||
*/
|
||||
private static final int ACCESS_INNER = 1048576;
|
||||
|
||||
/**
|
||||
* Constructs a new {@link org.objectweb.asm.xml.SAXClassAdapter SAXClassAdapter} object.
|
||||
*
|
||||
* @param h
|
||||
* content handler that will be used to send SAX 2.0 events.
|
||||
* @param singleDocument
|
||||
* if <tt>true</tt> adapter will not produce
|
||||
* {@link org.xml.sax.ContentHandler#startDocument() startDocument()} and
|
||||
* {@link org.xml.sax.ContentHandler#endDocument() endDocument()} events.
|
||||
*/
|
||||
public SAXClassAdapter(final ContentHandler h, boolean singleDocument) {
|
||||
super(Opcodes.ASM4);
|
||||
this.sa = new SAXAdapter(h);
|
||||
this.singleDocument = singleDocument;
|
||||
if (!singleDocument) {
|
||||
sa.addDocumentStart();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitSource(final String source, final String debug) {
|
||||
AttributesImpl att = new AttributesImpl();
|
||||
if (source != null) {
|
||||
att.addAttribute("", "file", "file", "", encode(source));
|
||||
}
|
||||
if (debug != null) {
|
||||
att.addAttribute("", "debug", "debug", "", encode(debug));
|
||||
}
|
||||
|
||||
sa.addElement("source", att);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitOuterClass(final String owner, final String name,
|
||||
final String desc) {
|
||||
AttributesImpl att = new AttributesImpl();
|
||||
att.addAttribute("", "owner", "owner", "", owner);
|
||||
if (name != null) {
|
||||
att.addAttribute("", "name", "name", "", name);
|
||||
}
|
||||
if (desc != null) {
|
||||
att.addAttribute("", "desc", "desc", "", desc);
|
||||
}
|
||||
|
||||
sa.addElement("outerclass", att);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitAnnotation(final String desc,
|
||||
final boolean visible) {
|
||||
return new SAXAnnotationAdapter(sa, "annotation", visible ? 1 : -1,
|
||||
null, desc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(final int version, final int access, final String name,
|
||||
final String signature, final String superName,
|
||||
final String[] interfaces) {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
appendAccess(access | ACCESS_CLASS, sb);
|
||||
|
||||
AttributesImpl att = new AttributesImpl();
|
||||
att.addAttribute("", "access", "access", "", sb.toString());
|
||||
if (name != null) {
|
||||
att.addAttribute("", "name", "name", "", name);
|
||||
}
|
||||
if (signature != null) {
|
||||
att.addAttribute("", "signature", "signature", "",
|
||||
encode(signature));
|
||||
}
|
||||
if (superName != null) {
|
||||
att.addAttribute("", "parent", "parent", "", superName);
|
||||
}
|
||||
att.addAttribute("", "major", "major", "",
|
||||
Integer.toString(version & 0xFFFF));
|
||||
att.addAttribute("", "minor", "minor", "",
|
||||
Integer.toString(version >>> 16));
|
||||
sa.addStart("class", att);
|
||||
|
||||
sa.addStart("interfaces", new AttributesImpl());
|
||||
if (interfaces != null && interfaces.length > 0) {
|
||||
for (int i = 0; i < interfaces.length; i++) {
|
||||
AttributesImpl att2 = new AttributesImpl();
|
||||
att2.addAttribute("", "name", "name", "", interfaces[i]);
|
||||
sa.addElement("interface", att2);
|
||||
}
|
||||
}
|
||||
sa.addEnd("interfaces");
|
||||
}
|
||||
|
||||
@Override
|
||||
public FieldVisitor visitField(final int access, final String name,
|
||||
final String desc, final String signature, final Object value) {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
appendAccess(access | ACCESS_FIELD, sb);
|
||||
|
||||
AttributesImpl att = new AttributesImpl();
|
||||
att.addAttribute("", "access", "access", "", sb.toString());
|
||||
att.addAttribute("", "name", "name", "", name);
|
||||
att.addAttribute("", "desc", "desc", "", desc);
|
||||
if (signature != null) {
|
||||
att.addAttribute("", "signature", "signature", "",
|
||||
encode(signature));
|
||||
}
|
||||
if (value != null) {
|
||||
att.addAttribute("", "value", "value", "", encode(value.toString()));
|
||||
}
|
||||
|
||||
return new SAXFieldAdapter(sa, att);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodVisitor visitMethod(final int access, final String name,
|
||||
final String desc, final String signature, final String[] exceptions) {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
appendAccess(access, sb);
|
||||
|
||||
AttributesImpl att = new AttributesImpl();
|
||||
att.addAttribute("", "access", "access", "", sb.toString());
|
||||
att.addAttribute("", "name", "name", "", name);
|
||||
att.addAttribute("", "desc", "desc", "", desc);
|
||||
if (signature != null) {
|
||||
att.addAttribute("", "signature", "signature", "", signature);
|
||||
}
|
||||
sa.addStart("method", att);
|
||||
|
||||
sa.addStart("exceptions", new AttributesImpl());
|
||||
if (exceptions != null && exceptions.length > 0) {
|
||||
for (int i = 0; i < exceptions.length; i++) {
|
||||
AttributesImpl att2 = new AttributesImpl();
|
||||
att2.addAttribute("", "name", "name", "", exceptions[i]);
|
||||
sa.addElement("exception", att2);
|
||||
}
|
||||
}
|
||||
sa.addEnd("exceptions");
|
||||
|
||||
return new SAXCodeAdapter(sa, access);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void visitInnerClass(final String name,
|
||||
final String outerName, final String innerName, final int access) {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
appendAccess(access | ACCESS_INNER, sb);
|
||||
|
||||
AttributesImpl att = new AttributesImpl();
|
||||
att.addAttribute("", "access", "access", "", sb.toString());
|
||||
if (name != null) {
|
||||
att.addAttribute("", "name", "name", "", name);
|
||||
}
|
||||
if (outerName != null) {
|
||||
att.addAttribute("", "outerName", "outerName", "", outerName);
|
||||
}
|
||||
if (innerName != null) {
|
||||
att.addAttribute("", "innerName", "innerName", "", innerName);
|
||||
}
|
||||
sa.addElement("innerclass", att);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void visitEnd() {
|
||||
sa.addEnd("class");
|
||||
if (!singleDocument) {
|
||||
sa.addDocumentEnd();
|
||||
}
|
||||
}
|
||||
|
||||
static final String encode(final String s) {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
for (int i = 0; i < s.length(); i++) {
|
||||
char c = s.charAt(i);
|
||||
if (c == '\\') {
|
||||
sb.append("\\\\");
|
||||
} else if (c < 0x20 || c > 0x7f) {
|
||||
sb.append("\\u");
|
||||
if (c < 0x10) {
|
||||
sb.append("000");
|
||||
} else if (c < 0x100) {
|
||||
sb.append("00");
|
||||
} else if (c < 0x1000) {
|
||||
sb.append('0');
|
||||
}
|
||||
sb.append(Integer.toString(c, 16));
|
||||
} else {
|
||||
sb.append(c);
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
static void appendAccess(final int access, final StringBuffer sb) {
|
||||
if ((access & Opcodes.ACC_PUBLIC) != 0) {
|
||||
sb.append("public ");
|
||||
}
|
||||
if ((access & Opcodes.ACC_PRIVATE) != 0) {
|
||||
sb.append("private ");
|
||||
}
|
||||
if ((access & Opcodes.ACC_PROTECTED) != 0) {
|
||||
sb.append("protected ");
|
||||
}
|
||||
if ((access & Opcodes.ACC_FINAL) != 0) {
|
||||
sb.append("final ");
|
||||
}
|
||||
if ((access & Opcodes.ACC_STATIC) != 0) {
|
||||
sb.append("static ");
|
||||
}
|
||||
if ((access & Opcodes.ACC_SUPER) != 0) {
|
||||
if ((access & ACCESS_CLASS) == 0) {
|
||||
sb.append("synchronized ");
|
||||
} else {
|
||||
sb.append("super ");
|
||||
}
|
||||
}
|
||||
if ((access & Opcodes.ACC_VOLATILE) != 0) {
|
||||
if ((access & ACCESS_FIELD) == 0) {
|
||||
sb.append("bridge ");
|
||||
} else {
|
||||
sb.append("volatile ");
|
||||
}
|
||||
}
|
||||
if ((access & Opcodes.ACC_TRANSIENT) != 0) {
|
||||
if ((access & ACCESS_FIELD) == 0) {
|
||||
sb.append("varargs ");
|
||||
} else {
|
||||
sb.append("transient ");
|
||||
}
|
||||
}
|
||||
if ((access & Opcodes.ACC_NATIVE) != 0) {
|
||||
sb.append("native ");
|
||||
}
|
||||
if ((access & Opcodes.ACC_STRICT) != 0) {
|
||||
sb.append("strict ");
|
||||
}
|
||||
if ((access & Opcodes.ACC_INTERFACE) != 0) {
|
||||
sb.append("interface ");
|
||||
}
|
||||
if ((access & Opcodes.ACC_ABSTRACT) != 0) {
|
||||
sb.append("abstract ");
|
||||
}
|
||||
if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
|
||||
sb.append("synthetic ");
|
||||
}
|
||||
if ((access & Opcodes.ACC_ANNOTATION) != 0) {
|
||||
sb.append("annotation ");
|
||||
}
|
||||
if ((access & Opcodes.ACC_ENUM) != 0) {
|
||||
sb.append("enum ");
|
||||
}
|
||||
if ((access & Opcodes.ACC_DEPRECATED) != 0) {
|
||||
sb.append("deprecated ");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,362 +0,0 @@
|
||||
/***
|
||||
* ASM XML Adapter
|
||||
* Copyright (c) 2004-2011, Eugene Kuleshov
|
||||
* 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.xml;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.objectweb.asm.AnnotationVisitor;
|
||||
import org.objectweb.asm.Handle;
|
||||
import org.objectweb.asm.Label;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.util.Printer;
|
||||
import org.xml.sax.helpers.AttributesImpl;
|
||||
|
||||
/**
|
||||
* A {@link org.objectweb.asm.MethodVisitor} that generates SAX 2.0 events from the visited
|
||||
* method.
|
||||
*
|
||||
* @see SAXClassAdapter
|
||||
* @see Processor
|
||||
*
|
||||
* @author Eugene Kuleshov
|
||||
*/
|
||||
public final class SAXCodeAdapter extends MethodVisitor {
|
||||
|
||||
static final String[] TYPES = { "top", "int", "float", "double", "long",
|
||||
"null", "uninitializedThis" };
|
||||
|
||||
SAXAdapter sa;
|
||||
|
||||
private final Map<Label, String> labelNames;
|
||||
|
||||
/**
|
||||
* Constructs a new {@link org.objectweb.asm.xml.SAXCodeAdapter SAXCodeAdapter} object.
|
||||
*
|
||||
* @param sa
|
||||
* content handler that will be used to send SAX 2.0 events.
|
||||
*/
|
||||
public SAXCodeAdapter(final SAXAdapter sa, final int access) {
|
||||
super(Opcodes.ASM4);
|
||||
this.sa = sa;
|
||||
this.labelNames = new HashMap<Label, String>();
|
||||
|
||||
if ((access & (Opcodes.ACC_ABSTRACT | Opcodes.ACC_INTERFACE | Opcodes.ACC_NATIVE)) == 0) {
|
||||
sa.addStart("code", new AttributesImpl());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void visitCode() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitFrame(final int type, final int nLocal,
|
||||
final Object[] local, final int nStack, final Object[] stack) {
|
||||
AttributesImpl attrs = new AttributesImpl();
|
||||
switch (type) {
|
||||
case Opcodes.F_NEW:
|
||||
case Opcodes.F_FULL:
|
||||
if (type == Opcodes.F_NEW) {
|
||||
attrs.addAttribute("", "type", "type", "", "NEW");
|
||||
} else {
|
||||
attrs.addAttribute("", "type", "type", "", "FULL");
|
||||
}
|
||||
sa.addStart("frame", attrs);
|
||||
appendFrameTypes(true, nLocal, local);
|
||||
appendFrameTypes(false, nStack, stack);
|
||||
break;
|
||||
case Opcodes.F_APPEND:
|
||||
attrs.addAttribute("", "type", "type", "", "APPEND");
|
||||
sa.addStart("frame", attrs);
|
||||
appendFrameTypes(true, nLocal, local);
|
||||
break;
|
||||
case Opcodes.F_CHOP:
|
||||
attrs.addAttribute("", "type", "type", "", "CHOP");
|
||||
attrs.addAttribute("", "count", "count", "",
|
||||
Integer.toString(nLocal));
|
||||
sa.addStart("frame", attrs);
|
||||
break;
|
||||
case Opcodes.F_SAME:
|
||||
attrs.addAttribute("", "type", "type", "", "SAME");
|
||||
sa.addStart("frame", attrs);
|
||||
break;
|
||||
case Opcodes.F_SAME1:
|
||||
attrs.addAttribute("", "type", "type", "", "SAME1");
|
||||
sa.addStart("frame", attrs);
|
||||
appendFrameTypes(false, 1, stack);
|
||||
break;
|
||||
}
|
||||
sa.addEnd("frame");
|
||||
}
|
||||
|
||||
private void appendFrameTypes(final boolean local, final int n,
|
||||
final Object[] types) {
|
||||
for (int i = 0; i < n; ++i) {
|
||||
Object type = types[i];
|
||||
AttributesImpl attrs = new AttributesImpl();
|
||||
if (type instanceof String) {
|
||||
attrs.addAttribute("", "type", "type", "", (String) type);
|
||||
} else if (type instanceof Integer) {
|
||||
attrs.addAttribute("", "type", "type", "",
|
||||
TYPES[((Integer) type).intValue()]);
|
||||
} else {
|
||||
attrs.addAttribute("", "type", "type", "", "uninitialized");
|
||||
attrs.addAttribute("", "label", "label", "",
|
||||
getLabel((Label) type));
|
||||
}
|
||||
sa.addElement(local ? "local" : "stack", attrs);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void visitInsn(final int opcode) {
|
||||
sa.addElement(Printer.OPCODES[opcode], new AttributesImpl());
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void visitIntInsn(final int opcode, final int operand) {
|
||||
AttributesImpl attrs = new AttributesImpl();
|
||||
attrs.addAttribute("", "value", "value", "", Integer.toString(operand));
|
||||
sa.addElement(Printer.OPCODES[opcode], attrs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void visitVarInsn(final int opcode, final int var) {
|
||||
AttributesImpl attrs = new AttributesImpl();
|
||||
attrs.addAttribute("", "var", "var", "", Integer.toString(var));
|
||||
sa.addElement(Printer.OPCODES[opcode], attrs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void visitTypeInsn(final int opcode, final String type) {
|
||||
AttributesImpl attrs = new AttributesImpl();
|
||||
attrs.addAttribute("", "desc", "desc", "", type);
|
||||
sa.addElement(Printer.OPCODES[opcode], attrs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void visitFieldInsn(final int opcode, final String owner,
|
||||
final String name, final String desc) {
|
||||
AttributesImpl attrs = new AttributesImpl();
|
||||
attrs.addAttribute("", "owner", "owner", "", owner);
|
||||
attrs.addAttribute("", "name", "name", "", name);
|
||||
attrs.addAttribute("", "desc", "desc", "", desc);
|
||||
sa.addElement(Printer.OPCODES[opcode], attrs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void visitMethodInsn(final int opcode, final String owner,
|
||||
final String name, final String desc) {
|
||||
AttributesImpl attrs = new AttributesImpl();
|
||||
attrs.addAttribute("", "owner", "owner", "", owner);
|
||||
attrs.addAttribute("", "name", "name", "", name);
|
||||
attrs.addAttribute("", "desc", "desc", "", desc);
|
||||
sa.addElement(Printer.OPCODES[opcode], attrs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitInvokeDynamicInsn(String name, String desc, Handle bsm,
|
||||
Object... bsmArgs) {
|
||||
AttributesImpl attrs = new AttributesImpl();
|
||||
attrs.addAttribute("", "name", "name", "", name);
|
||||
attrs.addAttribute("", "desc", "desc", "", desc);
|
||||
attrs.addAttribute("", "bsm", "bsm", "",
|
||||
SAXClassAdapter.encode(bsm.toString()));
|
||||
sa.addStart("INVOKEDYNAMIC", attrs);
|
||||
for (int i = 0; i < bsmArgs.length; i++) {
|
||||
sa.addElement("bsmArg", getConstantAttribute(bsmArgs[i]));
|
||||
}
|
||||
sa.addEnd("INVOKEDYNAMIC");
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void visitJumpInsn(final int opcode, final Label label) {
|
||||
AttributesImpl attrs = new AttributesImpl();
|
||||
attrs.addAttribute("", "label", "label", "", getLabel(label));
|
||||
sa.addElement(Printer.OPCODES[opcode], attrs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void visitLabel(final Label label) {
|
||||
AttributesImpl attrs = new AttributesImpl();
|
||||
attrs.addAttribute("", "name", "name", "", getLabel(label));
|
||||
sa.addElement("Label", attrs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void visitLdcInsn(final Object cst) {
|
||||
sa.addElement(Printer.OPCODES[Opcodes.LDC], getConstantAttribute(cst));
|
||||
}
|
||||
|
||||
private static AttributesImpl getConstantAttribute(final Object cst) {
|
||||
AttributesImpl attrs = new AttributesImpl();
|
||||
attrs.addAttribute("", "cst", "cst", "",
|
||||
SAXClassAdapter.encode(cst.toString()));
|
||||
attrs.addAttribute("", "desc", "desc", "",
|
||||
Type.getDescriptor(cst.getClass()));
|
||||
return attrs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void visitIincInsn(final int var, final int increment) {
|
||||
AttributesImpl attrs = new AttributesImpl();
|
||||
attrs.addAttribute("", "var", "var", "", Integer.toString(var));
|
||||
attrs.addAttribute("", "inc", "inc", "", Integer.toString(increment));
|
||||
sa.addElement(Printer.OPCODES[Opcodes.IINC], attrs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void visitTableSwitchInsn(final int min, final int max,
|
||||
final Label dflt, final Label... labels) {
|
||||
AttributesImpl attrs = new AttributesImpl();
|
||||
attrs.addAttribute("", "min", "min", "", Integer.toString(min));
|
||||
attrs.addAttribute("", "max", "max", "", Integer.toString(max));
|
||||
attrs.addAttribute("", "dflt", "dflt", "", getLabel(dflt));
|
||||
String o = Printer.OPCODES[Opcodes.TABLESWITCH];
|
||||
sa.addStart(o, attrs);
|
||||
for (int i = 0; i < labels.length; i++) {
|
||||
AttributesImpl att2 = new AttributesImpl();
|
||||
att2.addAttribute("", "name", "name", "", getLabel(labels[i]));
|
||||
sa.addElement("label", att2);
|
||||
}
|
||||
sa.addEnd(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void visitLookupSwitchInsn(final Label dflt, final int[] keys,
|
||||
final Label[] labels) {
|
||||
AttributesImpl att = new AttributesImpl();
|
||||
att.addAttribute("", "dflt", "dflt", "", getLabel(dflt));
|
||||
String o = Printer.OPCODES[Opcodes.LOOKUPSWITCH];
|
||||
sa.addStart(o, att);
|
||||
for (int i = 0; i < labels.length; i++) {
|
||||
AttributesImpl att2 = new AttributesImpl();
|
||||
att2.addAttribute("", "name", "name", "", getLabel(labels[i]));
|
||||
att2.addAttribute("", "key", "key", "", Integer.toString(keys[i]));
|
||||
sa.addElement("label", att2);
|
||||
}
|
||||
sa.addEnd(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void visitMultiANewArrayInsn(final String desc, final int dims) {
|
||||
AttributesImpl attrs = new AttributesImpl();
|
||||
attrs.addAttribute("", "desc", "desc", "", desc);
|
||||
attrs.addAttribute("", "dims", "dims", "", Integer.toString(dims));
|
||||
sa.addElement(Printer.OPCODES[Opcodes.MULTIANEWARRAY], attrs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void visitTryCatchBlock(final Label start, final Label end,
|
||||
final Label handler, final String type) {
|
||||
AttributesImpl attrs = new AttributesImpl();
|
||||
attrs.addAttribute("", "start", "start", "", getLabel(start));
|
||||
attrs.addAttribute("", "end", "end", "", getLabel(end));
|
||||
attrs.addAttribute("", "handler", "handler", "", getLabel(handler));
|
||||
if (type != null) {
|
||||
attrs.addAttribute("", "type", "type", "", type);
|
||||
}
|
||||
sa.addElement("TryCatch", attrs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void visitMaxs(final int maxStack, final int maxLocals) {
|
||||
AttributesImpl attrs = new AttributesImpl();
|
||||
attrs.addAttribute("", "maxStack", "maxStack", "",
|
||||
Integer.toString(maxStack));
|
||||
attrs.addAttribute("", "maxLocals", "maxLocals", "",
|
||||
Integer.toString(maxLocals));
|
||||
sa.addElement("Max", attrs);
|
||||
|
||||
sa.addEnd("code");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLocalVariable(final String name, final String desc,
|
||||
final String signature, final Label start, final Label end,
|
||||
final int index) {
|
||||
AttributesImpl attrs = new AttributesImpl();
|
||||
attrs.addAttribute("", "name", "name", "", name);
|
||||
attrs.addAttribute("", "desc", "desc", "", desc);
|
||||
if (signature != null) {
|
||||
attrs.addAttribute("", "signature", "signature", "",
|
||||
SAXClassAdapter.encode(signature));
|
||||
}
|
||||
attrs.addAttribute("", "start", "start", "", getLabel(start));
|
||||
attrs.addAttribute("", "end", "end", "", getLabel(end));
|
||||
attrs.addAttribute("", "var", "var", "", Integer.toString(index));
|
||||
sa.addElement("LocalVar", attrs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void visitLineNumber(final int line, final Label start) {
|
||||
AttributesImpl attrs = new AttributesImpl();
|
||||
attrs.addAttribute("", "line", "line", "", Integer.toString(line));
|
||||
attrs.addAttribute("", "start", "start", "", getLabel(start));
|
||||
sa.addElement("LineNumber", attrs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitAnnotationDefault() {
|
||||
return new SAXAnnotationAdapter(sa, "annotationDefault", 0, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitAnnotation(final String desc,
|
||||
final boolean visible) {
|
||||
return new SAXAnnotationAdapter(sa, "annotation", visible ? 1 : -1,
|
||||
null, desc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitParameterAnnotation(final int parameter,
|
||||
final String desc, final boolean visible) {
|
||||
return new SAXAnnotationAdapter(sa, "parameterAnnotation", visible ? 1
|
||||
: -1, parameter, desc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
sa.addEnd("method");
|
||||
}
|
||||
|
||||
private final String getLabel(final Label label) {
|
||||
String name = labelNames.get(label);
|
||||
if (name == null) {
|
||||
name = Integer.toString(labelNames.size());
|
||||
labelNames.put(label, name);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
/***
|
||||
* ASM XML Adapter
|
||||
* Copyright (c) 2004-2011, Eugene Kuleshov
|
||||
* 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.xml;
|
||||
|
||||
import org.objectweb.asm.AnnotationVisitor;
|
||||
import org.objectweb.asm.FieldVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.xml.sax.Attributes;
|
||||
|
||||
/**
|
||||
* SAXFieldAdapter
|
||||
*
|
||||
* @author Eugene Kuleshov
|
||||
*/
|
||||
public final class SAXFieldAdapter extends FieldVisitor {
|
||||
|
||||
SAXAdapter sa;
|
||||
|
||||
public SAXFieldAdapter(final SAXAdapter sa, final Attributes att) {
|
||||
super(Opcodes.ASM4);
|
||||
this.sa = sa;
|
||||
sa.addStart("field", att);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitAnnotation(final String desc,
|
||||
final boolean visible) {
|
||||
return new SAXAnnotationAdapter(sa, "annotation", visible ? 1 : -1,
|
||||
null, desc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
sa.addEnd("field");
|
||||
}
|
||||
}
|
||||
@@ -1,349 +0,0 @@
|
||||
<!--
|
||||
ASM XML Adapter
|
||||
Copyright (c) 2004-2011, Eugene Kuleshov
|
||||
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.
|
||||
-->
|
||||
|
||||
<!--
|
||||
This DTD must be used to create XML documents to be processed by
|
||||
org.objectweb.asm.xml.ASMContentHandler
|
||||
-->
|
||||
|
||||
<!--
|
||||
Root element used to aggregate multiple classes into single document.
|
||||
-->
|
||||
<!ELEMENT classes ( class+ )>
|
||||
|
||||
<!--
|
||||
Root element for a single class.
|
||||
-->
|
||||
<!ELEMENT class ( interfaces, ( field | innerclass | method )*)>
|
||||
<!ATTLIST class access CDATA #REQUIRED>
|
||||
<!ATTLIST class name CDATA #REQUIRED>
|
||||
<!ATTLIST class parent CDATA #REQUIRED>
|
||||
<!ATTLIST class major CDATA #REQUIRED>
|
||||
<!ATTLIST class minor CDATA #REQUIRED>
|
||||
<!ATTLIST class source CDATA #IMPLIED>
|
||||
|
||||
<!ELEMENT interfaces ( interface* )>
|
||||
<!ELEMENT interface EMPTY>
|
||||
<!ATTLIST interface name CDATA #REQUIRED>
|
||||
|
||||
<!ELEMENT field EMPTY>
|
||||
<!ATTLIST field access CDATA #REQUIRED>
|
||||
<!ATTLIST field desc CDATA #REQUIRED>
|
||||
<!ATTLIST field name CDATA #REQUIRED>
|
||||
<!--
|
||||
All characters out of interval 0x20 to 0x7f (inclusive) must
|
||||
be encoded (\uXXXX) and character '\' must be replaced by "\\"
|
||||
-->
|
||||
<!ATTLIST field value CDATA #IMPLIED>
|
||||
|
||||
<!ELEMENT innerclass EMPTY>
|
||||
<!ATTLIST innerclass access CDATA #REQUIRED>
|
||||
<!ATTLIST innerclass innerName CDATA #IMPLIED>
|
||||
<!ATTLIST innerclass name CDATA #REQUIRED>
|
||||
<!ATTLIST innerclass outerName CDATA #IMPLIED>
|
||||
|
||||
<!--
|
||||
Root element for method definition.
|
||||
-->
|
||||
<!ELEMENT method ( exceptions, code? )>
|
||||
<!ATTLIST method access CDATA #REQUIRED>
|
||||
<!ATTLIST method desc CDATA #REQUIRED>
|
||||
<!ATTLIST method name CDATA #REQUIRED>
|
||||
|
||||
<!ELEMENT exceptions ( exception* )>
|
||||
<!ELEMENT exception EMPTY>
|
||||
<!ATTLIST exception name CDATA #REQUIRED>
|
||||
|
||||
<!--
|
||||
code element contains bytecode instructions and definitions for labels, line numbers, try/catch and max
|
||||
-->
|
||||
<!ELEMENT code (( AALOAD | AASTORE | ACONST_NULL | ALOAD | ANEWARRAY | ARETURN | ARRAYLENGTH | ASTORE | ATHROW | BALOAD | BASTORE | BIPUSH | CALOAD | CASTORE | CHECKCAST | D2F | D2I | D2L | DADD | DALOAD | DASTORE | DCMPG | DCMPL | DCONST_0 | DCONST_1 | DDIV | DLOAD | DMUL | DNEG | DREM | DRETURN | DSTORE | DSUB | DUP | DUP2 | DUP2_X1 | DUP2_X2 | DUP_X1 | DUP_X2 | SWAP | F2D | F2I | F2L | FADD | FALOAD | FASTORE | FCMPG | FCMPL | FCONST_0 | FCONST_1 | FCONST_2 | FDIV | FLOAD | FMUL | FNEG | FREM | FRETURN | FSTORE | FSUB | GETFIELD | GETSTATIC | GOTO | I2B | I2C | I2D | I2F | I2L | I2S | IADD | IALOAD | IAND | IASTORE | ICONST_0 | ICONST_1 | ICONST_2 | ICONST_3 | ICONST_4 | ICONST_5 | ICONST_M1 | IDIV | IFEQ | IFGE | IFGT | IFLE | IFLT | IFNE | IFNONNULL | IFNULL | IF_ACMPEQ | IF_ACMPNE | IF_ICMPEQ | IF_ICMPGE | IF_ICMPGT | IF_ICMPLE | IF_ICMPLT | IF_ICMPNE | IINC | ILOAD | IMUL | INEG | INSTANCEOF | INVOKEINTERFACE | INVOKESPECIAL | INVOKESTATIC | INVOKEVIRTUAL | IOR | IREM | IRETURN | ISHL | ISHR | ISTORE | ISUB | IUSHR | IXOR | JSR | L2D | L2F | L2I | LADD | LALOAD | LAND | LASTORE | LCMP | LCONST_0 | LCONST_1 | LDC | LDIV | LLOAD | LMUL | LNEG | LOOKUPSWITCH | LOR | LREM | LRETURN | LSHL | LSHR | LSTORE | LSUB | LUSHR | LXOR | MONITORENTER | MONITOREXIT | MULTIANEWARRAY | NEW | NEWARRAY | NOP | POP | POP2 | PUTFIELD | PUTSTATIC | RET | RETURN | SALOAD | SASTORE | SIPUSH | TABLESWITCH | Label | LineNumber | TryCatch )*, Max)>
|
||||
|
||||
<!ELEMENT Label EMPTY>
|
||||
<!ATTLIST Label name CDATA #REQUIRED>
|
||||
|
||||
<!ELEMENT TryCatch EMPTY>
|
||||
<!ATTLIST TryCatch end CDATA #REQUIRED>
|
||||
<!ATTLIST TryCatch handler CDATA #REQUIRED>
|
||||
<!ATTLIST TryCatch start CDATA #REQUIRED>
|
||||
<!ATTLIST TryCatch type CDATA #IMPLIED>
|
||||
|
||||
<!ELEMENT LineNumber EMPTY>
|
||||
<!ATTLIST LineNumber line CDATA #REQUIRED>
|
||||
<!ATTLIST LineNumber start CDATA #REQUIRED>
|
||||
|
||||
<!ELEMENT Max EMPTY>
|
||||
<!ATTLIST Max maxLocals CDATA #REQUIRED>
|
||||
<!ATTLIST Max maxStack CDATA #REQUIRED>
|
||||
|
||||
<!ELEMENT AALOAD EMPTY>
|
||||
<!ELEMENT AASTORE EMPTY>
|
||||
<!ELEMENT ACONST_NULL EMPTY>
|
||||
<!ELEMENT ALOAD EMPTY>
|
||||
<!ATTLIST ALOAD var CDATA #REQUIRED>
|
||||
<!ELEMENT ANEWARRAY EMPTY>
|
||||
<!ATTLIST ANEWARRAY desc CDATA #REQUIRED>
|
||||
<!ELEMENT ARETURN EMPTY>
|
||||
<!ELEMENT ARRAYLENGTH EMPTY>
|
||||
<!ELEMENT ASTORE EMPTY>
|
||||
<!ATTLIST ASTORE var CDATA #REQUIRED>
|
||||
<!ELEMENT ATHROW EMPTY>
|
||||
<!ELEMENT BALOAD EMPTY>
|
||||
<!ELEMENT BASTORE EMPTY>
|
||||
<!ELEMENT BIPUSH EMPTY>
|
||||
<!ATTLIST BIPUSH value CDATA #REQUIRED>
|
||||
<!ELEMENT CALOAD EMPTY>
|
||||
<!ELEMENT CASTORE EMPTY>
|
||||
<!ELEMENT CHECKCAST EMPTY>
|
||||
<!ATTLIST CHECKCAST desc CDATA #REQUIRED>
|
||||
<!ELEMENT D2F EMPTY>
|
||||
<!ELEMENT D2I EMPTY>
|
||||
<!ELEMENT D2L EMPTY>
|
||||
<!ELEMENT DADD EMPTY>
|
||||
<!ELEMENT DALOAD EMPTY>
|
||||
<!ELEMENT DASTORE EMPTY>
|
||||
<!ELEMENT DCMPG EMPTY>
|
||||
<!ELEMENT DCMPL EMPTY>
|
||||
<!ELEMENT DCONST_0 EMPTY>
|
||||
<!ELEMENT DCONST_1 EMPTY>
|
||||
<!ELEMENT DDIV EMPTY>
|
||||
<!ELEMENT DLOAD EMPTY>
|
||||
<!ATTLIST DLOAD var CDATA #REQUIRED>
|
||||
<!ELEMENT DMUL EMPTY>
|
||||
<!ELEMENT DNEG EMPTY>
|
||||
<!ELEMENT DREM EMPTY>
|
||||
<!ELEMENT DRETURN EMPTY>
|
||||
<!ELEMENT DSTORE EMPTY>
|
||||
<!ATTLIST DSTORE var CDATA #REQUIRED>
|
||||
<!ELEMENT DSUB EMPTY>
|
||||
<!ELEMENT DUP EMPTY>
|
||||
<!ELEMENT DUP2 EMPTY>
|
||||
<!ELEMENT DUP2_X1 EMPTY>
|
||||
<!ELEMENT DUP2_X2 EMPTY>
|
||||
<!ELEMENT DUP_X1 EMPTY>
|
||||
<!ELEMENT DUP_X2 EMPTY>
|
||||
<!ELEMENT SWAP EMPTY>
|
||||
<!ELEMENT F2D EMPTY>
|
||||
<!ELEMENT F2I EMPTY>
|
||||
<!ELEMENT F2L EMPTY>
|
||||
<!ELEMENT FADD EMPTY>
|
||||
<!ELEMENT FALOAD EMPTY>
|
||||
<!ELEMENT FASTORE EMPTY>
|
||||
<!ELEMENT FCMPG EMPTY>
|
||||
<!ELEMENT FCMPL EMPTY>
|
||||
<!ELEMENT FCONST_0 EMPTY>
|
||||
<!ELEMENT FCONST_1 EMPTY>
|
||||
<!ELEMENT FCONST_2 EMPTY>
|
||||
<!ELEMENT FDIV EMPTY>
|
||||
<!ELEMENT FLOAD EMPTY>
|
||||
<!ATTLIST FLOAD var CDATA #REQUIRED>
|
||||
<!ELEMENT FMUL EMPTY>
|
||||
<!ELEMENT FNEG EMPTY>
|
||||
<!ELEMENT FREM EMPTY>
|
||||
<!ELEMENT FRETURN EMPTY>
|
||||
<!ELEMENT FSTORE EMPTY>
|
||||
<!ATTLIST FSTORE var CDATA #REQUIRED>
|
||||
<!ELEMENT FSUB EMPTY>
|
||||
<!ELEMENT GETFIELD EMPTY>
|
||||
<!ATTLIST GETFIELD desc CDATA #REQUIRED>
|
||||
<!ATTLIST GETFIELD name CDATA #REQUIRED>
|
||||
<!ATTLIST GETFIELD owner CDATA #REQUIRED>
|
||||
<!ELEMENT GETSTATIC EMPTY>
|
||||
<!ATTLIST GETSTATIC desc CDATA #REQUIRED>
|
||||
<!ATTLIST GETSTATIC name CDATA #REQUIRED>
|
||||
<!ATTLIST GETSTATIC owner CDATA #REQUIRED>
|
||||
<!ELEMENT GOTO EMPTY>
|
||||
<!ATTLIST GOTO label CDATA #REQUIRED>
|
||||
<!ELEMENT I2B EMPTY>
|
||||
<!ELEMENT I2C EMPTY>
|
||||
<!ELEMENT I2D EMPTY>
|
||||
<!ELEMENT I2F EMPTY>
|
||||
<!ELEMENT I2L EMPTY>
|
||||
<!ELEMENT I2S EMPTY>
|
||||
<!ELEMENT IADD EMPTY>
|
||||
<!ELEMENT IALOAD EMPTY>
|
||||
<!ELEMENT IAND EMPTY>
|
||||
<!ELEMENT IASTORE EMPTY>
|
||||
<!ELEMENT ICONST_0 EMPTY>
|
||||
<!ELEMENT ICONST_1 EMPTY>
|
||||
<!ELEMENT ICONST_2 EMPTY>
|
||||
<!ELEMENT ICONST_3 EMPTY>
|
||||
<!ELEMENT ICONST_4 EMPTY>
|
||||
<!ELEMENT ICONST_5 EMPTY>
|
||||
<!ELEMENT ICONST_M1 EMPTY>
|
||||
<!ELEMENT IDIV EMPTY>
|
||||
<!ELEMENT IFEQ EMPTY>
|
||||
<!ATTLIST IFEQ label CDATA #REQUIRED>
|
||||
<!ELEMENT IFGE EMPTY>
|
||||
<!ATTLIST IFGE label CDATA #REQUIRED>
|
||||
<!ELEMENT IFGT EMPTY>
|
||||
<!ATTLIST IFGT label CDATA #REQUIRED>
|
||||
<!ELEMENT IFLE EMPTY>
|
||||
<!ATTLIST IFLE label CDATA #REQUIRED>
|
||||
<!ELEMENT IFLT EMPTY>
|
||||
<!ATTLIST IFLT label CDATA #REQUIRED>
|
||||
<!ELEMENT IFNE EMPTY>
|
||||
<!ATTLIST IFNE label CDATA #REQUIRED>
|
||||
<!ELEMENT IFNONNULL EMPTY>
|
||||
<!ATTLIST IFNONNULL label CDATA #REQUIRED>
|
||||
<!ELEMENT IFNULL EMPTY>
|
||||
<!ATTLIST IFNULL label CDATA #REQUIRED>
|
||||
<!ELEMENT IF_ACMPEQ EMPTY>
|
||||
<!ATTLIST IF_ACMPEQ label CDATA #REQUIRED>
|
||||
<!ELEMENT IF_ACMPNE EMPTY>
|
||||
<!ATTLIST IF_ACMPNE label CDATA #REQUIRED>
|
||||
<!ELEMENT IF_ICMPEQ EMPTY>
|
||||
<!ATTLIST IF_ICMPEQ label CDATA #REQUIRED>
|
||||
<!ELEMENT IF_ICMPGE EMPTY>
|
||||
<!ATTLIST IF_ICMPGE label CDATA #REQUIRED>
|
||||
<!ELEMENT IF_ICMPGT EMPTY>
|
||||
<!ATTLIST IF_ICMPGT label CDATA #REQUIRED>
|
||||
<!ELEMENT IF_ICMPLE EMPTY>
|
||||
<!ATTLIST IF_ICMPLE label CDATA #REQUIRED>
|
||||
<!ELEMENT IF_ICMPLT EMPTY>
|
||||
<!ATTLIST IF_ICMPLT label CDATA #REQUIRED>
|
||||
<!ELEMENT IF_ICMPNE EMPTY>
|
||||
<!ATTLIST IF_ICMPNE label CDATA #REQUIRED>
|
||||
<!ELEMENT IINC EMPTY>
|
||||
<!ATTLIST IINC inc CDATA #REQUIRED>
|
||||
<!ATTLIST IINC var CDATA #REQUIRED>
|
||||
<!ELEMENT ILOAD EMPTY>
|
||||
<!ATTLIST ILOAD var CDATA #REQUIRED>
|
||||
<!ELEMENT IMUL EMPTY>
|
||||
<!ELEMENT INEG EMPTY>
|
||||
<!ELEMENT INSTANCEOF EMPTY>
|
||||
<!ATTLIST INSTANCEOF desc CDATA #REQUIRED>
|
||||
<!ELEMENT INVOKEINTERFACE EMPTY>
|
||||
<!ATTLIST INVOKEINTERFACE desc CDATA #REQUIRED>
|
||||
<!ATTLIST INVOKEINTERFACE name CDATA #REQUIRED>
|
||||
<!ATTLIST INVOKEINTERFACE owner CDATA #REQUIRED>
|
||||
<!ELEMENT INVOKESPECIAL EMPTY>
|
||||
<!ATTLIST INVOKESPECIAL desc CDATA #REQUIRED>
|
||||
<!ATTLIST INVOKESPECIAL name CDATA #REQUIRED>
|
||||
<!ATTLIST INVOKESPECIAL owner CDATA #REQUIRED>
|
||||
<!ELEMENT INVOKESTATIC EMPTY>
|
||||
<!ATTLIST INVOKESTATIC desc CDATA #REQUIRED>
|
||||
<!ATTLIST INVOKESTATIC name CDATA #REQUIRED>
|
||||
<!ATTLIST INVOKESTATIC owner CDATA #REQUIRED>
|
||||
<!ELEMENT INVOKEVIRTUAL EMPTY>
|
||||
<!ATTLIST INVOKEVIRTUAL desc CDATA #REQUIRED>
|
||||
<!ATTLIST INVOKEVIRTUAL name CDATA #REQUIRED>
|
||||
<!ATTLIST INVOKEVIRTUAL owner CDATA #REQUIRED>
|
||||
<!ELEMENT INVOKEDYNAMIC ( bsmArgs+ )>
|
||||
<!ATTLIST INVOKEDYNAMIC desc CDATA #REQUIRED>
|
||||
<!ATTLIST INVOKEDYNAMIC name CDATA #REQUIRED>
|
||||
<!ATTLIST INVOKEDYNAMIC bsm CDATA #REQUIRED>
|
||||
<!ELEMENT bsmArgs EMPTY>
|
||||
<!ATTLIST bsmArgs cst CDATA #REQUIRED>
|
||||
<!ATTLIST bsmArgs desc CDATA #REQUIRED>
|
||||
<!ELEMENT IOR EMPTY>
|
||||
<!ELEMENT IREM EMPTY>
|
||||
<!ELEMENT IRETURN EMPTY>
|
||||
<!ELEMENT ISHL EMPTY>
|
||||
<!ELEMENT ISHR EMPTY>
|
||||
<!ELEMENT ISTORE EMPTY>
|
||||
<!ATTLIST ISTORE var CDATA #REQUIRED>
|
||||
<!ELEMENT ISUB EMPTY>
|
||||
<!ELEMENT IUSHR EMPTY>
|
||||
<!ELEMENT IXOR EMPTY>
|
||||
<!ELEMENT JSR EMPTY>
|
||||
<!ATTLIST JSR label CDATA #REQUIRED>
|
||||
<!ELEMENT L2D EMPTY>
|
||||
<!ELEMENT L2F EMPTY>
|
||||
<!ELEMENT L2I EMPTY>
|
||||
<!ELEMENT LADD EMPTY>
|
||||
<!ELEMENT LALOAD EMPTY>
|
||||
<!ELEMENT LAND EMPTY>
|
||||
<!ELEMENT LASTORE EMPTY>
|
||||
<!ELEMENT LCMP EMPTY>
|
||||
<!ELEMENT LCONST_0 EMPTY>
|
||||
<!ELEMENT LCONST_1 EMPTY>
|
||||
<!ELEMENT LDC EMPTY>
|
||||
<!--
|
||||
All characters out of interval 0x20 to 0x7f (inclusive) must
|
||||
be encoded (\uXXXX) and character '\' must be replaced by "\\"
|
||||
-->
|
||||
<!ATTLIST LDC cst CDATA #REQUIRED>
|
||||
<!ATTLIST LDC desc CDATA #REQUIRED>
|
||||
<!ELEMENT LDIV EMPTY>
|
||||
<!ELEMENT LLOAD EMPTY>
|
||||
<!ATTLIST LLOAD var CDATA #REQUIRED>
|
||||
<!ELEMENT LMUL EMPTY>
|
||||
<!ELEMENT LNEG EMPTY>
|
||||
<!ELEMENT LOR EMPTY>
|
||||
<!ELEMENT LREM EMPTY>
|
||||
<!ELEMENT LRETURN EMPTY>
|
||||
<!ELEMENT LSHL EMPTY>
|
||||
<!ELEMENT LSHR EMPTY>
|
||||
<!ELEMENT LSTORE EMPTY>
|
||||
<!ATTLIST LSTORE var CDATA #REQUIRED>
|
||||
<!ELEMENT LSUB EMPTY>
|
||||
<!ELEMENT LUSHR EMPTY>
|
||||
<!ELEMENT LXOR EMPTY>
|
||||
<!ELEMENT MONITORENTER EMPTY>
|
||||
<!ELEMENT MONITOREXIT EMPTY>
|
||||
<!ELEMENT MULTIANEWARRAY EMPTY>
|
||||
<!ATTLIST MULTIANEWARRAY desc CDATA #REQUIRED>
|
||||
<!ATTLIST MULTIANEWARRAY dims CDATA #REQUIRED>
|
||||
<!ELEMENT NEW EMPTY>
|
||||
<!ATTLIST NEW desc CDATA #REQUIRED>
|
||||
<!ELEMENT NEWARRAY EMPTY>
|
||||
<!ATTLIST NEWARRAY value CDATA #REQUIRED>
|
||||
<!ELEMENT NOP EMPTY>
|
||||
<!ELEMENT POP EMPTY>
|
||||
<!ELEMENT POP2 EMPTY>
|
||||
<!ELEMENT PUTFIELD EMPTY>
|
||||
<!ATTLIST PUTFIELD desc CDATA #REQUIRED>
|
||||
<!ATTLIST PUTFIELD name CDATA #REQUIRED>
|
||||
<!ATTLIST PUTFIELD owner CDATA #REQUIRED>
|
||||
<!ELEMENT PUTSTATIC EMPTY>
|
||||
<!ATTLIST PUTSTATIC desc CDATA #REQUIRED>
|
||||
<!ATTLIST PUTSTATIC name CDATA #REQUIRED>
|
||||
<!ATTLIST PUTSTATIC owner CDATA #REQUIRED>
|
||||
<!ELEMENT RET EMPTY>
|
||||
<!ATTLIST RET var CDATA #REQUIRED>
|
||||
<!ELEMENT RETURN EMPTY>
|
||||
<!ELEMENT SALOAD EMPTY>
|
||||
<!ELEMENT SASTORE EMPTY>
|
||||
<!ELEMENT SIPUSH EMPTY>
|
||||
<!ATTLIST SIPUSH value CDATA #REQUIRED>
|
||||
|
||||
<!ELEMENT LOOKUPSWITCH ( label+ )>
|
||||
<!ATTLIST LOOKUPSWITCH dflt CDATA #REQUIRED>
|
||||
|
||||
<!ELEMENT TABLESWITCH ( label+ )>
|
||||
<!ATTLIST TABLESWITCH dflt CDATA #REQUIRED>
|
||||
<!ATTLIST TABLESWITCH max CDATA #REQUIRED>
|
||||
<!ATTLIST TABLESWITCH min CDATA #REQUIRED>
|
||||
|
||||
<!ELEMENT label EMPTY>
|
||||
<!ATTLIST label key CDATA #IMPLIED>
|
||||
<!ATTLIST label name CDATA #REQUIRED>
|
||||
|
||||
@@ -1,96 +0,0 @@
|
||||
<html>
|
||||
<!--
|
||||
* ASM XML Adapter
|
||||
* Copyright (c) 2004-2011, Eugene Kuleshov
|
||||
* 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.
|
||||
-->
|
||||
<body>
|
||||
Provides <a href="http://sax.sourceforge.net/">SAX 2.0</a> adapters for ASM
|
||||
visitors to convert classes to and from XML.
|
||||
These adapters can be chained with other SAX compliant content handlers and
|
||||
filters, eg. XSLT or XQuery engines. This package is bundled as
|
||||
a separate <tt>asm-xml.jar</tt> library and requires <tt>asm.jar</tt>.
|
||||
<p>
|
||||
<tt>ASMContentHandler</tt> and <tt>SAXClassAdapter/SAXCodeAdapter</tt>
|
||||
are using <a href="asm-xml.dtd">asm-xml.dtd</a>.
|
||||
Here is the example of bytecode to bytecode XSLT transformation.
|
||||
|
||||
<pre>
|
||||
SAXTransformerFactory saxtf = ( SAXTransformerFactory) TransformerFactory.newInstance();
|
||||
Templates templates = saxtf.newTemplates( xsltSource);
|
||||
|
||||
TransformerHandler handler = saxtf.newTransformerHandler( templates);
|
||||
handler.setResult( new SAXResult( new ASMContentHandler( outputStream, computeMax)));
|
||||
|
||||
ClassReader cr = new ClassReader( bytecode);
|
||||
cr.accept( new SAXClassAdapter( handler, cr.getVersion(), false), false);
|
||||
</pre>
|
||||
|
||||
See JAXP and SAX documentation for more detils.
|
||||
|
||||
<p>
|
||||
There are few illustrations of the bytecode transformation with XSLT in
|
||||
examples directory. The following XSLT procesors has been tested.
|
||||
|
||||
<blockquote>
|
||||
<table border="1" cellspacing="0" cellpadding="3">
|
||||
<tr>
|
||||
<th>Engine</td>
|
||||
<th>javax.xml.transform.TransformerFactory property</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>jd.xslt</td>
|
||||
<td>jd.xml.xslt.trax.TransformerFactoryImpl</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>Saxon</td>
|
||||
<td>net.sf.saxon.TransformerFactoryImpl</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>Caucho</td>
|
||||
<td>com.caucho.xsl.Xsl</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>Xalan interpeter</td>
|
||||
<td>org.apache.xalan.processor.TransformerFactory</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>Xalan xsltc</td>
|
||||
<td>org.apache.xalan.xsltc.trax.TransformerFactoryImpl</td>
|
||||
</tr>
|
||||
</table>
|
||||
</blockquote>
|
||||
|
||||
@since ASM 1.4.3
|
||||
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user