接上面,我们继续分析doTranslate的下一部分
private void doTranslate(final Path dist) throws IOException {这里定义了一个ClassVisitorFactory cvf,主要是实现了ClassVisitorFactory的create方法,创建一个ClassVisitor,ClassVisitor的构造函数里面又new了一个ClassWriter,并实现了visitEnd方法
DexFileNode fileNode = new DexFileNode();//创建一个DexFileNode的访问者
try {
reader.accept(fileNode, readerConfig | DexFileReader.IGNORE_READ_EXCEPTION);
} catch (Exception ex) {
exceptionHandler.handleFileException(ex);
}
ClassVisitorFactory cvf = new ClassVisitorFactory() {
@Override
public ClassVisitor create(final String name) {
return new ClassVisitor(Opcodes.ASM4, new ClassWriter(ClassWriter.COMPUTE_MAXS)) {
@Override
public void visitEnd() {
super.visitEnd();
ClassWriter cw = (ClassWriter) super.cv;
byte[] data;
try {
// FIXME handle 'java.lang.RuntimeException: Method code too large!'
data = cw.toByteArray();
} catch (Exception ex) {
System.err.println(String.format("ASM fail to generate .class file: %s", name));
exceptionHandler.handleFileException(ex);
return;
}
try {
Path dist1 = dist.resolve(name + ".class");
Path parent = dist1.getParent();
if (parent != null && !Files.exists(parent)) {
Files.createDirectories(parent);
}
Files.write(dist1, data);
} catch (IOException e) {
e.printStackTrace(System.err);
}
}
};
}
};
new ExDex2Asm(exceptionHandler) {
public void convertCode(DexMethodNode methodNode, MethodVisitor mv) {
if ((readerConfig & DexFileReader.SKIP_CODE) != 0 && methodNode.method.getName().equals("<clinit>")) {
// also skip clinit
return;
}
super.convertCode(methodNode, mv);
}
@Override
public void optimize(IrMethod irMethod) {
T_cleanLabel.transform(irMethod);
if (0 != (v3Config & V3.TOPOLOGICAL_SORT)) {
// T_topologicalSort.transform(irMethod);
}
T_deadCode.transform(irMethod);
T_removeLocal.transform(irMethod);
T_removeConst.transform(irMethod);
T_zero.transform(irMethod);
if (T_npe.transformReportChanged(irMethod)) {
T_deadCode.transform(irMethod);
T_removeLocal.transform(irMethod);
T_removeConst.transform(irMethod);
}
T_new.transform(irMethod);
T_fillArray.transform(irMethod);
T_agg.transform(irMethod);
T_multiArray.transform(irMethod);
T_voidInvoke.transform(irMethod);
if (0 != (v3Config & V3.PRINT_IR)) {
int i = 0;
for (Stmt p : irMethod.stmts) {
if (p.st == Stmt.ST.LABEL) {
LabelStmt labelStmt = (LabelStmt) p;
labelStmt.displayName = "L" + i++;
}
}
System.out.println(irMethod);
}
T_type.transform(irMethod);
T_unssa.transform(irMethod);
T_ir2jRegAssign.transform(irMethod);
T_trimEx.transform(irMethod);
}
@Override
public void ir2j(IrMethod irMethod, MethodVisitor mv) {
new IR2JConverter(0 != (V3.OPTIMIZE_SYNCHRONIZED & v3Config)).convert(irMethod, mv);
}
}.convertDex(fileNode, cvf);
}
然后定义了一个ExDex2Asm,他继承于Dex2Asm,主要重写了convertCode和optimize、ir2j方法
调用convertDex方法
public void convertDex(DexFileNode fileNode, ClassVisitorFactory cvf) { if (fileNode.clzs != null) { Map<String, Clz> classes = collectClzInfo(fileNode); for (DexClassNode classNode : fileNode.clzs) { convertClass(classNode, cvf, classes); } } }
主要是对dex里面的class调用convertClass
public void convertClass(DexClassNode classNode, ClassVisitorFactory cvf, Map<String, Clz> classes) { ClassVisitor cv = cvf.create(toInternalName(classNode.className)); if (cv == null) { return; } // the default value of static-final field are omitted by dex, fix it DexFix.fixStaticFinalFieldValue(classNode);//默认static-final 字段的值被dex忽略,这里修正 String signature = null; if (classNode.anns != null) {//是否有注解 for (DexAnnotationNode ann : classNode.anns) { if (ann.visibility == Visibility.SYSTEM) { switch (ann.type) { case DexConstants.ANNOTATION_SIGNATURE_TYPE: { Object[] strs = (Object[]) findAnnotationAttribute(ann, "value"); if (strs != null) { StringBuilder sb = new StringBuilder(); for (Object str : strs) { sb.append(str); } signature = sb.toString(); } } break; } } } } String interfaceInterNames[] = null; if (classNode.interfaceNames != null) {//接口处理 interfaceInterNames = new String[classNode.interfaceNames.length]; for (int i = 0; i < classNode.interfaceNames.length; i++) { interfaceInterNames[i] = toInternalName(classNode.interfaceNames[i]); } } Clz clzInfo = classes.get(classNode.className); int access = classNode.access; boolean isInnerClass = false; if (clzInfo != null) { isInnerClass = clzInfo.enclosingClass != null || clzInfo.enclosingMethod != null; } access = clearClassAccess(isInnerClass, access);//清除一些类的标志 cv.visit(Opcodes.V1_6, access, toInternalName(classNode.className), signature,//访问类 把类名 接口名添加到常量池 classNode.superClass == null ? null : toInternalName(classNode.superClass), interfaceInterNames); List<InnerClassNode> innerClassNodes = new ArrayList<InnerClassNode>(5); if (clzInfo != null) { searchInnerClass(clzInfo, innerClassNodes, classNode.className); } if (isInnerClass) {//是不是内部类 // build Outer Clz if (clzInfo.innerName == null) {// anonymous Innerclass Method enclosingMethod = clzInfo.enclosingMethod; if (enclosingMethod != null) { cv.visitOuterClass(toInternalName(enclosingMethod.getOwner()), enclosingMethod.getName(), enclosingMethod.getDesc()); } else { Clz enclosingClass = clzInfo.enclosingClass; cv.visitOuterClass(toInternalName(enclosingClass.name), null, null); } } searchEnclosing(clzInfo, innerClassNodes); } Collections.sort(innerClassNodes, INNER_CLASS_NODE_COMPARATOR); for (InnerClassNode icn : innerClassNodes) { if (icn.innerName != null && !isJavaIdentifier(icn.innerName)) { System.err.println("WARN: ignored invalid inner class name " + ", treat as anonymous inner class."); icn.innerName = null; icn.outerName = null; } icn.accept(cv); } accept(classNode.anns, cv); if (classNode.fields != null) { for (DexFieldNode fieldNode : classNode.fields) { convertField(classNode, fieldNode, cv); } } if (classNode.methods != null) { for (DexMethodNode methodNode : classNode.methods) { convertMethod(classNode, methodNode, cv); } } cv.visitEnd(); }
这个函数比较长,主要做了如下工作:
1、调用 cvf.create创建一个ClassVisitor,ClassVisitorFactory是我们前面定义的
2、处理注解,接口,清除一些类标志
3、调用ClassVisitor 的visit
4、convertField访问字段
5、convertMethod访问方法
先看ClassVisitor的创建
public ClassVisitor create(final String name) { return new ClassVisitor(Opcodes.ASM4, new ClassWriter(ClassWriter.COMPUTE_MAXS)) { @Override public void visitEnd() { super.visitEnd(); ClassWriter cw = (ClassWriter) super.cv; byte[] data; try { // FIXME handle 'java.lang.RuntimeException: Method code too large!' data = cw.toByteArray(); } catch (Exception ex) { System.err.println(String.format("ASM fail to generate .class file: %s", name)); exceptionHandler.handleFileException(ex); return; } try { Path dist1 = dist.resolve(name + ".class"); Path parent = dist1.getParent(); if (parent != null && !Files.exists(parent)) { Files.createDirectories(parent); } Files.write(dist1, data); } catch (IOException e) { e.printStackTrace(System.err); } } }; }
这里主要又创建了一个ClassWriter
public ClassWriter(final int flags) { super(Opcodes.ASM5); index = 1; pool = new ByteVector(); items = new Item[256]; threshold = (int) (0.75d * items.length); key = new Item(); key2 = new Item(); key3 = new Item(); key4 = new Item(); this.computeMaxs = (flags & COMPUTE_MAXS) != 0; this.computeFrames = (flags & COMPUTE_FRAMES) != 0; }
这里的pool就是我们的常量池
public ClassVisitor(final int api, final ClassVisitor cv) { if (api != Opcodes.ASM4 && api != Opcodes.ASM5) { throw new IllegalArgumentException(); } this.api = api; this.cv = cv; }ClassWriter继承于ClassVisitor,这里保存在新创建ClassVisitor的cv里面
回到convertClass,接着
分析3 调用ClassVisitor 的visit
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { if (cv != null) { cv.visit(version, access, name, signature, superName, interfaces); } }这里的cv是我们前面创建的ClassWriter
@Override public final void visit(final int version, final int access, final String name, final String signature, final String superName, final String[] interfaces) { this.version = version; this.access = access; this.name = newClass(name); thisName = name; if (ClassReader.SIGNATURES && signature != null) { this.signature = newUTF8(signature); } this.superName = superName == null ? 0 : newClass(superName); if (interfaces != null && interfaces.length > 0) { interfaceCount = interfaces.length; this.interfaces = new int[interfaceCount]; for (int i = 0; i < interfaceCount; ++i) { this.interfaces[i] = newClass(interfaces[i]); } } }
这里主要是访问并保存类相关的一些信息
我们看下newClass
public int newClass(final String value) { return newClassItem(value).index; }
Item newClassItem(final String value) { key2.set(CLASS, value, null, null); Item result = get(key2); if (result == null) { pool.put12(CLASS, newUTF8(value)); result = new Item(index++, key2); put(result); } return result; }这里的value是我们的类名a/Test,这里CLASS对应是7,跟我们前面http://blog.csdn.net/new_abc/article/details/53501765中常量池中数据类型是一致的。
首先给key2临时变量设置值和类型
void set(final int type, final String strVal1, final String strVal2, final String strVal3) { this.type = type; this.strVal1 = strVal1; this.strVal2 = strVal2; this.strVal3 = strVal3; switch (type) { case ClassWriter.CLASS: this.intVal = 0; // intVal of a class must be zero, see visitInnerClass case ClassWriter.UTF8: case ClassWriter.STR: case ClassWriter.MTYPE: case ClassWriter.TYPE_NORMAL: hashCode = 0x7FFFFFFF & (type + strVal1.hashCode()); return; case ClassWriter.NAME_TYPE: { hashCode = 0x7FFFFFFF & (type + strVal1.hashCode() * strVal2.hashCode()); return; } // ClassWriter.FIELD: // ClassWriter.METH: // ClassWriter.IMETH: // ClassWriter.HANDLE_BASE + 1..9 default: hashCode = 0x7FFFFFFF & (type + strVal1.hashCode() * strVal2.hashCode() * strVal3.hashCode()); } }这里会通过type和value计算hashCode的值
然后调用get查找是否已经存在
private Item get(final Item key) { Item i = items[key.hashCode % items.length]; while (i != null && (i.type != key.type || !key.isEqualTo(i))) { i = i.next; } return i; }这里就是通过hashCode % item.lengt获取索引,后面我们会看到put时就是这么设置的
回到newClassItem
如果item不存在,则添加到常量池,添加到常量池之前,先调用newUTF8新建一个UTF8的字符串表示类名
public int newUTF8(final String value) { key.set(UTF8, value, null, null); Item result = get(key); if (result == null) { pool.putByte(UTF8).putUTF8(value); result = new Item(index++, key); put(result); } return result.index; }先查找对应的字符串是否存在,不存在则先添加一个UTF8,然后把UTF8的字符串添加到常量池
public ByteVector putByte(final int b) { int length = this.length; if (length + 1 > data.length) { enlarge(1); } data[length++] = (byte) b; this.length = length; return this; }
public ByteVector putUTF8(final String s) { int charLength = s.length(); if (charLength > 65535) { throw new IllegalArgumentException(); } int len = length; if (len + 2 + charLength > data.length) { enlarge(2 + charLength); } byte[] data = this.data; // optimistic algorithm: instead of computing the byte length and then // serializing the string (which requires two loops), we assume the byte // length is equal to char length (which is the most frequent case), and // we start serializing the string right away. During the serialization, // if we find that this assumption is wrong, we continue with the // general method. data[len++] = (byte) (charLength >>> 8); data[len++] = (byte) charLength; for (int i = 0; i < charLength; ++i) { char c = s.charAt(i); if (c >= '\001' && c <= '\177') { data[len++] = (byte) c; } else { length = len; return encodeUTF8(s, i, 65535); } } length = len; return this; }
putUTF8先写2字节的长度,然后把字符串写到常量池
newUTF8然后调用put添加到item列表中
private void put(final Item i) { if (index + typeCount > threshold) { int ll = items.length; int nl = ll * 2 + 1; Item[] newItems = new Item[nl]; for (int l = ll - 1; l >= 0; --l) { Item j = items[l]; while (j != null) { int index = j.hashCode % newItems.length; Item k = j.next; j.next = newItems[index]; newItems[index] = j; j = k; } } items = newItems; threshold = (int) (nl * 0.75); } int index = i.hashCode % items.length; i.next = items[index]; items[index] = i; }
到这里visit就完了,主要是新建了类相关的一些信息保存到常量池
回到convertClass,接着调用convertField访问字段
//访问字段 public void convertField(DexClassNode classNode, DexFieldNode fieldNode, ClassVisitor cv) { String signature = null; if (fieldNode.anns != null) { for (DexAnnotationNode ann : fieldNode.anns) { if (ann.visibility == Visibility.SYSTEM) { switch (ann.type) { case DexConstants.ANNOTATION_SIGNATURE_TYPE: { Object[] strs = (Object[]) findAnnotationAttribute(ann, "value"); if (strs != null) { StringBuilder sb = new StringBuilder(); for (Object str : strs) { sb.append(str); } signature = sb.toString(); } } break; } } } } Object value = fieldNode.cst; if (value instanceof DexType) { value = Type.getType(((DexType) value).desc); } final int FieldCleanFlag = ~DexConstants.ACC_DECLARED_SYNCHRONIZED; FieldVisitor fv = cv.visitField(fieldNode.access & FieldCleanFlag, fieldNode.field.getName(),//最终里面创建了一个FieldWriter fieldNode.field.getType(), signature, value); if (fv == null) { return; } accept(fieldNode.anns, fv); fv.visitEnd(); }先检查有没有注解,然后调用ClassVisitor的visitField访问字段
public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) { if (cv != null) { return cv.visitField(access, name, desc, signature, value); } return null; }
public final FieldVisitor visitField(final int access, final String name, final String desc, final String signature, final Object value) { return new FieldWriter(this, access, name, desc, signature, value); }
FieldWriter(final ClassWriter cw, final int access, final String name, final String desc, final String signature, final Object value) { super(Opcodes.ASM5); if (cw.firstField == null) { cw.firstField = this; } else { cw.lastField.fv = this; } cw.lastField = this; this.cw = cw; this.access = access; this.name = cw.newUTF8(name); this.desc = cw.newUTF8(desc); if (ClassReader.SIGNATURES && signature != null) { this.signature = cw.newUTF8(signature); } if (value != null) { this.value = cw.newConstItem(value).index; } }这里主要是新建一个FieldWriter,同样会把field相关的字段保存到常量池
然后再看下convertMethod
public void convertMethod(DexClassNode classNode, DexMethodNode methodNode, ClassVisitor cv) { MethodVisitor mv = collectBasicMethodInfo(methodNode, cv);//返回一个MethodWriter if (mv == null) { return; } if (0 != (classNode.access & DexConstants.ACC_ANNOTATION)) { // its inside an annotation Object defaultValue = null; if (classNode.anns != null) { for (DexAnnotationNode ann : classNode.anns) { if (ann.visibility == Visibility.SYSTEM && ann.type.equals(DexConstants.ANNOTATION_DEFAULT_TYPE)) { DexAnnotationNode node = (DexAnnotationNode) findAnnotationAttribute(ann, "value"); if (node != null) { defaultValue = findAnnotationAttribute(node, methodNode.method.getName()); } break; } } } if (defaultValue != null) { AnnotationVisitor av = mv.visitAnnotationDefault(); if (av != null) { accept(av, null, defaultValue); av.visitEnd(); } } } accept(methodNode.anns, mv); if (methodNode.parameterAnns != null) { for (int i = 0; i < methodNode.parameterAnns.length; i++) { List<DexAnnotationNode> anns = methodNode.parameterAnns[i]; if (anns != null) { for (DexAnnotationNode ann : anns) { if (ann.visibility != Visibility.SYSTEM) { acceptParameter(ann, i, mv); } } } } } if ((NO_CODE_MASK & methodNode.access) == 0) { // has code if (methodNode.codeNode != null) { mv.visitCode(); convertCode(methodNode, mv); } } mv.visitEnd(); }
collectBasicMethodInfo最终返回一个MethodWriter
MethodWriter(final ClassWriter cw, final int access, final String name, final String desc, final String signature, final String[] exceptions, final boolean computeMaxs, final boolean computeFrames) { super(Opcodes.ASM5); if (cw.firstMethod == null) { cw.firstMethod = this; } else { cw.lastMethod.mv = this; } cw.lastMethod = this; this.cw = cw; this.access = access; if ("<init>".equals(name)) { this.access |= ACC_CONSTRUCTOR; } this.name = cw.newUTF8(name); this.desc = cw.newUTF8(desc); this.descriptor = desc; if (ClassReader.SIGNATURES) { this.signature = signature; } if (exceptions != null && exceptions.length > 0) { exceptionCount = exceptions.length; this.exceptions = new int[exceptionCount]; for (int i = 0; i < exceptionCount; ++i) { this.exceptions[i] = cw.newClass(exceptions[i]); } } this.compute = computeFrames ? FRAMES : (computeMaxs ? MAXS : NOTHING); if (computeMaxs || computeFrames) { // updates maxLocals int size = Type.getArgumentsAndReturnSizes(descriptor) >> 2; if ((access & Opcodes.ACC_STATIC) != 0) { --size; } maxLocals = size; currentLocals = size; // creates and visits the label for the first basic block labels = new Label(); labels.status |= Label.PUSHED; visitLabel(labels); } }如果方法有参数,则调用acceptParameter访问参数
然后最重要的是调用convertCode转换code部分,convertCode最终调用的是我们前面定义的ExDex2Asm的convertCode
public void convertCode(DexMethodNode methodNode, MethodVisitor mv) { if (!AsmBridge.isMethodWriter(mv)) { throw new RuntimeException("We use a MethodWriter tricky here!"); } MethodNode mn = new MethodNode(Opcodes.ASM4, methodNode.access, methodNode.method.getName(), methodNode.method.getDesc(), null, null);//新建一个MethodNode节点 try { super.convertCode(methodNode, mn); } catch (Exception ex) { if (exceptionHandler == null) { throw new DexException(ex, "fail convert code for %s", methodNode.method); } else { mn.instructions.clear(); mn.tryCatchBlocks.clear(); exceptionHandler.handleMethodTranslateException(methodNode.method, methodNode, mn, ex); } } // code convert ok, copy to MethodWriter and check for Size mn.accept(mv);//把获取到的指令转换为二进制写到MethodVisitor的code字节数组中去 try { AsmBridge.sizeOfMethodWriter(mv); } catch (Exception ex) { mn.instructions.clear(); mn.tryCatchBlocks.clear(); exceptionHandler.handleMethodTranslateException(methodNode.method, methodNode, mn, ex); AsmBridge.replaceMethodWriter(mv, mn); } }这里新建一个MethodNode,由他负责对code的访问,传进来的MethodVisitor只后面负责接受二进制的结果
这里主要是调用父类的convertCode
由于后面部分还比较长,再下一篇介绍