下面列出了org.objectweb.asm.Type#getSort ( ) 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
public static AbstractInsnNode getRandomValue(Type type) {
switch (type.getSort()) {
case Type.BOOLEAN:
return ASMUtils.getNumberInsn(RandomUtils.getRandomInt(0, 2));
case Type.CHAR:
return ASMUtils.getNumberInsn(RandomUtils.getRandomInt(Character.MIN_VALUE, Character.MAX_VALUE));
case Type.BYTE:
return ASMUtils.getNumberInsn(RandomUtils.getRandomInt(Byte.MIN_VALUE, Byte.MAX_VALUE));
case Type.SHORT:
return ASMUtils.getNumberInsn(RandomUtils.getRandomInt(Short.MIN_VALUE, Short.MAX_VALUE));
case Type.INT:
return ASMUtils.getNumberInsn(RandomUtils.getRandomInt());
case Type.FLOAT:
return ASMUtils.getNumberInsn(RandomUtils.getRandomFloat());
case Type.LONG:
return ASMUtils.getNumberInsn(RandomUtils.getRandomLong());
case Type.DOUBLE:
return ASMUtils.getNumberInsn(RandomUtils.getRandomDouble());
case Type.ARRAY:
case Type.OBJECT:
return new InsnNode(Opcodes.ACONST_NULL);
default:
throw new AssertionError();
}
}
static void pushDefault(MethodVisitor mv, Type type) {
switch (type.getSort()) {
case Type.BOOLEAN:
mv.visitInsn(ICONST_0);
break;
case Type.CHAR:
case Type.BYTE:
case Type.SHORT:
case Type.INT:
mv.visitInsn(ICONST_0);
break;
case Type.FLOAT:
mv.visitInsn(FCONST_0);
break;
case Type.LONG:
mv.visitInsn(LCONST_0);
break;
case Type.DOUBLE:
mv.visitInsn(DCONST_0);
break;
default:
mv.visitInsn(ACONST_NULL);
break;
}
}
public static Type resolveBinOpType(Type type1, Type type2) {
if (isObjectRef(type1) || isObjectRef(type2)) {
if (isObjectRef(type1) != isObjectRef(type2)) {
throw new IllegalStateException("Illegal binop types: " + type1 + " " + type2);
}
return OBJECT_TYPE;
} else if (type1 == Type.DOUBLE_TYPE || type2 == Type.DOUBLE_TYPE) {
return Type.DOUBLE_TYPE;
} else if (type1 == Type.FLOAT_TYPE || type2 == Type.FLOAT_TYPE) {
return Type.FLOAT_TYPE;
} else if (type1 == Type.LONG_TYPE || type2 == Type.LONG_TYPE) {
return Type.LONG_TYPE;
} else if (type1.getSort() >= Type.BOOLEAN && type1.getSort() <= Type.INT && type2.getSort() >= Type.BOOLEAN && type2.getSort() <= Type.INT) {
return Type.INT_TYPE;
} else {
throw new UnsupportedOperationException("Unsupported binop types: " + type1 + " " + type2);
}
}
private void pushDefault(Type type) {
switch (type.getSort()) {
case Type.VOID:
break;
case Type.DOUBLE:
mv.visitInsn(DCONST_0);
break;
case Type.LONG:
mv.visitInsn(LCONST_0);
break;
case Type.FLOAT:
mv.visitInsn(FCONST_0);
break;
case Type.OBJECT:
case Type.ARRAY:
mv.visitInsn(ACONST_NULL);
break;
default:
mv.visitInsn(ICONST_0);
break;
}
}
private void pushDefault(Type type) {
switch (type.getSort()) {
case Type.VOID:
break;
case Type.DOUBLE:
mv.visitInsn(DCONST_0);
break;
case Type.LONG:
mv.visitInsn(LCONST_0);
break;
case Type.FLOAT:
mv.visitInsn(FCONST_0);
break;
case Type.OBJECT:
case Type.ARRAY:
mv.visitInsn(ACONST_NULL);
break;
default:
mv.visitInsn(ICONST_0);
break;
}
}
public static int getReturnOpcode(Type type) {
switch (type.getSort()) {
case Type.BOOLEAN:
case Type.CHAR:
case Type.BYTE:
case Type.SHORT:
case Type.INT:
return Opcodes.IRETURN;
case Type.FLOAT:
return Opcodes.FRETURN;
case Type.LONG:
return Opcodes.LRETURN;
case Type.DOUBLE:
return Opcodes.DRETURN;
case Type.ARRAY:
case Type.OBJECT:
return Opcodes.ARETURN;
case Type.VOID:
return Opcodes.RETURN;
default:
throw new AssertionError("Unknown type sort: " + type.getClassName());
}
}
/**
* Generates the instruction to create a new array.
*
* @param type the type of the array elements.
*/
public void newArray(final Type type) {
int arrayType;
switch (type.getSort()) {
case Type.BOOLEAN:
arrayType = Opcodes.T_BOOLEAN;
break;
case Type.CHAR:
arrayType = Opcodes.T_CHAR;
break;
case Type.BYTE:
arrayType = Opcodes.T_BYTE;
break;
case Type.SHORT:
arrayType = Opcodes.T_SHORT;
break;
case Type.INT:
arrayType = Opcodes.T_INT;
break;
case Type.FLOAT:
arrayType = Opcodes.T_FLOAT;
break;
case Type.LONG:
arrayType = Opcodes.T_LONG;
break;
case Type.DOUBLE:
arrayType = Opcodes.T_DOUBLE;
break;
default:
typeInsn(Opcodes.ANEWARRAY, type);
return;
}
mv.visitIntInsn(Opcodes.NEWARRAY, arrayType);
}
private static Class<?> getType(Type type) throws ClassNotFoundException {
switch (type.getSort()) {
case Type.VOID:
return void.class;
case Type.BOOLEAN:
return boolean.class;
case Type.CHAR:
return char.class;
case Type.BYTE:
return byte.class;
case Type.SHORT:
return short.class;
case Type.INT:
return int.class;
case Type.FLOAT:
return float.class;
case Type.LONG:
return long.class;
case Type.DOUBLE:
return double.class;
case Type.ARRAY:
return Util.getArrayClass(getType(type.getElementType()),
type.getDimensions());
default:
return Class.forName(type.getClassName(), false, null);
}
}
@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 (arrayType.equals(NULL_TYPE)) {
return objectArrayValue;
}
}
throw new AssertionError();
}
/**
* Generates the instruction to create a new array.
*
* @param type the type of the array elements.
*/
public void newArray(final Type type) {
int arrayType;
switch (type.getSort()) {
case Type.BOOLEAN:
arrayType = Opcodes.T_BOOLEAN;
break;
case Type.CHAR:
arrayType = Opcodes.T_CHAR;
break;
case Type.BYTE:
arrayType = Opcodes.T_BYTE;
break;
case Type.SHORT:
arrayType = Opcodes.T_SHORT;
break;
case Type.INT:
arrayType = Opcodes.T_INT;
break;
case Type.FLOAT:
arrayType = Opcodes.T_FLOAT;
break;
case Type.LONG:
arrayType = Opcodes.T_LONG;
break;
case Type.DOUBLE:
arrayType = Opcodes.T_DOUBLE;
break;
default:
typeInsn(Opcodes.ANEWARRAY, type);
return;
}
mv.visitIntInsn(Opcodes.NEWARRAY, arrayType);
}
/**
* Returns whether the class corresponding to the first argument is either the same as, or is a
* superclass or superinterface of the class corresponding to the second argument. The default
* implementation of this method loads the classes and uses the reflection API to return its
* result (unless the result can be computed from the class being verified, and the types of its
* super classes and implemented interfaces).
*
* @param type1 a type.
* @param type2 another type.
* @return whether the class corresponding to 'type1' is either the same as, or is a superclass or
* superinterface of the class corresponding to 'type2'.
*/
protected boolean isAssignableFrom(final Type type1, final Type type2) {
if (type1.equals(type2)) {
return true;
}
if (currentClass != null && currentClass.equals(type1)) {
if (getSuperClass(type2) == null) {
return false;
} else {
if (isInterface) {
return type2.getSort() == Type.OBJECT || type2.getSort() == Type.ARRAY;
}
return isAssignableFrom(type1, getSuperClass(type2));
}
}
if (currentClass != null && currentClass.equals(type2)) {
if (isAssignableFrom(type1, currentSuperClass)) {
return true;
}
if (currentClassInterfaces != null) {
for (Type currentClassInterface : currentClassInterfaces) {
if (isAssignableFrom(type1, currentClassInterface)) {
return true;
}
}
}
return false;
}
return getClass(type1).isAssignableFrom(getClass(type2));
}
static String getReturnAccessor(Type returnType) {
if (returnType.getSort() == Type.OBJECT || returnType.getSort() == Type.ARRAY) {
return "getReturnValue";
}
return String.format("getReturnValue%s", returnType.getDescriptor());
}
/**
* Generates the instruction to push the given value on the stack.
*
* @param value the value to be pushed on the stack.
*/
public void push(final Type value) {
if (value == null) {
mv.visitInsn(Opcodes.ACONST_NULL);
} else {
switch (value.getSort()) {
case Type.BOOLEAN:
mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Boolean", "TYPE", CLASS_DESCRIPTOR);
break;
case Type.CHAR:
mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Character", "TYPE", CLASS_DESCRIPTOR);
break;
case Type.BYTE:
mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Byte", "TYPE", CLASS_DESCRIPTOR);
break;
case Type.SHORT:
mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Short", "TYPE", CLASS_DESCRIPTOR);
break;
case Type.INT:
mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Integer", "TYPE", CLASS_DESCRIPTOR);
break;
case Type.FLOAT:
mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Float", "TYPE", CLASS_DESCRIPTOR);
break;
case Type.LONG:
mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Long", "TYPE", CLASS_DESCRIPTOR);
break;
case Type.DOUBLE:
mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Double", "TYPE", CLASS_DESCRIPTOR);
break;
default:
mv.visitLdcInsn(value);
break;
}
}
}
@Override
public boolean canCheckcast(JavaValue target, Type type, Context context) {
Type finalType = type;
while (finalType.getSort() == Type.ARRAY) {
finalType = finalType.getElementType();
}
if (finalType.getSort() != Type.OBJECT) {
throw new ExecutionException("Expected instanceof Object, but got " + finalType.getSort());
}
return dictionary.containsKey(finalType.getInternalName());
}
@Override
public void visitInvokeDynamicInsn(
final String name,
final String descriptor,
final Handle bootstrapMethodHandle,
final Object... bootstrapMethodArguments) {
stringBuilder.setLength(0);
stringBuilder.append(tab2).append("INVOKEDYNAMIC").append(' ');
stringBuilder.append(name);
appendDescriptor(METHOD_DESCRIPTOR, descriptor);
stringBuilder.append(" [");
stringBuilder.append('\n');
stringBuilder.append(tab3);
appendHandle(bootstrapMethodHandle);
stringBuilder.append('\n');
stringBuilder.append(tab3).append("// arguments:");
if (bootstrapMethodArguments.length == 0) {
stringBuilder.append(" none");
} else {
stringBuilder.append('\n');
for (Object value : bootstrapMethodArguments) {
stringBuilder.append(tab3);
if (value instanceof String) {
Printer.appendString(stringBuilder, (String) value);
} else if (value instanceof Type) {
Type type = (Type) value;
if (type.getSort() == Type.METHOD) {
appendDescriptor(METHOD_DESCRIPTOR, type.getDescriptor());
} else {
visitType(type);
}
} else if (value instanceof Handle) {
appendHandle((Handle) value);
} else {
stringBuilder.append(value);
}
stringBuilder.append(", \n");
}
stringBuilder.setLength(stringBuilder.length() - 3);
}
stringBuilder.append('\n');
stringBuilder.append(tab2).append("]\n");
text.add(stringBuilder.toString());
}
public static boolean isArray(Type type) {
return type.getSort() == Type.ARRAY;
}
private static String getPushMethod(Type type) {
return PUSH_METHOD + SUFFIXES[type.getSort()];
}
/**
* Checks to see if one type is assignable from another type. This method should be similar to
* {@link Class#isAssignableFrom(java.lang.Class) } (with some caveats, explained in next paragraph), but uses a
* {@link ClassInformationRepository} object rather than requiring classes to be loaded up in to the JVM.
* <p>
* Note that this code tries to mimic what ASM's original {@link org.objectweb.asm.tree.analysis.SimpleVerifier} does to find out
* if two types are equal. The main difference between SimpleVerifier's code and {@link Class#isAssignableFrom(java.lang.Class) } is
* that SimpleVerifier will treat any interface instance as if it were an {@link Object} instance. That means that, for example, an
* {@link Object} is assignable to a {@link Comparable} (Comparable = Object) in the eyes of ASM's SimpleVerifier. Why this is the case
* has never been explained.
* @param repo repository to use for deriving class details
* @param t type being assigned from
* @param u type being assigned to
* @return {@code true} if u is assignable to t ({@code t = u}), {@code false} otherwise
*/
public static boolean isAssignableFrom(ClassInformationRepository repo, Type t, Type u) {
Validate.notNull(repo);
Validate.notNull(t);
Validate.notNull(u);
if (t.equals(u)) {
return true;
}
if (t.getSort() == Type.OBJECT && u.getSort() == Type.OBJECT) {
// Both are objects, check hierarchy for both to see if assignable
// e.g. you're allowed to do Number = Integer
// e.g. you're allowed to do Serializable = Object, this seems counter-intuative but it is what ASM does
return isObjectTypeAssignableFrom(repo, t, u);
} else if (t.getSort() == Type.ARRAY && u.getSort() == Type.ARRAY) {
// Both are arrays
if (t.getDimensions() == u.getDimensions()) {
// If dimensions are equal...
Type tElem = t.getElementType();
Type uElem = u.getElementType();
if (tElem.getSort() == Type.OBJECT && uElem.getSort() == Type.OBJECT) {
// If dimensions are equal and both element types are objects, check hierarchy for both to see if assignable
// e.g. you're allowed to do Number[][] = Integer[][]
// e.g. you're allowed to do Object[][] = Integer[][]
// e.g. you're not allowed to do Serializable[][] = Object[][] because of false being passed in to method below...
// we only want to resolve interfaces to object if we aren't dealing with arrays (see first if block at top of this
// method)
return isArrayElementTypeAssignableFrom(repo, tElem, uElem);
} else if (tElem.getSort() != Type.OBJECT && uElem.getSort() != Type.OBJECT) {
// If dimensions are equal and both element types are primitives, check that both are equal to see if assignable
// e.g. you're allowed to do int[][] = int[][]
// e.g. you're not allowed to do int[][] = byte[][]
// e.g. you're not allowed to do byte[][] = int[][]
return tElem.equals(uElem);
} else {
// If dimensions are equal but you're dealing with one element type being an object and the other a primitive, always
// return false
// e.g. you're not allowed to do int[][] = Object[][]
// e.g. you're not allowed to do Object[][] = int[][]
return false;
}
} else if (t.getDimensions() > u.getDimensions()) {
// If t has MORE dimensions than u, it is not assignable
// e.g. you're not allowed to do Number[][] = Integer[]
// e.g. you're not allowed to do Object[][] = Integer[]
return false;
} else if (t.getDimensions() < u.getDimensions()) {
// If t has LESS dimensions than u, it is not assignable UNLESS t has an element type of Object
// e.g. you're allowed to do Object[][] = Number[][][]
// e.g. you're not allowed to do Number[][] = Integer[][][]
// e.g. you're not allowed to do Object[][] = Integer[][][]
return Type.getType(Object.class).equals(t.getElementType());
}
} else if (t.getSort() == Type.OBJECT && u.getSort() == Type.ARRAY) {
// Assigning an array to an object, only valid if the object is of type Object
// e.g. you're allowed to do Object = Integer[]
return Type.getType(Object.class).equals(t);
} else if (t.getSort() == Type.ARRAY && u.getSort() == Type.OBJECT) {
// Assigning an array to an object, never valid
// e.g. it doesn't make sense to do Integer[] = Object
return false;
}
// What about primitives?
return false;
}
private MethodNode methodGen() {
String randDesc = descGen();
MethodNode method = new MethodNode(ACC_STATIC + ACC_PRIVATE, randomString(), randDesc, null, null);
int instructions = RandomUtils.getRandomInt(30) + 30;
InsnList insns = new InsnList();
for (int i = 0; i < instructions; ++i)
insns.add(junkInstructions());
Type returnType = Type.getReturnType(randDesc);
switch (returnType.getSort()) {
case Type.VOID:
insns.add(new InsnNode(RETURN));
break;
case Type.BOOLEAN:
case Type.CHAR:
case Type.BYTE:
case Type.SHORT:
case Type.INT:
if (RandomUtils.getRandomInt(10) % 2 == 1)
insns.add(new InsnNode(ICONST_0));
else
insns.add(new InsnNode(ICONST_1));
insns.add(new InsnNode(IRETURN));
break;
case Type.FLOAT:
insns.add(ASMUtils.getNumberInsn(RandomUtils.getRandomFloat()));
insns.add(new InsnNode(FRETURN));
break;
case Type.LONG:
insns.add(ASMUtils.getNumberInsn(RandomUtils.getRandomLong()));
insns.add(new InsnNode(LRETURN));
break;
case Type.DOUBLE:
insns.add(ASMUtils.getNumberInsn(RandomUtils.getRandomDouble()));
insns.add(new InsnNode(DRETURN));
break;
default:
insns.add(new VarInsnNode(ALOAD, RandomUtils.getRandomInt(30)));
insns.add(new InsnNode(ARETURN));
break;
}
method.instructions = insns;
return method;
}
@Override
public BasicValue newValue(Type type) {
return type != null && (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) ? new BasicValue(type)
: super.newValue(type);
}