本文属于Java ASM系列三:Tree API当中的一篇。

在本章内容当中,最核心的内容就是下面两行代码。这两行代码包含了asm-analysis.jar当中AnalyzerFrameInterpreterValue最重要的四个类:

   ┌── Analyzer
   │        ┌── Value                                   ┌── Interpreter
   │        │                                           │
Analyzer<BasicValue> analyzer = new Analyzer<>(new SimpleVerifier());
Frame<BasicValue>[] frames = analyzer.analyze(owner, mn);
   │        │
   │        └── Value
   └── Frame

在本文当中,我们将介绍SimpleVerifier类:

┌───┬───────────────────┬─────────────┬───────┐
│ 0 │    Interpreter    │    Value    │ Range │
├───┼───────────────────┼─────────────┼───────┤
│ 1 │ BasicInterpreter  │ BasicValue  │   7   │
├───┼───────────────────┼─────────────┼───────┤
│ 2 │   BasicVerifier   │ BasicValue  │   7   │
├───┼───────────────────┼─────────────┼───────┤
│ 3 │  SimpleVerifier   │ BasicValue  │   N   │
├───┼───────────────────┼─────────────┼───────┤
│ 4 │ SourceInterpreter │ SourceValue │   N   │
└───┴───────────────────┴─────────────┴───────┘

在上面这个表当中,我们关注以下三点:

  • 第一点,类的继承关系。SimpleVerifier类继承自BasicVerifier类,BasicVerifier类继承自BasicInterpreter类,而BasicInterpreter类继承自Interpreter抽象类。
  • 第二点,类的合作关系。SimpleVerifierBasicValue类是一起使用的。
  • 第三点,类的表达能力。SimpleVerifier类能够使用的BasicValue对象有很多个。因为SimpleVerifier类重新实现了newValue()方法。每个类都有自己的表示形式。

The SimpleVerifier class extends the BasicVerifier class.
It uses more sets to simulate the execution of bytecode instructions:
indeed each class is represented by its own set, representing all possible objects of this class.

This class uses the Java reflection API
in order to perform verifications and computations related to the class hierarchy.
It therefore loads the classes referenced by a method into the JVM.
This default behavior can be changed by overriding the protected methods of this class.

1. SimpleVerifier

理解SimpleVerifier类,从两个方面来把握:

  • 第一点,SimpleVerifier类可以模拟的Value值有多少个?为什么关注这个问题呢?因为这些Value值会存储在Frame内,它体现了Frame的表达能力。
  • 第二点,SimpleVerifier类如何实现验证(Verify)的功能?

1.1. class info

第一个部分,SimpleVerifier类继承自BasicVerifier类。

public class SimpleVerifier extends BasicVerifier {
}

1.2. fields

第二个部分,SimpleVerifier类定义的字段有哪些。

public class SimpleVerifier extends BasicVerifier {
    // 第一组字段,当前类、父类、接口
    private Type currentClass;
    private Type currentSuperClass;
    private List<Type> currentClassInterfaces;
    private boolean isInterface;

    // 第二组字段,ClassLoader
    private ClassLoader loader = getClass().getClassLoader();
}

第一组字段,是记录当前类的相关信息。同时,我们也要注意到Analyzer.analyze(owner, mn)方法只提供了当前类的名字(owner),提供的类相关信息太少;而SimpleVerifier这个类记录了当前类、父类、接口和当前类是不是接口的信息。

   ┌── Analyzer
   │        ┌── Value                                   ┌── Interpreter
   │        │                                           │
Analyzer<BasicValue> analyzer = new Analyzer<>(new BasicInterpreter());
Frame<BasicValue>[] frames = analyzer.analyze(owner, mn);
   │        │                                   │
   │        └── Value                           └── 只提供了当前类的名字信息
   └── Frame

第二组字段,loader字段通过反射的方式将某个类加载进来,从而进一步判断类的继承关系。另外,SimpleVerifier也提供了一个setter方法来设置loader字段的值。

public class SimpleVerifier extends BasicVerifier {
    public void setClassLoader(ClassLoader loader) {
        this.loader = loader;
    }    
}

1.3. constructors

第三个部分,SimpleVerifier类定义的构造方法有哪些。

注意,前三个构造方法都不适合由子类继承,因为它会判断getClass() != SimpleVerifier.class是否成立;如果是子类实现,就会抛出IllegalStateException类型的异常。

public class SimpleVerifier extends BasicVerifier {
    public SimpleVerifier() {
        this(null, null, false);
    }

    public SimpleVerifier(Type currentClass, Type currentSuperClass, boolean isInterface) {
        this(currentClass, currentSuperClass, null, isInterface);
    }

    public SimpleVerifier(Type currentClass, Type currentSuperClass, List<Type> currentClassInterfaces, boolean isInterface) {
        this(ASM9, currentClass, currentSuperClass, currentClassInterfaces, isInterface);
        if (getClass() != SimpleVerifier.class) {
            throw new IllegalStateException();
        }
    }

    protected SimpleVerifier(int api, Type currentClass, Type currentSuperClass, List<Type> currentClassInterfaces, boolean isInterface) {
        super(api);
        this.currentClass = currentClass;
        this.currentSuperClass = currentSuperClass;
        this.currentClassInterfaces = currentClassInterfaces;
        this.isInterface = isInterface;
    }
}

1.4. methods

第四个部分,SimpleVerifier类定义的方法有哪些。

1.4.1. Interpreter.newValue方法

这个newValue方法原本是在Interpreter类里定义的。

在下面的表当中,我们可以看到:

  • BasicInterpreterBasicVerifier类当中,可以使用的BasicValue值有7个。
  • SimpleVerifier类当中,可以使用的BasicValue值有N个。
┌───┬───────────────────┬─────────────┬───────┐
│ 0 │    Interpreter    │    Value    │ Range │
├───┼───────────────────┼─────────────┼───────┤
│ 1 │ BasicInterpreter  │ BasicValue  │   7   │
├───┼───────────────────┼─────────────┼───────┤
│ 2 │   BasicVerifier   │ BasicValue  │   7   │
├───┼───────────────────┼─────────────┼───────┤
│ 3 │  SimpleVerifier   │ BasicValue  │   N   │
├───┼───────────────────┼─────────────┼───────┤
│ 4 │ SourceInterpreter │ SourceValue │   N   │
└───┴───────────────────┴─────────────┴───────┘

那么,为什么SimpleVerifier类可以使用更多的BasicValue值呢?原因就在于newValue方法。我们从两点来把握:

  • 第一点,在SimpleVerifier类当中,newValue方法使用new BasicValue(Type)创建新的对象,因此使得BasicValue值多样化,每个不同的类都有一个对应的BasicValue值。
  • 第二点,在SimpleVerifier类当中,new BasicValue(Type)的调用只在newValue方法中发生,不会在其它方法中调用。也就是说,创建新的BasicValue值,只会在newValue方法发生。
public class SimpleVerifier extends BasicVerifier {
    @Override
    public BasicValue newValue(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);
                default:
                    break;
            }
        }

        BasicValue value = super.newValue(type);
        if (BasicValue.REFERENCE_VALUE.equals(value)) {
            if (isArray) {
                value = newValue(type.getElementType());
                StringBuilder descriptor = new StringBuilder();
                for (int i = 0; i < type.getDimensions(); ++i) {
                    descriptor.append('[');
                }
                descriptor.append(value.getType().getDescriptor());
                value = new BasicValue(Type.getType(descriptor.toString()));
            } else {
                value = new BasicValue(type);
            }
        }
        return value;
    }
}

1.4.2. Interpreter.merge方法

其实,newValuemerge方法都是Interpreter类所定义的方法。

  • Interpreter类当中,merge方法是一个抽象方法。
  • BasicInterpreter类当中,为merge方法提供了一个简单实现。
  • BasicVerifier类当中,继承了BasicInterpreter类的merge方法没有做任何改变。
  • SimpleVerifier类当中,对merge方法的代码逻辑进行了重新编写。

BasicInterpreterBasicVerifier类当中,只使用7个BasicValue值,因此merge方法实现起来很简单。然而,在SimpleVerifier类当中,可以使用N个BasicValue值;也就是说,每个类型都有一个对应的BasicValue值,那么相应的merge操作就变得复杂起来了。

public class SimpleVerifier extends BasicVerifier {
    @Override
    public BasicValue merge(BasicValue value1, BasicValue value2) {
        if (!value1.equals(value2)) {
            Type type1 = value1.getType();
            Type type2 = value2.getType();
            if (type1 != null
                    && (type1.getSort() == Type.OBJECT || type1.getSort() == Type.ARRAY)
                    && type2 != null
                    && (type2.getSort() == Type.OBJECT || type2.getSort() == Type.ARRAY)) {
                if (type1.equals(NULL_TYPE)) {
                    return value2;
                }
                if (type2.equals(NULL_TYPE)) {
                    return value1;
                }
                if (isAssignableFrom(type1, type2)) {
                    return value1;
                }
                if (isAssignableFrom(type2, type1)) {
                    return value2;
                }
                int numDimensions = 0;
                if (type1.getSort() == Type.ARRAY
                        && type2.getSort() == Type.ARRAY
                        && type1.getDimensions() == type2.getDimensions()
                        && type1.getElementType().getSort() == Type.OBJECT
                        && type2.getElementType().getSort() == Type.OBJECT) {
                    numDimensions = type1.getDimensions();
                    type1 = type1.getElementType();
                    type2 = type2.getElementType();
                }
                while (true) {
                    if (type1 == null || isInterface(type1)) {
                        return newArrayValue(Type.getObjectType("java/lang/Object"), numDimensions);
                    }
                    type1 = getSuperClass(type1);
                    if (isAssignableFrom(type1, type2)) {
                        return newArrayValue(type1, numDimensions);
                    }
                }
            }
            return BasicValue.UNINITIALIZED_VALUE;
        }
        return value1;
    }    
}

1.4.3. BasicVerifier方法

下面几个方法是从BasicVerifier继承来的方法

public class SimpleVerifier extends BasicVerifier {
    @Override
    protected boolean isArrayValue(BasicValue value) {
        Type type = value.getType();
        return type != null && (type.getSort() == Type.ARRAY || type.equals(NULL_TYPE));
    }

    @Override
    protected BasicValue getElementValue(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();
    }

    @Override
    protected boolean isSubTypeOf(BasicValue value, 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 (type.equals(NULL_TYPE)) {
                    return true;
                } else if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) {
                    if (isAssignableFrom(expectedType, type)) {
                        return true;
                    } else if (getClass(expectedType).isInterface()) {
                        // The merge of class or interface types can only yield class types (because it is not
                        // possible in general to find an unambiguous common super interface, due to multiple
                        // inheritance). Because of this limitation, we need to relax the subtyping check here
                        // if 'value' is an interface.
                        return Object.class.isAssignableFrom(getClass(type));
                    } else {
                        return false;
                    }
                } else {
                    return false;
                }
            default:
                throw new AssertionError();
        }
    }
}

1.4.4. protected方法

下面几个方法是SimpleVerifier自定义的protected方法:

  • isAssignableFrom方法:判断两个Type之间是否兼容。
  • isInterface方法:判断某个Type是否为接口。
  • getSuperClass方法:获取某个Type的父类型。
  • getClass方法:通过反射的方式加载某个Type类型,是loader字段发挥作用的地方。另外,isAssignableFromisInterfacegetSuperClass方法都会调用getClass方法。
public class SimpleVerifier extends BasicVerifier {
    protected boolean isAssignableFrom(Type type1, 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));
    }

    protected boolean isInterface(Type type) {
        if (currentClass != null && currentClass.equals(type)) {
            return isInterface;
        }
        return getClass(type).isInterface();
    }

    protected Type getSuperClass(Type type) {
        if (currentClass != null && currentClass.equals(type)) {
            return currentSuperClass;
        }
        Class<?> superClass = getClass(type).getSuperclass();
        return superClass == null ? null : Type.getType(superClass);
    }

    protected Class<?> getClass(Type type) {
        try {
            if (type.getSort() == Type.ARRAY) {
                return Class.forName(type.getDescriptor().replace('/', '.'), false, loader);
            }
            return Class.forName(type.getClassName(), false, loader);
        } catch (ClassNotFoundException e) {
            throw new TypeNotPresentException(e.toString(), e);
        }
    }    
}

2. SimpleVerifier的表达能力

2.1. primitive type无法区分

SimpleVerifier的表达能力可以描述成这样:

  • 可以区分不同的引用类型(Reference Type),例如StringObject类型
  • 可以区分同一个引用类型的不同对象实例,例如"AAA"和"BBB"是String类型的不同对象实例
  • 但是,不能够区分同一种primitive type的不同值

例如,下面的HelloWorld类当中,str1str2这两个变量是String类型,它们分别使用不同的BasicValue对象来表示;相应的,ab都是int类型(primitive type),它们分别是12两个值,但是它们都是用BasicValue.INT_VALUE来表示,没有办法进行区分。

public class HelloWorld {
    public void test() {
        int a = 1;
        int b = 2;
        String str1 = "AAA";
        String str2 = "BBB";
    }
}

2.2. 如何验证

为了验证上面的内容是否正确,我们可以使用HelloWorldFrameTree类查看frame当中存储的数据:看一看int类型的ab能不能区分,看一个String类型的str1str2能不能区分开?

第一次尝试(错误示例,不能区分):

print(owner, mn, new SimpleVerifier(), null);

输出结果:ab都用I表示,str1str2都用Ljava/lang/String;,看不出str1str2有什么区别

test:()V
000:    iconst_1                                {Lsample/HelloWorld;, ., ., ., .} | {}
001:    istore_1                                {Lsample/HelloWorld;, ., ., ., .} | {I}
002:    iconst_2                                {Lsample/HelloWorld;, I, ., ., .} | {}
003:    istore_2                                {Lsample/HelloWorld;, I, ., ., .} | {I}
004:    ldc "AAA"                               {Lsample/HelloWorld;, I, I, ., .} | {}
005:    astore_3                                {Lsample/HelloWorld;, I, I, ., .} | {Ljava/lang/String;}
006:    ldc "BBB"                               {Lsample/HelloWorld;, I, I, Ljava/lang/String;, .} | {}
007:    astore 4                                {Lsample/HelloWorld;, I, I, Ljava/lang/String;, .} | {Ljava/lang/String;}
008:    return                                  {Lsample/HelloWorld;, I, I, Ljava/lang/String;, Ljava/lang/String;} | {}
================================================================

第二次尝试(错误示例,不能区分):

print(owner, mn, new SimpleVerifier(), item -> item.toString() + "@" + item.hashCode());

输出结果:ab都用I@65表示,str1str2都用Ljava/lang/String;@-689322901,看不出str1str2有什么区别

test:()V
000:    iconst_1                                {Lsample/HelloWorld;@1649535039, .@0, .@0, .@0, .@0} | {}
001:    istore_1                                {Lsample/HelloWorld;@1649535039, .@0, .@0, .@0, .@0} | {I@65}
002:    iconst_2                                {Lsample/HelloWorld;@1649535039, I@65, .@0, .@0, .@0} | {}
003:    istore_2                                {Lsample/HelloWorld;@1649535039, I@65, .@0, .@0, .@0} | {I@65}
004:    ldc "AAA"                               {Lsample/HelloWorld;@1649535039, I@65, I@65, .@0, .@0} | {}
005:    astore_3                                {Lsample/HelloWorld;@1649535039, I@65, I@65, .@0, .@0} | {Ljava/lang/String;@-689322901}
006:    ldc "BBB"                               {Lsample/HelloWorld;@1649535039, I@65, I@65, Ljava/lang/String;@-689322901, .@0} | {}
007:    astore 4                                {Lsample/HelloWorld;@1649535039, I@65, I@65, Ljava/lang/String;@-689322901, .@0} | {Ljava/lang/String;@-689322901}
008:    return                                  {Lsample/HelloWorld;@1649535039, I@65, I@65, Ljava/lang/String;@-689322901, Ljava/lang/String;@-689322901} | {}
================================================================

那么,为什么第二次尝试是错误的呢?是因为BasicValue.hashCode()是经过修改的,它会进一步调用Type.hashCode();而Type.hashCode()会根据descritor来计算hash值,只要descriptor相同,那么hash值就相同。

第三次尝试(正确示例,能够区分):借助于System.identityHashCode()方法

print(owner, mn, new SimpleVerifier(), item -> item.toString() + "@" + System.identityHashCode(item));

输出结果:ab都用I@1267032364表示,str1Ljava/lang/String;@661672156表示,str2都用Ljava/lang/String;@96639997,可以看出str1str2是不同的对象。

test:()V
000:    iconst_1                                {Lsample/HelloWorld;@1147985808, .@2040495657, .@2040495657, .@2040495657, .@2040495657} | {}
001:    istore_1                                {Lsample/HelloWorld;@1147985808, .@2040495657, .@2040495657, .@2040495657, .@2040495657} | {I@1267032364}
002:    iconst_2                                {Lsample/HelloWorld;@1147985808, I@1267032364, .@2040495657, .@2040495657, .@2040495657} | {}
003:    istore_2                                {Lsample/HelloWorld;@1147985808, I@1267032364, .@2040495657, .@2040495657, .@2040495657} | {I@1267032364}
004:    ldc "AAA"                               {Lsample/HelloWorld;@1147985808, I@1267032364, I@1267032364, .@2040495657, .@2040495657} | {}
005:    astore_3                                {Lsample/HelloWorld;@1147985808, I@1267032364, I@1267032364, .@2040495657, .@2040495657} | {Ljava/lang/String;@661672156}
006:    ldc "BBB"                               {Lsample/HelloWorld;@1147985808, I@1267032364, I@1267032364, Ljava/lang/String;@661672156, .@2040495657} | {}
007:    astore 4                                {Lsample/HelloWorld;@1147985808, I@1267032364, I@1267032364, Ljava/lang/String;@661672156, .@2040495657} | {Ljava/lang/String;@96639997}
008:    return                                  {Lsample/HelloWorld;@1147985808, I@1267032364, I@1267032364, Ljava/lang/String;@661672156, Ljava/lang/String;@96639997} | {}
================================================================

那么,我们为什么要将三次尝试都记录下来呢?因为大家在自己尝试的过程当中,可能也会想去确定local variable和operand stack上的某两个位置的值到底是不是同一个元素呢?如果说具体的Value值修改过hashCode()方法,那么可能就检测不出来。为了正确的检测两个位置的值是不是同一个对象,我们可以借助于System.identityHashCode()方法

3. 总结

本文内容总结如下:

  • 第一点,介绍SimpleVerifier类的各个部分。
  • 第二点,理解SimpleVerifier类的表达能力。