Mercurial > hg > icedrobot > daneel
changeset 56:ef7e8137da03
Adapted parser interface for annotations.
Reviewed-by: Remi Forax
* dex/AnnotationsDirectory.java (acceptClassAnnotations): Implemented acceptor.
* (acceptFieldAnnotations, acceptMethodAnnotations): Likewise.
* (acceptAnnotation): Still missing, coming soon.
* dex/ClassData.java: Pass class definition as argument.
* (acceptField, acceptMethod): Also visit annotations.
* dex/ClassDef.java (accept): Also visit annotations.
* dex/DexAnnotationVisitor.java: New parser interface for annotations.
* dex/DexClassVisitor.java: Adapted for annotations.
* dex/DexFieldVisitor.java: Likewise.
* dex/DexMethodVisitor.java: Likewise.
* dex/EncodedValue.java (AnnotationValue): Make fields package-private.
* rewriter/DexRewriter.java: Adapted to above changes.
author | Michael Starzinger <michi@complang.tuwien.ac.at> |
---|---|
date | Sun, 20 Mar 2011 20:56:43 +0100 |
parents | 80952fd2bbd4 |
children | 8c9542073cf4 |
files | src/main/java/org/icedrobot/daneel/dex/AnnotationsDirectory.java src/main/java/org/icedrobot/daneel/dex/ClassData.java src/main/java/org/icedrobot/daneel/dex/ClassDef.java src/main/java/org/icedrobot/daneel/dex/DexAnnotationVisitor.java src/main/java/org/icedrobot/daneel/dex/DexClassVisitor.java src/main/java/org/icedrobot/daneel/dex/DexFieldVisitor.java src/main/java/org/icedrobot/daneel/dex/DexMethodVisitor.java src/main/java/org/icedrobot/daneel/dex/EncodedValue.java src/main/java/org/icedrobot/daneel/rewriter/DexRewriter.java |
diffstat | 9 files changed, 236 insertions(+), 44 deletions(-) [+] |
line wrap: on
line diff
--- a/src/main/java/org/icedrobot/daneel/dex/AnnotationsDirectory.java Sun Mar 20 19:51:58 2011 +0100 +++ b/src/main/java/org/icedrobot/daneel/dex/AnnotationsDirectory.java Sun Mar 20 20:56:43 2011 +0100 @@ -63,11 +63,11 @@ private final Annotation[] classAnnotations; - private final Map<Integer, Annotation[]> fieldAnnotations; + private final Map<FieldId, Annotation[]> fieldAnnotations; - private final Map<Integer, Annotation[]> methodAnnotations; + private final Map<MethodId, Annotation[]> methodAnnotations; - private final Map<Integer, Annotation[][]> parameterAnnotations; + private final Map<MethodId, Annotation[][]> parameterAnnotations; private AnnotationsDirectory(ByteBuffer buffer, DexFile dex) { int classAnnotationsOff = buffer.getInt(); @@ -83,28 +83,28 @@ classAnnotations = null; // Parse annotation_set_item structures in field_annotations array. - fieldAnnotations = new HashMap<Integer, Annotation[]>(fieldsSize); + fieldAnnotations = new HashMap<FieldId, Annotation[]>(fieldsSize); for (int i = 0; i < fieldsSize; i++) { int fieldIdx = buffer.getInt(); int annotationsOff = buffer.getInt(); ByteBuffer buf = dex.getDataBuffer(annotationsOff); Annotation[] annotations = parseAnnotations(buf, dex); - fieldAnnotations.put(fieldIdx, annotations); + fieldAnnotations.put(dex.getFieldId(fieldIdx), annotations); } // Parse annotation_set_item structures in method_annotations array. - methodAnnotations = new HashMap<Integer, Annotation[]>(methodsSize); + methodAnnotations = new HashMap<MethodId, Annotation[]>(methodsSize); for (int i = 0; i < methodsSize; i++) { int methodIdx = buffer.getInt(); int annotationsOff = buffer.getInt(); ByteBuffer buf = dex.getDataBuffer(annotationsOff); Annotation[] annotations = parseAnnotations(buf, dex); - methodAnnotations.put(methodIdx, annotations); + methodAnnotations.put(dex.getMethodId(methodIdx), annotations); } // Parse annotation_set_ref_list and contained annotation_set_item // structures in parameter_annotations array. - parameterAnnotations = new HashMap<Integer, Annotation[][]>(); + parameterAnnotations = new HashMap<MethodId, Annotation[][]>(); for (int i = 0; i < parametersSize; i++) { /*int methodIdx = buffer.getInt(); int annotationsOff = buffer.getInt(); @@ -116,41 +116,85 @@ buf = dex.getDataBuffer(list[j]); annotationSet[j] = parseAnnotations(buf, dex); } - parameterAnnotations.put(methodIdx, annotationSet);*/ + parameterAnnotations.put(dex.getMethodId(methodIdx), annotationSet);*/ throw new UnsupportedOperationException("Not yet tested!"); } } /** - * Returns all class annotations present in this directory or {@code null} - * if there are no such annotations. + * Allows the given visitor to visit all class annotations present in this + * directory. * - * @return An array containing the annotation items or {@code null}. + * @param visitor The given DEX class visitor object. */ - public Annotation[] getClassAnnotations() { - return classAnnotations; + public void acceptClassAnnotations(DexClassVisitor visitor) { + if (classAnnotations != null) + for (Annotation annotation : classAnnotations) { + int visibility = annotation.visibility; + String type = annotation.annotationValue.type; + acceptAnnotation(visitor.visitAnnotation(visibility, type), + annotation); + } + } + + /** + * Allows the given visitor to visit all field for a given field present in + * this directory. + * + * @param visitor The given DEX field visitor object. + * @param field The given field identifier. + */ + public void acceptFieldAnnotations(DexFieldVisitor visitor, FieldId field) { + Annotation[] annotations = fieldAnnotations.get(field); + if (annotations != null) + for (Annotation annotation : annotations) { + int visibility = annotation.visibility; + String type = annotation.annotationValue.type; + acceptAnnotation(visitor.visitAnnotation(visibility, type), + annotation); + } } /** - * Returns all field annotations for the given field index present in this - * directory or {@code null} if there are no such annotations. + * Allows the given visitor to visit all method and method parameter + * annotations for a given method present in this directory. * - * @param idx The given field index. - * @return An array containing the annotation items or {@code null}. + * @param visitor The given DEX method visitor object. + * @param method The given method identifier. */ - public Annotation[] getFieldAnnotations(int idx) { - return fieldAnnotations.get(idx); + public void acceptMethodAnnotations(DexMethodVisitor visitor, + MethodId method) { + Annotation[] annotations = methodAnnotations.get(method); + if (annotations != null) + for (Annotation annotation : annotations) { + int visibility = annotation.visibility; + String type = annotation.annotationValue.type; + acceptAnnotation(visitor.visitAnnotation(visibility, type), + annotation); + } + Annotation[][] annotationSet = parameterAnnotations.get(method); + if (annotationSet != null) + for (int i = 0; i < annotationSet.length; i++) + for (Annotation annotation : annotationSet[i]) { + int visibility = annotation.visibility; + String type = annotation.annotationValue.type; + acceptAnnotation(visitor.visitParameterAnnotation(i, + visibility, type), annotation); + } } /** - * Returns all method annotations for the given method index present in this - * directory or {@code null} if there are no such annotations. + * Allows the given visitor to visit the given annotation. * - * @param idx The given field index. - * @return An array containing the annotation items or {@code null}. + * @param visitor The given DEX annotation visitor or {@code null}. + * @param annotation The given annotation to visit. */ - public Annotation[] getMethodAnnotations(int idx) { - return methodAnnotations.get(idx); + private static void acceptAnnotation(DexAnnotationVisitor visitor, + Annotation annotation) { + if (visitor == null) + return; + // XXX Visit the annotation! + visitor.visitEnd(); } /** @@ -186,8 +230,6 @@ public Annotation(ByteBuffer buffer, DexFile dex) { visibility = buffer.get(); annotationValue = EncodedValue.parseAnnotation(buffer, dex); - System.out.printf("ANNOTATION: vis=0x%02x, val=%s\n", visibility, - annotationValue); } }; }
--- a/src/main/java/org/icedrobot/daneel/dex/ClassData.java Sun Mar 20 19:51:58 2011 +0100 +++ b/src/main/java/org/icedrobot/daneel/dex/ClassData.java Sun Mar 20 20:56:43 2011 +0100 @@ -53,16 +53,16 @@ * * @param buffer The byte buffer to read from. * @param dex The DEX file currently being parsed. - * @param staticValuesOff Offset to the list of initial values for static - * fields as stored in {@code class_def_item}, or 0 in case there - * are none. + * @param classDef The class definition this data belongs to. * @return An object representing the parsed data. */ public static ClassData parse(ByteBuffer buffer, DexFile dex, - int staticValuesOff) { - return new ClassData(buffer, dex, staticValuesOff); + ClassDef classDef) { + return new ClassData(buffer, dex, classDef); } + private final ClassDef classDef; + private int staticFieldsSize; private int instanceFieldsSize; @@ -87,7 +87,8 @@ private final Object[] staticValues; - private ClassData(ByteBuffer buffer, DexFile dex, int staticValuesOff) { + private ClassData(ByteBuffer buffer, DexFile dex, ClassDef classDef) { + this.classDef = classDef; staticFieldsSize = BufferUtil.getULEB128(buffer); instanceFieldsSize = BufferUtil.getULEB128(buffer); directMethodsSize = BufferUtil.getULEB128(buffer); @@ -146,6 +147,7 @@ } // Parse encoded_array_item and contained encoded_value structures. + int staticValuesOff = classDef.getStaticValuesOff(); if (staticValuesOff != 0) { ByteBuffer buf = dex.getDataBuffer(staticValuesOff); staticValues = EncodedValue.parseArray(buf, dex); @@ -235,18 +237,22 @@ /** * Helper method to visit a field. */ - private static void acceptField(DexClassVisitor visitor, int access, + private void acceptField(DexClassVisitor visitor, int access, FieldId field, Object value) { - DexFieldVisitor dfv = visitor.visitField(access, field.getName(), - field.getTypeDescriptor(), value); - if (dfv != null) - dfv.visitEnd(); + DexFieldVisitor dfv = visitor.visitField(access, field.getName(), field + .getTypeDescriptor(), value); + if (dfv == null) + return; + AnnotationsDirectory annotations = classDef.getAnnotations(); + if (annotations != null) + annotations.acceptFieldAnnotations(dfv, field); + dfv.visitEnd(); } /** * Helper method to visit a method. */ - private static void acceptMethod(DexClassVisitor visitor, int access, + private void acceptMethod(DexClassVisitor visitor, int access, MethodId method, Code code) { ProtoId proto = method.getProtoId(); DexMethodVisitor dmv = visitor @@ -254,6 +260,9 @@ proto.getReturnType(), proto.getParameters()); if (dmv == null) return; + AnnotationsDirectory annotations = classDef.getAnnotations(); + if (annotations != null) + annotations.acceptMethodAnnotations(dmv, method); if (code != null) code.accept(dmv); dmv.visitEnd();
--- a/src/main/java/org/icedrobot/daneel/dex/ClassDef.java Sun Mar 20 19:51:58 2011 +0100 +++ b/src/main/java/org/icedrobot/daneel/dex/ClassDef.java Sun Mar 20 20:56:43 2011 +0100 @@ -71,6 +71,8 @@ private ClassData classData; + private final int staticValuesOff; + private ClassDef(ByteBuffer buffer, DexFile dex) { int classIdx = buffer.getInt(); accessFlags = buffer.getInt(); @@ -79,7 +81,7 @@ int sourceFileIdx = buffer.getInt(); int annotationsOff = buffer.getInt(); int classDataOff = buffer.getInt(); - int staticValuesOff = buffer.getInt(); + staticValuesOff = buffer.getInt(); // Resolve string and type indices. className = dex.getTypeDescriptor(classIdx); @@ -106,7 +108,7 @@ // Parse associated class_data_item structure. if (classDataOff != 0) { ByteBuffer buf = dex.getDataBuffer(classDataOff); - classData = ClassData.parse(buf, dex, staticValuesOff); + classData = ClassData.parse(buf, dex, this); } } @@ -130,10 +132,18 @@ return sourceFile; } + public AnnotationsDirectory getAnnotations() { + return annotations; + } + public ClassData getClassData() { return classData; } + public int getStaticValuesOff() { + return staticValuesOff; + } + /** * Allows the given visitor to visit this class definition. * @@ -143,6 +153,8 @@ visitor.visit(accessFlags, className, superclass, interfaces); if (sourceFile != null) visitor.visitSource(sourceFile); + if (annotations != null) + annotations.acceptClassAnnotations(visitor); if (classData != null) classData.accept(visitor); visitor.visitEnd();
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/org/icedrobot/daneel/dex/DexAnnotationVisitor.java Sun Mar 20 20:56:43 2011 +0100 @@ -0,0 +1,51 @@ +/* + * Daneel - Dalvik to Java bytecode compiler + * Copyright (C) 2011 IcedRobot team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * This file is subject to the "Classpath" exception: + * + * Linking this library statically or dynamically with other modules is + * making a combined work based on this library. Thus, the terms and + * conditions of the GNU General Public License cover the whole + * combination. + * + * As a special exception, the copyright holders of this library give you + * permission to link this library with independent modules to produce an + * executable, regardless of the license terms of these independent + * modules, and to copy and distribute the resulting executable under terms + * of your choice, provided that you also meet, for each linked independent + * module, the terms and conditions of the license of that module. An + * independent module is a module which is not derived from or based on + * this library. If you modify this library, you may extend this exception + * to your version of the library, but you are not obligated to do so. If + * you do not wish to do so, delete this exception statement from your + * version. + */ + +package org.icedrobot.daneel.dex; + +/** + * A visitor for annotations contained in DEX files. + */ +public interface DexAnnotationVisitor { + + // XXX Define further methods! + + /** + * Visits the end of the annotation. + */ + void visitEnd(); +}
--- a/src/main/java/org/icedrobot/daneel/dex/DexClassVisitor.java Sun Mar 20 19:51:58 2011 +0100 +++ b/src/main/java/org/icedrobot/daneel/dex/DexClassVisitor.java Sun Mar 20 20:56:43 2011 +0100 @@ -64,6 +64,18 @@ void visitSource(String source); /** + * Visits an annotation of the class. In case this visitor is interested in + * further details about the annotation it should return a new visitor + * object, otherwise it should return {@code null}. + * + * @param visibility The annotation's visibility flags. + * @param type The annotation's type as a type descriptor. + * @return A visitor object for the annotation or {@code null} if this + * visitor is not interested in details about the annotation. + */ + DexAnnotationVisitor visitAnnotation(int visibility, String type); + + /** * Visits a field of the class. In case this visitor is interested in * further details about the field (i.e. annotations) it should return a new * visitor object, otherwise it should return {@code null}.
--- a/src/main/java/org/icedrobot/daneel/dex/DexFieldVisitor.java Sun Mar 20 19:51:58 2011 +0100 +++ b/src/main/java/org/icedrobot/daneel/dex/DexFieldVisitor.java Sun Mar 20 20:56:43 2011 +0100 @@ -43,6 +43,18 @@ public interface DexFieldVisitor { /** + * Visits an annotation of the field. In case this visitor is interested in + * further details about the annotation it should return a new visitor + * object, otherwise it should return {@code null}. + * + * @param visibility The annotation's visibility flags. + * @param type The annotation's type as a type descriptor. + * @return A visitor object for the annotation or {@code null} if this + * visitor is not interested in details about the annotation. + */ + DexAnnotationVisitor visitAnnotation(int visibility, String type); + + /** * Visits the end of the field. */ void visitEnd();
--- a/src/main/java/org/icedrobot/daneel/dex/DexMethodVisitor.java Sun Mar 20 19:51:58 2011 +0100 +++ b/src/main/java/org/icedrobot/daneel/dex/DexMethodVisitor.java Sun Mar 20 20:56:43 2011 +0100 @@ -42,6 +42,33 @@ * A visitor for methods contained in DEX files. */ public interface DexMethodVisitor { + + /** + * Visits an annotation of the method. In case this visitor is interested in + * further details about the annotation it should return a new visitor + * object, otherwise it should return {@code null}. + * + * @param visibility The annotation's visibility flags. + * @param type The annotation's type as a type descriptor. + * @return A visitor object for the annotation or {@code null} if this + * visitor is not interested in details about the annotation. + */ + DexAnnotationVisitor visitAnnotation(int visibility, String type); + + /** + * Visits an annotation of a parameter to the method. In case this visitor + * is interested in further details about the annotation it should return a + * new visitor object, otherwise it should return {@code null}. + * + * @param parameter The parameter index. + * @param visibility The annotation's visibility flags. + * @param type The annotation's type as a type descriptor. + * @return A visitor object for the annotation or {@code null} if this + * visitor is not interested in details about the annotation. + */ + DexAnnotationVisitor visitParameterAnnotation(int parameter, + int visibility, String type); + /** * Starts visiting the method's code. The code is visited by subsequent * calls to {@code visitLabel()} and {@code visitInstr*()} methods.
--- a/src/main/java/org/icedrobot/daneel/dex/EncodedValue.java Sun Mar 20 19:51:58 2011 +0100 +++ b/src/main/java/org/icedrobot/daneel/dex/EncodedValue.java Sun Mar 20 20:56:43 2011 +0100 @@ -205,8 +205,8 @@ * encoded_annotation} structure. */ static class AnnotationValue { - private final String type; - private final Map<String, Object> elements; + final String type; + final Map<String, Object> elements; public AnnotationValue(String type, Map<String, Object> elements) { this.type = type;
--- a/src/main/java/org/icedrobot/daneel/rewriter/DexRewriter.java Sun Mar 20 19:51:58 2011 +0100 +++ b/src/main/java/org/icedrobot/daneel/rewriter/DexRewriter.java Sun Mar 20 20:56:43 2011 +0100 @@ -45,6 +45,7 @@ import java.util.HashMap; import java.util.Map; +import org.icedrobot.daneel.dex.DexAnnotationVisitor; import org.icedrobot.daneel.dex.DexClassVisitor; import org.icedrobot.daneel.dex.DexFieldVisitor; import org.icedrobot.daneel.dex.DexMethodVisitor; @@ -103,6 +104,12 @@ } @Override + public DexAnnotationVisitor visitAnnotation(int visibility, String type) { + // XXX Ignore annotations for now. + return null; + } + + @Override public DexFieldVisitor visitField(int access, String name, String type, Object value) { final FieldVisitor fv = cv.visitField(access, name, type, null, value); @@ -115,6 +122,13 @@ public void visitEnd() { fv.visitEnd(); } + + @Override + public DexAnnotationVisitor visitAnnotation(int visibility, + String type) { + // XXX Ignore annotations for now. + return null; + } }; } @@ -448,6 +462,19 @@ } @Override + public DexAnnotationVisitor visitAnnotation(int visibility, String type) { + // XXX Ignore annotations for now. + return null; + } + + @Override + public DexAnnotationVisitor visitParameterAnnotation(int parameter, + int visibility, String type) { + // XXX Ignore annotations for now. + return null; + } + + @Override public void visitLabel(Label label) { Register[] registers = interpreter.getJoinPoint(label); if (registers != null) { // target of an already seen jump