ASM 字节码框架源码解析

2019-04-16

2019-04-16  本文已影响0人  Xcdf
第一步:accept()接受一个ClassVisitor 实例对象
    classReader.accept(classAdapter, ClassReader.SKIP_DEBUG);
第二步:ClassReader.accpet()方法的调用1
accept() 方法中调用核心部分如下,使用了for循环处理所有的method
第二步:ClassReader.accpet()核心过程
第三步:ClassReader.readMethod()方法的调用
第三步:ClassReader.readMethod()核心逻辑
ClassReader调用accept()方法接受一个ClassVisitor类型的对象。

我们深入到accept()方法中

    public void accept(ClassVisitor classVisitor, Attribute[] attributePrototypes, int parsingOptions) {
        Context context = new Context();
        context.attributePrototypes = attributePrototypes;
        context.parsingOptions = parsingOptions;
        context.charBuffer = new char[this.maxStringLength];
        char[] charBuffer = context.charBuffer;
        int currentOffset = this.header;
        int accessFlags = this.readUnsignedShort(currentOffset);
        String thisClass = this.readClass(currentOffset + 2, charBuffer);
        String superClass = this.readClass(currentOffset + 4, charBuffer);
        String[] interfaces = new String[this.readUnsignedShort(currentOffset + 6)];
        currentOffset += 8;
      // for 循环中读取所有的innerClasse
        int innerClassesOffset;
        for(innerClassesOffset = 0; innerClassesOffset < interfaces.length; ++innerClassesOffset) {
            interfaces[innerClassesOffset] = this.readClass(currentOffset, charBuffer);
            currentOffset += 2;
        }

        innerClassesOffset = 0;
        int enclosingMethodOffset = 0;
        String signature = null;
        String sourceFile = null;
        String sourceDebugExtension = null;
        int runtimeVisibleAnnotationsOffset = 0;
        int runtimeInvisibleAnnotationsOffset = 0;
        int runtimeVisibleTypeAnnotationsOffset = 0;
        int runtimeInvisibleTypeAnnotationsOffset = 0;
        int moduleOffset = 0;
        int modulePackagesOffset = 0;
        String moduleMainClass = null;
        String nestHostClass = null;
        int nestMembersOffset = 0;
        Attribute attributes = null;
        int currentAttributeOffset = this.getFirstAttributeOffset();

        int fieldsCount;
        for(fieldsCount = this.readUnsignedShort(currentAttributeOffset - 2); fieldsCount > 0; --fieldsCount) {
            String attributeName = this.readUTF8(currentAttributeOffset, charBuffer);
            int attributeLength = this.readInt(currentAttributeOffset + 2);
            currentAttributeOffset += 6;
            if ("SourceFile".equals(attributeName)) {
                sourceFile = this.readUTF8(currentAttributeOffset, charBuffer);
            } else if ("InnerClasses".equals(attributeName)) {
                innerClassesOffset = currentAttributeOffset;
            } else if ("EnclosingMethod".equals(attributeName)) {
                enclosingMethodOffset = currentAttributeOffset;
            } else if ("NestHost".equals(attributeName)) {
                nestHostClass = this.readClass(currentAttributeOffset, charBuffer);
            } else if ("NestMembers".equals(attributeName)) {
                nestMembersOffset = currentAttributeOffset;
            } else if ("Signature".equals(attributeName)) {
                signature = this.readUTF8(currentAttributeOffset, charBuffer);
            } else if ("RuntimeVisibleAnnotations".equals(attributeName)) {
                runtimeVisibleAnnotationsOffset = currentAttributeOffset;
            } else if ("RuntimeVisibleTypeAnnotations".equals(attributeName)) {
                runtimeVisibleTypeAnnotationsOffset = currentAttributeOffset;
            } else if ("Deprecated".equals(attributeName)) {
                accessFlags |= 131072;
            } else if ("Synthetic".equals(attributeName)) {
                accessFlags |= 4096;
            } else if ("SourceDebugExtension".equals(attributeName)) {
                sourceDebugExtension = this.readUtf(currentAttributeOffset, attributeLength, new char[attributeLength]);
            } else if ("RuntimeInvisibleAnnotations".equals(attributeName)) {
                runtimeInvisibleAnnotationsOffset = currentAttributeOffset;
            } else if ("RuntimeInvisibleTypeAnnotations".equals(attributeName)) {
                runtimeInvisibleTypeAnnotationsOffset = currentAttributeOffset;
            } else if ("Module".equals(attributeName)) {
                moduleOffset = currentAttributeOffset;
            } else if ("ModuleMainClass".equals(attributeName)) {
                moduleMainClass = this.readClass(currentAttributeOffset, charBuffer);
            } else if ("ModulePackages".equals(attributeName)) {
                modulePackagesOffset = currentAttributeOffset;
            } else if (!"BootstrapMethods".equals(attributeName)) {
                Attribute attribute = this.readAttribute(attributePrototypes, attributeName, currentAttributeOffset, attributeLength, charBuffer, -1, (Label[])null);
                attribute.nextAttribute = attributes;
                attributes = attribute;
            }

            currentAttributeOffset += attributeLength;
        }
       // classVisitor.visit()
        classVisitor.visit(this.readInt(this.cpInfoOffsets[1] - 7), accessFlags, thisClass, signature, superClass, interfaces);
       // classVisitor.visitSource
        if ((parsingOptions & 2) == 0 && (sourceFile != null || sourceDebugExtension != null)) {
            classVisitor.visitSource(sourceFile, sourceDebugExtension);
        }

        if (moduleOffset != 0) {
            this.readModuleAttributes(classVisitor, context, moduleOffset, modulePackagesOffset, moduleMainClass);
        }
       // classVisitor.visitNestHost
        if (nestHostClass != null) {
            classVisitor.visitNestHost(nestHostClass);
        }
       // classVisitor.visitOuterClass
        int methodsCount;
        String annotationDescriptor;
        if (enclosingMethodOffset != 0) {
            String className = this.readClass(enclosingMethodOffset, charBuffer);
            methodsCount = this.readUnsignedShort(enclosingMethodOffset + 2);
            annotationDescriptor = methodsCount == 0 ? null : this.readUTF8(this.cpInfoOffsets[methodsCount], charBuffer);
            String type = methodsCount == 0 ? null : this.readUTF8(this.cpInfoOffsets[methodsCount] + 2, charBuffer);
            classVisitor.visitOuterClass(className, annotationDescriptor, type);
        }

        if (runtimeVisibleAnnotationsOffset != 0) {
            fieldsCount = this.readUnsignedShort(runtimeVisibleAnnotationsOffset);

            for(methodsCount = runtimeVisibleAnnotationsOffset + 2; fieldsCount-- > 0; methodsCount = this.readElementValues(classVisitor.visitAnnotation(annotationDescriptor, true), methodsCount, true, charBuffer)) {
                annotationDescriptor = this.readUTF8(methodsCount, charBuffer);
                methodsCount += 2;
            }
        }

        if (runtimeInvisibleAnnotationsOffset != 0) {
            fieldsCount = this.readUnsignedShort(runtimeInvisibleAnnotationsOffset);

            for(methodsCount = runtimeInvisibleAnnotationsOffset + 2; fieldsCount-- > 0; methodsCount = this.readElementValues(classVisitor.visitAnnotation(annotationDescriptor, false), methodsCount, true, charBuffer)) {
                annotationDescriptor = this.readUTF8(methodsCount, charBuffer);
                methodsCount += 2;
            }
        }

        if (runtimeVisibleTypeAnnotationsOffset != 0) {
            fieldsCount = this.readUnsignedShort(runtimeVisibleTypeAnnotationsOffset);

            for(methodsCount = runtimeVisibleTypeAnnotationsOffset + 2; fieldsCount-- > 0; methodsCount = this.readElementValues(classVisitor.visitTypeAnnotation(context.currentTypeAnnotationTarget, context.currentTypeAnnotationTargetPath, annotationDescriptor, true), methodsCount, true, charBuffer)) {
                methodsCount = this.readTypeAnnotationTarget(context, methodsCount);
                annotationDescriptor = this.readUTF8(methodsCount, charBuffer);
                methodsCount += 2;
            }
        }

        if (runtimeInvisibleTypeAnnotationsOffset != 0) {
            fieldsCount = this.readUnsignedShort(runtimeInvisibleTypeAnnotationsOffset);

            for(methodsCount = runtimeInvisibleTypeAnnotationsOffset + 2; fieldsCount-- > 0; methodsCount = this.readElementValues(classVisitor.visitTypeAnnotation(context.currentTypeAnnotationTarget, context.currentTypeAnnotationTargetPath, annotationDescriptor, false), methodsCount, true, charBuffer)) {
                methodsCount = this.readTypeAnnotationTarget(context, methodsCount);
                annotationDescriptor = this.readUTF8(methodsCount, charBuffer);
                methodsCount += 2;
            }
        }
     // classVisitor.visitAttribute
        while(attributes != null) {
            Attribute nextAttribute = attributes.nextAttribute;
            attributes.nextAttribute = null;
            classVisitor.visitAttribute(attributes);
            attributes = nextAttribute;
        }
      // classVisitor.visitNestMember
        if (nestMembersOffset != 0) {
            fieldsCount = this.readUnsignedShort(nestMembersOffset);

            for(methodsCount = nestMembersOffset + 2; fieldsCount-- > 0; methodsCount += 2) {
                classVisitor.visitNestMember(this.readClass(methodsCount, charBuffer));
            }
        }
      // classVisitor.visitInnerClass
        if (innerClassesOffset != 0) {
            fieldsCount = this.readUnsignedShort(innerClassesOffset);

            for(methodsCount = innerClassesOffset + 2; fieldsCount-- > 0; methodsCount += 8) {
                classVisitor.visitInnerClass(this.readClass(methodsCount, charBuffer), this.readClass(methodsCount + 2, charBuffer), this.readUTF8(methodsCount + 4, charBuffer), this.readUnsignedShort(methodsCount + 6));
            }
        }

        fieldsCount = this.readUnsignedShort(currentOffset);
       // this.readField(classVisitor)
        for(currentOffset += 2; fieldsCount-- > 0; currentOffset = this.readField(classVisitor, context, currentOffset)) {
            ;
        }

        methodsCount = this.readUnsignedShort(currentOffset);
       // this.readMethod(classVisitor)
        for(currentOffset += 2; methodsCount-- > 0; currentOffset = this.readMethod(classVisitor, context, currentOffset)) {
            ;
        }
       // visitEnd()
        classVisitor.visitEnd();
    }

那么我们的逻辑(NameMethodVisitor)到底在哪里被执行到了?

    // 定义一个自己的方法访问类
    public static class NameMethodVisitor extends MethodVisitor {

        public NameMethodVisitor(MethodVisitor mv) {
            super(Opcodes.ASM7, mv);  //???
        }

        public NameMethodVisitor(int api) {
            super(api);
        }

        public NameMethodVisitor(int api, MethodVisitor methodVisitor) {
            super(api, methodVisitor);
        }

        // 在源方法前去修改方法内容,这部分的修改将加载源方法的字节码之前
        @Override
        public void visitCode() {
            mv.visitVarInsn(Opcodes.ALOAD, 0);
            mv.visitLdcInsn("yy");
            mv.visitFieldInsn(Opcodes.PUTFIELD, "asm5/Person", "name", "Ljava/lang/String;");
        }
    }
image.png

让我们再看看visitoCode()是如何执行的。

image.png

visitMethod() 访问了init()方法(即构造方法)


上一篇下一篇

猜你喜欢

热点阅读