diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 18:28:14 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 18:28:14 -0800 |
commit | f72d5de56a522ac3be03873bdde26f23a5eeeb3c (patch) | |
tree | 4b825dc642cb6eb9a060e54bf8d69288fbee4904 /dx/src/com/android/dx/dex/file | |
parent | 31e30105703263782efd450d356cd67ea01af3b7 (diff) | |
download | android_dalvik-f72d5de56a522ac3be03873bdde26f23a5eeeb3c.tar.gz android_dalvik-f72d5de56a522ac3be03873bdde26f23a5eeeb3c.tar.bz2 android_dalvik-f72d5de56a522ac3be03873bdde26f23a5eeeb3c.zip |
auto import from //depot/cupcake/@135843
Diffstat (limited to 'dx/src/com/android/dx/dex/file')
50 files changed, 0 insertions, 10771 deletions
diff --git a/dx/src/com/android/dx/dex/file/AnnotationItem.java b/dx/src/com/android/dx/dex/file/AnnotationItem.java deleted file mode 100644 index 43ac36266..000000000 --- a/dx/src/com/android/dx/dex/file/AnnotationItem.java +++ /dev/null @@ -1,220 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.dx.dex.file; - -import com.android.dx.rop.annotation.Annotation; -import com.android.dx.rop.annotation.AnnotationVisibility; -import com.android.dx.rop.annotation.NameValuePair; -import com.android.dx.rop.cst.Constant; -import com.android.dx.rop.cst.CstAnnotation; -import com.android.dx.rop.cst.CstArray; -import com.android.dx.rop.cst.CstUtf8; -import com.android.dx.util.ByteArrayAnnotatedOutput; -import com.android.dx.util.AnnotatedOutput; - -import java.util.Arrays; -import java.util.Comparator; - -/** - * Single annotation, which consists of a type and a set of name-value - * element pairs. - */ -public final class AnnotationItem extends OffsettedItem { - /** annotation visibility constant: visible at build time only */ - private static final int VISIBILITY_BUILD = 0; - - /** annotation visibility constant: visible at runtime */ - private static final int VISIBILITY_RUNTIME = 1; - - /** annotation visibility constant: visible at runtime only to system */ - private static final int VISIBILITY_SYSTEM = 2; - - /** the required alignment for instances of this class */ - private static final int ALIGNMENT = 1; - - /** non-null; unique instance of {@link #TypeIdSorter} */ - private static final TypeIdSorter TYPE_ID_SORTER = new TypeIdSorter(); - - /** non-null; the annotation to represent */ - private final Annotation annotation; - - /** - * null-ok; type reference for the annotation type; set during - * {@link #addContents} - */ - private TypeIdItem type; - - /** - * null-ok; encoded form, ready for writing to a file; set during - * {@link #place0} - */ - private byte[] encodedForm; - - /** - * Comparator that sorts (outer) instances by type id index. - */ - private static class TypeIdSorter implements Comparator<AnnotationItem> { - /** {@inheritDoc} */ - public int compare(AnnotationItem item1, AnnotationItem item2) { - int index1 = item1.type.getIndex(); - int index2 = item2.type.getIndex(); - - if (index1 < index2) { - return -1; - } else if (index1 > index2) { - return 1; - } - - return 0; - } - } - - /** - * Sorts an array of instances, in place, by type id index, - * ignoring all other aspects of the elements. This is only valid - * to use after type id indices are known. - * - * @param array non-null; array to sort - */ - public static void sortByTypeIdIndex(AnnotationItem[] array) { - Arrays.sort(array, TYPE_ID_SORTER); - } - - /** - * Constructs an instance. - * - * @param annotation non-null; annotation to represent - */ - public AnnotationItem(Annotation annotation) { - /* - * The write size isn't known up-front because (the variable-lengthed) - * leb128 type is used to represent some things. - */ - super(ALIGNMENT, -1); - - if (annotation == null) { - throw new NullPointerException("annotation == null"); - } - - this.annotation = annotation; - this.type = null; - this.encodedForm = null; - } - - /** {@inheritDoc} */ - @Override - public ItemType itemType() { - return ItemType.TYPE_ANNOTATION_ITEM; - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - return annotation.hashCode(); - } - - /** {@inheritDoc} */ - @Override - protected int compareTo0(OffsettedItem other) { - AnnotationItem otherAnnotation = (AnnotationItem) other; - - return annotation.compareTo(otherAnnotation.annotation); - } - - /** {@inheritDoc} */ - @Override - public String toHuman() { - return annotation.toHuman(); - } - - /** {@inheritDoc} */ - public void addContents(DexFile file) { - type = file.getTypeIds().intern(annotation.getType()); - ValueEncoder.addContents(file, annotation); - } - - /** {@inheritDoc} */ - @Override - protected void place0(Section addedTo, int offset) { - // Encode the data and note the size. - - ByteArrayAnnotatedOutput out = new ByteArrayAnnotatedOutput(); - ValueEncoder encoder = new ValueEncoder(addedTo.getFile(), out); - - encoder.writeAnnotation(annotation, false); - encodedForm = out.toByteArray(); - - // Add one for the visibility byte in front of the encoded annotation. - setWriteSize(encodedForm.length + 1); - } - - /** - * Write a (listing file) annotation for this instance to the given - * output, that consumes no bytes of output. This is for annotating - * a reference to this instance at the point of the reference. - * - * @param out non-null; where to output to - * @param prefix non-null; prefix for each line of output - */ - public void annotateTo(AnnotatedOutput out, String prefix) { - out.annotate(0, prefix + "visibility: " + - annotation.getVisibility().toHuman()); - out.annotate(0, prefix + "type: " + annotation.getType().toHuman()); - - for (NameValuePair pair : annotation.getNameValuePairs()) { - CstUtf8 name = pair.getName(); - Constant value = pair.getValue(); - - out.annotate(0, prefix + name.toHuman() + ": " + - ValueEncoder.constantToHuman(value)); - } - } - - /** {@inheritDoc} */ - @Override - protected void writeTo0(DexFile file, AnnotatedOutput out) { - boolean annotates = out.annotates(); - AnnotationVisibility visibility = annotation.getVisibility(); - - if (annotates) { - out.annotate(0, offsetString() + " annotation"); - out.annotate(1, " visibility: VISBILITY_" + visibility); - } - - switch (visibility) { - case BUILD: out.writeByte(VISIBILITY_BUILD); break; - case RUNTIME: out.writeByte(VISIBILITY_RUNTIME); break; - case SYSTEM: out.writeByte(VISIBILITY_SYSTEM); break; - default: { - // EMBEDDED shouldn't appear at the top level. - throw new RuntimeException("shouldn't happen"); - } - } - - if (annotates) { - /* - * The output is to be annotated, so redo the work previously - * done by place0(), except this time annotations will actually - * get emitted. - */ - ValueEncoder encoder = new ValueEncoder(file, out); - encoder.writeAnnotation(annotation, true); - } else { - out.write(encodedForm); - } - } -} diff --git a/dx/src/com/android/dx/dex/file/AnnotationSetItem.java b/dx/src/com/android/dx/dex/file/AnnotationSetItem.java deleted file mode 100644 index f03cc08d1..000000000 --- a/dx/src/com/android/dx/dex/file/AnnotationSetItem.java +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.dx.dex.file; - -import com.android.dx.rop.annotation.Annotations; -import com.android.dx.rop.annotation.Annotation; -import com.android.dx.util.AnnotatedOutput; -import com.android.dx.util.Hex; - -/** - * Set of annotations, where no annotation type appears more than once. - */ -public final class AnnotationSetItem extends OffsettedItem { - /** the required alignment for instances of this class */ - private static final int ALIGNMENT = 4; - - /** the size of an entry int the set: one <code>uint</code> */ - private static final int ENTRY_WRITE_SIZE = 4; - - /** non-null; the set of annotations */ - private final Annotations annotations; - - /** - * non-null; set of annotations as individual items in an array. - * <b>Note:</b> The contents have to get sorted by type id before - * writing. - */ - private final AnnotationItem[] items; - - /** - * Constructs an instance. - * - * @param annotations non-null; set of annotations - */ - public AnnotationSetItem(Annotations annotations) { - super(ALIGNMENT, writeSize(annotations)); - - this.annotations = annotations; - this.items = new AnnotationItem[annotations.size()]; - - int at = 0; - for (Annotation a : annotations.getAnnotations()) { - items[at] = new AnnotationItem(a); - at++; - } - } - - /** - * Gets the write size for the given set. - * - * @param annotations non-null; the set - * @return > 0; the write size - */ - private static int writeSize(Annotations annotations) { - // This includes an int size at the start of the list. - - try { - return (annotations.size() * ENTRY_WRITE_SIZE) + 4; - } catch (NullPointerException ex) { - // Elucidate the exception. - throw new NullPointerException("list == null"); - } - } - - /** - * Gets the underlying annotations of this instance - * - * @return non-null; the annotations - */ - public Annotations getAnnotations() { - return annotations; - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - return annotations.hashCode(); - } - - /** {@inheritDoc} */ - @Override - protected int compareTo0(OffsettedItem other) { - AnnotationSetItem otherSet = (AnnotationSetItem) other; - - return annotations.compareTo(otherSet.annotations); - } - - /** {@inheritDoc} */ - @Override - public ItemType itemType() { - return ItemType.TYPE_ANNOTATION_SET_ITEM; - } - - /** {@inheritDoc} */ - @Override - public String toHuman() { - return annotations.toString(); - } - - /** {@inheritDoc} */ - public void addContents(DexFile file) { - MixedItemSection byteData = file.getByteData(); - int size = items.length; - - for (int i = 0; i < size; i++) { - items[i] = byteData.intern(items[i]); - } - } - - /** {@inheritDoc} */ - @Override - protected void place0(Section addedTo, int offset) { - // Sort the array to be in type id index order. - AnnotationItem.sortByTypeIdIndex(items); - } - - /** {@inheritDoc} */ - @Override - protected void writeTo0(DexFile file, AnnotatedOutput out) { - boolean annotates = out.annotates(); - int size = items.length; - - if (annotates) { - out.annotate(0, offsetString() + " annotation set"); - out.annotate(4, " size: " + Hex.u4(size)); - } - - out.writeInt(size); - - for (int i = 0; i < size; i++) { - AnnotationItem item = items[i]; - int offset = item.getAbsoluteOffset(); - - if (annotates) { - out.annotate(4, " entries[" + Integer.toHexString(i) + "]: " + - Hex.u4(offset)); - items[i].annotateTo(out, " "); - } - - out.writeInt(offset); - } - } -} diff --git a/dx/src/com/android/dx/dex/file/AnnotationSetRefItem.java b/dx/src/com/android/dx/dex/file/AnnotationSetRefItem.java deleted file mode 100644 index 422e2f019..000000000 --- a/dx/src/com/android/dx/dex/file/AnnotationSetRefItem.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.dx.dex.file; - -import com.android.dx.util.AnnotatedOutput; -import com.android.dx.util.Hex; - -/** - * Indirect reference to an {@link AnnotationSetItem}. - */ -public final class AnnotationSetRefItem extends OffsettedItem { - /** the required alignment for instances of this class */ - private static final int ALIGNMENT = 4; - - /** write size of this class, in bytes */ - private static final int WRITE_SIZE = 4; - - /** non-null; the annotation set to refer to */ - private AnnotationSetItem annotations; - - /** - * Constructs an instance. - * - * @param annotations non-null; the annotation set to refer to - */ - public AnnotationSetRefItem(AnnotationSetItem annotations) { - super(ALIGNMENT, WRITE_SIZE); - - if (annotations == null) { - throw new NullPointerException("annotations == null"); - } - - this.annotations = annotations; - } - - /** {@inheritDoc} */ - @Override - public ItemType itemType() { - return ItemType.TYPE_ANNOTATION_SET_REF_ITEM; - } - - /** {@inheritDoc} */ - public void addContents(DexFile file) { - MixedItemSection wordData = file.getWordData(); - - annotations = wordData.intern(annotations); - } - - /** {@inheritDoc} */ - @Override - public String toHuman() { - return annotations.toHuman(); - } - - /** {@inheritDoc} */ - @Override - protected void writeTo0(DexFile file, AnnotatedOutput out) { - int annotationsOff = annotations.getAbsoluteOffset(); - - if (out.annotates()) { - out.annotate(4, " annotations_off: " + Hex.u4(annotationsOff)); - } - - out.writeInt(annotationsOff); - } -} diff --git a/dx/src/com/android/dx/dex/file/AnnotationUtils.java b/dx/src/com/android/dx/dex/file/AnnotationUtils.java deleted file mode 100644 index c9d796843..000000000 --- a/dx/src/com/android/dx/dex/file/AnnotationUtils.java +++ /dev/null @@ -1,254 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.dx.dex.file; - -import com.android.dx.rop.annotation.Annotation; -import com.android.dx.rop.annotation.NameValuePair; -import com.android.dx.rop.cst.Constant; -import com.android.dx.rop.cst.CstAnnotation; -import com.android.dx.rop.cst.CstArray; -import com.android.dx.rop.cst.CstInteger; -import com.android.dx.rop.cst.CstKnownNull; -import com.android.dx.rop.cst.CstMethodRef; -import com.android.dx.rop.cst.CstString; -import com.android.dx.rop.cst.CstType; -import com.android.dx.rop.cst.CstUtf8; -import com.android.dx.rop.type.Type; -import com.android.dx.rop.type.TypeList; - -import java.util.ArrayList; - -import static com.android.dx.rop.annotation.AnnotationVisibility.*; - -/** - * Utility class for dealing with annotations. - */ -public final class AnnotationUtils { - /** non-null; type for <code>AnnotationDefault</code> annotations */ - private static final CstType ANNOTATION_DEFAULT_TYPE = - CstType.intern(Type.intern("Ldalvik/annotation/AnnotationDefault;")); - - /** non-null; type for <code>EnclosingClass</code> annotations */ - private static final CstType ENCLOSING_CLASS_TYPE = - CstType.intern(Type.intern("Ldalvik/annotation/EnclosingClass;")); - - /** non-null; type for <code>EnclosingMethod</code> annotations */ - private static final CstType ENCLOSING_METHOD_TYPE = - CstType.intern(Type.intern("Ldalvik/annotation/EnclosingMethod;")); - - /** non-null; type for <code>InnerClass</code> annotations */ - private static final CstType INNER_CLASS_TYPE = - CstType.intern(Type.intern("Ldalvik/annotation/InnerClass;")); - - /** non-null; type for <code>MemberClasses</code> annotations */ - private static final CstType MEMBER_CLASSES_TYPE = - CstType.intern(Type.intern("Ldalvik/annotation/MemberClasses;")); - - /** non-null; type for <code>Signature</code> annotations */ - private static final CstType SIGNATURE_TYPE = - CstType.intern(Type.intern("Ldalvik/annotation/Signature;")); - - /** non-null; type for <code>Throws</code> annotations */ - private static final CstType THROWS_TYPE = - CstType.intern(Type.intern("Ldalvik/annotation/Throws;")); - - /** non-null; the UTF-8 constant <code>"accessFlags"</code> */ - private static final CstUtf8 ACCESS_FLAGS_UTF = new CstUtf8("accessFlags"); - - /** non-null; the UTF-8 constant <code>"name"</code> */ - private static final CstUtf8 NAME_UTF = new CstUtf8("name"); - - /** non-null; the UTF-8 constant <code>"value"</code> */ - private static final CstUtf8 VALUE_UTF = new CstUtf8("value"); - - /** - * This class is uninstantiable. - */ - private AnnotationUtils() { - // This space intentionally left blank. - } - - /** - * Constructs a standard <code>AnnotationDefault</code> annotation. - * - * @param defaults non-null; the defaults, itself as an annotation - * @return non-null; the constructed annotation - */ - public static Annotation makeAnnotationDefault(Annotation defaults) { - Annotation result = new Annotation(ANNOTATION_DEFAULT_TYPE, SYSTEM); - - result.put(new NameValuePair(VALUE_UTF, new CstAnnotation(defaults))); - result.setImmutable(); - return result; - } - - /** - * Constructs a standard <code>EnclosingClass</code> annotation. - * - * @param clazz non-null; the enclosing class - * @return non-null; the annotation - */ - public static Annotation makeEnclosingClass(CstType clazz) { - Annotation result = new Annotation(ENCLOSING_CLASS_TYPE, SYSTEM); - - result.put(new NameValuePair(VALUE_UTF, clazz)); - result.setImmutable(); - return result; - } - - /** - * Constructs a standard <code>EnclosingMethod</code> annotation. - * - * @param method non-null; the enclosing method - * @return non-null; the annotation - */ - public static Annotation makeEnclosingMethod(CstMethodRef method) { - Annotation result = new Annotation(ENCLOSING_METHOD_TYPE, SYSTEM); - - result.put(new NameValuePair(VALUE_UTF, method)); - result.setImmutable(); - return result; - } - - /** - * Constructs a standard <code>InnerClass</code> annotation. - * - * @param name null-ok; the original name of the class, or - * <code>null</code> to represent an anonymous class - * @param accessFlags the original access flags - * @return non-null; the annotation - */ - public static Annotation makeInnerClass(CstUtf8 name, int accessFlags) { - Annotation result = new Annotation(INNER_CLASS_TYPE, SYSTEM); - Constant nameCst = - (name != null) ? new CstString(name) : CstKnownNull.THE_ONE; - - result.put(new NameValuePair(NAME_UTF, nameCst)); - result.put(new NameValuePair(ACCESS_FLAGS_UTF, - CstInteger.make(accessFlags))); - result.setImmutable(); - return result; - } - - /** - * Constructs a standard <code>MemberClasses</code> annotation. - * - * @param types non-null; the list of (the types of) the member classes - * @return non-null; the annotation - */ - public static Annotation makeMemberClasses(TypeList types) { - CstArray array = makeCstArray(types); - Annotation result = new Annotation(MEMBER_CLASSES_TYPE, SYSTEM); - result.put(new NameValuePair(VALUE_UTF, array)); - result.setImmutable(); - return result; - } - - /** - * Constructs a standard <code>Signature</code> annotation. - * - * @param signature non-null; the signature string - * @return non-null; the annotation - */ - public static Annotation makeSignature(CstUtf8 signature) { - Annotation result = new Annotation(SIGNATURE_TYPE, SYSTEM); - - /* - * Split the string into pieces that are likely to be common - * across many signatures and the rest of the file. - */ - - String raw = signature.getString(); - int rawLength = raw.length(); - ArrayList<String> pieces = new ArrayList<String>(20); - - for (int at = 0; at < rawLength; /*at*/) { - char c = raw.charAt(at); - int endAt = at + 1; - if (c == 'L') { - // Scan to ';' or '<'. Consume ';' but not '<'. - while (endAt < rawLength) { - c = raw.charAt(endAt); - if (c == ';') { - endAt++; - break; - } else if (c == '<') { - break; - } - endAt++; - } - } else { - // Scan to 'L' without consuming it. - while (endAt < rawLength) { - c = raw.charAt(endAt); - if (c == 'L') { - break; - } - endAt++; - } - } - - pieces.add(raw.substring(at, endAt)); - at = endAt; - } - - int size = pieces.size(); - CstArray.List list = new CstArray.List(size); - - for (int i = 0; i < size; i++) { - list.set(i, new CstString(pieces.get(i))); - } - - list.setImmutable(); - - result.put(new NameValuePair(VALUE_UTF, new CstArray(list))); - result.setImmutable(); - return result; - } - - /** - * Constructs a standard <code>Throws</code> annotation. - * - * @param types non-null; the list of thrown types - * @return non-null; the annotation - */ - public static Annotation makeThrows(TypeList types) { - CstArray array = makeCstArray(types); - Annotation result = new Annotation(THROWS_TYPE, SYSTEM); - result.put(new NameValuePair(VALUE_UTF, array)); - result.setImmutable(); - return result; - } - - /** - * Converts a {@link TypeList} to a {@link CstArray}. - * - * @param types non-null; the type list - * @return non-null; the corresponding array constant - */ - private static CstArray makeCstArray(TypeList types) { - int size = types.size(); - CstArray.List list = new CstArray.List(size); - - for (int i = 0; i < size; i++) { - list.set(i, CstType.intern(types.getType(i))); - } - - list.setImmutable(); - return new CstArray(list); - } -} diff --git a/dx/src/com/android/dx/dex/file/AnnotationsDirectoryItem.java b/dx/src/com/android/dx/dex/file/AnnotationsDirectoryItem.java deleted file mode 100644 index 4521e4c5b..000000000 --- a/dx/src/com/android/dx/dex/file/AnnotationsDirectoryItem.java +++ /dev/null @@ -1,385 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.dx.dex.file; - -import com.android.dx.rop.annotation.Annotations; -import com.android.dx.rop.annotation.AnnotationsList; -import com.android.dx.rop.cst.CstFieldRef; -import com.android.dx.rop.cst.CstMethodRef; -import com.android.dx.util.AnnotatedOutput; -import com.android.dx.util.Hex; - -import java.io.PrintWriter; -import java.util.ArrayList; -import java.util.Collections; - -/** - * Per-class directory of annotations. - */ -public final class AnnotationsDirectoryItem extends OffsettedItem { - /** the required alignment for instances of this class */ - private static final int ALIGNMENT = 4; - - /** write size of this class's header, in bytes */ - private static final int HEADER_SIZE = 16; - - /** write size of a list element, in bytes */ - private static final int ELEMENT_SIZE = 8; - - /** null-ok; the class-level annotations, if any */ - private AnnotationSetItem classAnnotations; - - /** null-ok; the annotated fields, if any */ - private ArrayList<FieldAnnotationStruct> fieldAnnotations; - - /** null-ok; the annotated methods, if any */ - private ArrayList<MethodAnnotationStruct> methodAnnotations; - - /** null-ok; the annotated parameters, if any */ - private ArrayList<ParameterAnnotationStruct> parameterAnnotations; - - /** - * Constructs an empty instance. - */ - public AnnotationsDirectoryItem() { - super(ALIGNMENT, -1); - - classAnnotations = null; - fieldAnnotations = null; - methodAnnotations = null; - parameterAnnotations = null; - } - - /** {@inheritDoc} */ - @Override - public ItemType itemType() { - return ItemType.TYPE_ANNOTATIONS_DIRECTORY_ITEM; - } - - /** - * Returns whether this item is empty (has no contents). - * - * @return <code>true</code> if this item is empty, or <code>false</code> - * if not - */ - public boolean isEmpty() { - return (classAnnotations == null) && - (fieldAnnotations == null) && - (methodAnnotations == null) && - (parameterAnnotations == null); - } - - /** - * Returns whether this item is a candidate for interning. The only - * interning candidates are ones that <i>only</i> have a non-null - * set of class annotations, with no other lists. - * - * @return <code>true</code> if this is an interning candidate, or - * <code>false</code> if not - */ - public boolean isInternable() { - return (classAnnotations != null) && - (fieldAnnotations == null) && - (methodAnnotations == null) && - (parameterAnnotations == null); - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - if (classAnnotations == null) { - return 0; - } - - return classAnnotations.hashCode(); - } - - /** - * {@inheritDoc} - * - * <p><b>Note:</b>: This throws an exception if this item is not - * internable.</p> - * - * @see #isInternable - */ - @Override - public int compareTo0(OffsettedItem other) { - if (! isInternable()) { - throw new UnsupportedOperationException("uninternable instance"); - } - - AnnotationsDirectoryItem otherDirectory = - (AnnotationsDirectoryItem) other; - return classAnnotations.compareTo(otherDirectory.classAnnotations); - } - - /** - * Sets the direct annotations on this instance. These are annotations - * made on the class, per se, as opposed to on one of its members. - * It is only valid to call this method at most once per instance. - * - * @param annotations non-null; annotations to set for this class - */ - public void setClassAnnotations(Annotations annotations) { - if (annotations == null) { - throw new NullPointerException("annotations == null"); - } - - if (classAnnotations != null) { - throw new UnsupportedOperationException( - "class annotations already set"); - } - - classAnnotations = new AnnotationSetItem(annotations); - } - - /** - * Adds a field annotations item to this instance. - * - * @param field non-null; field in question - * @param annotations non-null; associated annotations to add - */ - public void addFieldAnnotations(CstFieldRef field, - Annotations annotations) { - if (fieldAnnotations == null) { - fieldAnnotations = new ArrayList<FieldAnnotationStruct>(); - } - - fieldAnnotations.add(new FieldAnnotationStruct(field, - new AnnotationSetItem(annotations))); - } - - /** - * Adds a method annotations item to this instance. - * - * @param method non-null; method in question - * @param annotations non-null; associated annotations to add - */ - public void addMethodAnnotations(CstMethodRef method, - Annotations annotations) { - if (methodAnnotations == null) { - methodAnnotations = new ArrayList<MethodAnnotationStruct>(); - } - - methodAnnotations.add(new MethodAnnotationStruct(method, - new AnnotationSetItem(annotations))); - } - - /** - * Adds a parameter annotations item to this instance. - * - * @param method non-null; method in question - * @param list non-null; associated list of annotation sets to add - */ - public void addParameterAnnotations(CstMethodRef method, - AnnotationsList list) { - if (parameterAnnotations == null) { - parameterAnnotations = new ArrayList<ParameterAnnotationStruct>(); - } - - parameterAnnotations.add(new ParameterAnnotationStruct(method, list)); - } - - /** - * Gets the method annotations for a given method, if any. This is - * meant for use by debugging / dumping code. - * - * @param method non-null; the method - * @return null-ok; the method annotations, if any - */ - public Annotations getMethodAnnotations(CstMethodRef method) { - if (methodAnnotations == null) { - return null; - } - - for (MethodAnnotationStruct item : methodAnnotations) { - if (item.getMethod().equals(method)) { - return item.getAnnotations(); - } - } - - return null; - } - - /** - * Gets the parameter annotations for a given method, if any. This is - * meant for use by debugging / dumping code. - * - * @param method non-null; the method - * @return null-ok; the parameter annotations, if any - */ - public AnnotationsList getParameterAnnotations(CstMethodRef method) { - if (parameterAnnotations == null) { - return null; - } - - for (ParameterAnnotationStruct item : parameterAnnotations) { - if (item.getMethod().equals(method)) { - return item.getAnnotationsList(); - } - } - - return null; - } - - /** {@inheritDoc} */ - public void addContents(DexFile file) { - MixedItemSection wordData = file.getWordData(); - - if (classAnnotations != null) { - classAnnotations = wordData.intern(classAnnotations); - } - - if (fieldAnnotations != null) { - for (FieldAnnotationStruct item : fieldAnnotations) { - item.addContents(file); - } - } - - if (methodAnnotations != null) { - for (MethodAnnotationStruct item : methodAnnotations) { - item.addContents(file); - } - } - - if (parameterAnnotations != null) { - for (ParameterAnnotationStruct item : parameterAnnotations) { - item.addContents(file); - } - } - } - - /** {@inheritDoc} */ - @Override - public String toHuman() { - throw new RuntimeException("unsupported"); - } - - /** {@inheritDoc} */ - @Override - protected void place0(Section addedTo, int offset) { - // We just need to set the write size here. - - int elementCount = listSize(fieldAnnotations) - + listSize(methodAnnotations) + listSize(parameterAnnotations); - setWriteSize(HEADER_SIZE + (elementCount * ELEMENT_SIZE)); - } - - /** {@inheritDoc} */ - @Override - protected void writeTo0(DexFile file, AnnotatedOutput out) { - boolean annotates = out.annotates(); - int classOff = OffsettedItem.getAbsoluteOffsetOr0(classAnnotations); - int fieldsSize = listSize(fieldAnnotations); - int methodsSize = listSize(methodAnnotations); - int parametersSize = listSize(parameterAnnotations); - - if (annotates) { - out.annotate(0, offsetString() + " annotations directory"); - out.annotate(4, " class_annotations_off: " + Hex.u4(classOff)); - out.annotate(4, " fields_size: " + - Hex.u4(fieldsSize)); - out.annotate(4, " methods_size: " + - Hex.u4(methodsSize)); - out.annotate(4, " parameters_size: " + - Hex.u4(parametersSize)); - } - - out.writeInt(classOff); - out.writeInt(fieldsSize); - out.writeInt(methodsSize); - out.writeInt(parametersSize); - - if (fieldsSize != 0) { - Collections.sort(fieldAnnotations); - if (annotates) { - out.annotate(0, " fields:"); - } - for (FieldAnnotationStruct item : fieldAnnotations) { - item.writeTo(file, out); - } - } - - if (methodsSize != 0) { - Collections.sort(methodAnnotations); - if (annotates) { - out.annotate(0, " methods:"); - } - for (MethodAnnotationStruct item : methodAnnotations) { - item.writeTo(file, out); - } - } - - if (parametersSize != 0) { - Collections.sort(parameterAnnotations); - if (annotates) { - out.annotate(0, " parameters:"); - } - for (ParameterAnnotationStruct item : parameterAnnotations) { - item.writeTo(file, out); - } - } - } - - /** - * Gets the list size of the given list, or <code>0</code> if given - * <code>null</code>. - * - * @param list null-ok; the list in question - * @return >= 0; its size - */ - private static int listSize(ArrayList<?> list) { - if (list == null) { - return 0; - } - - return list.size(); - } - - /** - * Prints out the contents of this instance, in a debugging-friendly - * way. This is meant to be called from {@link ClassDefItem#debugPrint}. - * - * @param out non-null; where to output to - */ - /*package*/ void debugPrint(PrintWriter out) { - if (classAnnotations != null) { - out.println(" class annotations: " + classAnnotations); - } - - if (fieldAnnotations != null) { - out.println(" field annotations:"); - for (FieldAnnotationStruct item : fieldAnnotations) { - out.println(" " + item.toHuman()); - } - } - - if (methodAnnotations != null) { - out.println(" method annotations:"); - for (MethodAnnotationStruct item : methodAnnotations) { - out.println(" " + item.toHuman()); - } - } - - if (parameterAnnotations != null) { - out.println(" parameter annotations:"); - for (ParameterAnnotationStruct item : parameterAnnotations) { - out.println(" " + item.toHuman()); - } - } - } -} diff --git a/dx/src/com/android/dx/dex/file/CatchStructs.java b/dx/src/com/android/dx/dex/file/CatchStructs.java deleted file mode 100644 index b7abc3f53..000000000 --- a/dx/src/com/android/dx/dex/file/CatchStructs.java +++ /dev/null @@ -1,320 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.dx.dex.file; - -import com.android.dx.dex.code.CatchHandlerList; -import com.android.dx.dex.code.CatchTable; -import com.android.dx.dex.code.DalvCode; -import com.android.dx.rop.cst.CstType; -import com.android.dx.rop.type.Type; -import com.android.dx.util.AnnotatedOutput; -import com.android.dx.util.ByteArrayAnnotatedOutput; -import com.android.dx.util.Hex; - -import java.io.PrintWriter; -import java.util.Map; -import java.util.TreeMap; - -/** - * List of exception handlers (tuples of covered range, catch type, - * handler address) for a particular piece of code. Instances of this - * class correspond to a <code>try_item[]</code> and a - * <code>catch_handler_item[]</code>. - */ -public final class CatchStructs { - /** - * the size of a <code>try_item</code>: a <code>uint</code> - * and two <code>ushort</code>s - */ - private static final int TRY_ITEM_WRITE_SIZE = 4 + (2 * 2); - - /** non-null; code that contains the catches */ - private final DalvCode code; - - /** - * null-ok; the underlying table; set in - * {@link #finishProcessingIfNecessary} - */ - private CatchTable table; - - /** - * null-ok; the encoded handler list, if calculated; set in - * {@link #encode} - */ - private byte[] encodedHandlers; - - /** - * length of the handlers header (encoded size), if known; used for - * annotation - */ - private int encodedHandlerHeaderSize; - - /** - * null-ok; map from handler lists to byte offsets, if calculated; set in - * {@link #encode} - */ - private TreeMap<CatchHandlerList, Integer> handlerOffsets; - - /** - * Constructs an instance. - * - * @param code non-null; code that contains the catches - */ - public CatchStructs(DalvCode code) { - this.code = code; - this.table = null; - this.encodedHandlers = null; - this.encodedHandlerHeaderSize = 0; - this.handlerOffsets = null; - } - - /** - * Finish processing the catches, if necessary. - */ - private void finishProcessingIfNecessary() { - if (table == null) { - table = code.getCatches(); - } - } - - /** - * Gets the size of the tries list, in entries. - * - * @return >= 0; the tries list size - */ - public int triesSize() { - finishProcessingIfNecessary(); - return table.size(); - } - - /** - * Does a human-friendly dump of this instance. - * - * @param out non-null; where to dump - * @param prefix non-null; prefix to attach to each line of output - */ - public void debugPrint(PrintWriter out, String prefix) { - annotateEntries(prefix, out, null); - } - - /** - * Encodes the handler lists. - * - * @param file non-null; file this instance is part of - */ - public void encode(DexFile file) { - finishProcessingIfNecessary(); - - TypeIdsSection typeIds = file.getTypeIds(); - int size = table.size(); - - handlerOffsets = new TreeMap<CatchHandlerList, Integer>(); - - /* - * First add a map entry for each unique list. The tree structure - * will ensure they are sorted when we reiterate later. - */ - for (int i = 0; i < size; i++) { - handlerOffsets.put(table.get(i).getHandlers(), null); - } - - if (handlerOffsets.size() > 65535) { - throw new UnsupportedOperationException( - "too many catch handlers"); - } - - ByteArrayAnnotatedOutput out = new ByteArrayAnnotatedOutput(); - - // Write out the handlers "header" consisting of its size in entries. - encodedHandlerHeaderSize = - out.writeUnsignedLeb128(handlerOffsets.size()); - - // Now write the lists out in order, noting the offset of each. - for (Map.Entry<CatchHandlerList, Integer> mapping : - handlerOffsets.entrySet()) { - CatchHandlerList list = mapping.getKey(); - int listSize = list.size(); - boolean catchesAll = list.catchesAll(); - - // Set the offset before we do any writing. - mapping.setValue(out.getCursor()); - - if (catchesAll) { - // A size <= 0 means that the list ends with a catch-all. - out.writeSignedLeb128(-(listSize - 1)); - listSize--; - } else { - out.writeSignedLeb128(listSize); - } - - for (int i = 0; i < listSize; i++) { - CatchHandlerList.Entry entry = list.get(i); - out.writeUnsignedLeb128( - typeIds.indexOf(entry.getExceptionType())); - out.writeUnsignedLeb128(entry.getHandler()); - } - - if (catchesAll) { - out.writeUnsignedLeb128(list.get(listSize).getHandler()); - } - } - - encodedHandlers = out.toByteArray(); - } - - /** - * Gets the write size of this instance, in bytes. - * - * @return >= 0; the write size - */ - public int writeSize() { - return (triesSize() * TRY_ITEM_WRITE_SIZE) + - + encodedHandlers.length; - } - - /** - * Writes this instance to the given stream. - * - * @param file non-null; file this instance is part of - * @param out non-null; where to write to - */ - public void writeTo(DexFile file, AnnotatedOutput out) { - finishProcessingIfNecessary(); - - TypeIdsSection typeIds = file.getTypeIds(); - int tableSize = table.size(); - int handlersSize = handlerOffsets.size(); - - if (out.annotates()) { - annotateEntries(" ", null, out); - } - - for (int i = 0; i < tableSize; i++) { - CatchTable.Entry one = table.get(i); - int start = one.getStart(); - int end = one.getEnd(); - int insnCount = end - start; - - if (insnCount >= 65536) { - throw new UnsupportedOperationException( - "bogus exception range: " + Hex.u4(start) + ".." + - Hex.u4(end)); - } - - out.writeInt(start); - out.writeShort(insnCount); - out.writeShort(handlerOffsets.get(one.getHandlers())); - } - - out.write(encodedHandlers); - } - - /** - * Helper method to annotate or simply print the exception handlers. - * Only one of <code>printTo</code> or <code>annotateTo</code> should - * be non-null. - * - * @param prefix non-null; prefix for each line - * @param printTo null-ok; where to print to - * @param annotateTo null-ok; where to consume bytes and annotate to - */ - private void annotateEntries(String prefix, PrintWriter printTo, - AnnotatedOutput annotateTo) { - finishProcessingIfNecessary(); - - boolean consume = (annotateTo != null); - int amt1 = consume ? 6 : 0; - int amt2 = consume ? 2 : 0; - int size = table.size(); - String subPrefix = prefix + " "; - - if (consume) { - annotateTo.annotate(0, prefix + "tries:"); - } else { - printTo.println(prefix + "tries:"); - } - - for (int i = 0; i < size; i++) { - CatchTable.Entry entry = table.get(i); - CatchHandlerList handlers = entry.getHandlers(); - String s1 = subPrefix + "try " + Hex.u2or4(entry.getStart()) - + ".." + Hex.u2or4(entry.getEnd()); - String s2 = handlers.toHuman(subPrefix, ""); - - if (consume) { - annotateTo.annotate(amt1, s1); - annotateTo.annotate(amt2, s2); - } else { - printTo.println(s1); - printTo.println(s2); - } - } - - if (! consume) { - // Only emit the handler lists if we are consuming bytes. - return; - } - - annotateTo.annotate(0, prefix + "handlers:"); - annotateTo.annotate(encodedHandlerHeaderSize, - subPrefix + "size: " + Hex.u2(handlerOffsets.size())); - - int lastOffset = 0; - CatchHandlerList lastList = null; - - for (Map.Entry<CatchHandlerList, Integer> mapping : - handlerOffsets.entrySet()) { - CatchHandlerList list = mapping.getKey(); - int offset = mapping.getValue(); - - if (lastList != null) { - annotateAndConsumeHandlers(lastList, lastOffset, - offset - lastOffset, subPrefix, printTo, annotateTo); - } - - lastList = list; - lastOffset = offset; - } - - annotateAndConsumeHandlers(lastList, lastOffset, - encodedHandlers.length - lastOffset, - subPrefix, printTo, annotateTo); - } - - /** - * Helper for {@link #annotateEntries} to annotate a catch handler list - * while consuming it. - * - * @param handlers non-null; handlers to annotate - * @param offset >= 0; the offset of this handler - * @param size >= 1; the number of bytes the handlers consume - * @param prefix non-null; prefix for each line - * @param printTo null-ok; where to print to - * @param annotateTo non-null; where to annotate to - */ - private static void annotateAndConsumeHandlers(CatchHandlerList handlers, - int offset, int size, String prefix, PrintWriter printTo, - AnnotatedOutput annotateTo) { - String s = handlers.toHuman(prefix, Hex.u2(offset) + ": "); - - if (printTo != null) { - printTo.println(s); - } - - annotateTo.annotate(size, s); - } -} diff --git a/dx/src/com/android/dx/dex/file/ClassDataItem.java b/dx/src/com/android/dx/dex/file/ClassDataItem.java deleted file mode 100644 index 638daed21..000000000 --- a/dx/src/com/android/dx/dex/file/ClassDataItem.java +++ /dev/null @@ -1,431 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.dx.dex.file; - -import com.android.dx.rop.cst.Constant; -import com.android.dx.rop.cst.CstArray; -import com.android.dx.rop.cst.CstLiteralBits; -import com.android.dx.rop.cst.CstType; -import com.android.dx.rop.cst.Zeroes; -import com.android.dx.util.ByteArrayAnnotatedOutput; -import com.android.dx.util.AnnotatedOutput; -import com.android.dx.util.Hex; -import com.android.dx.util.Writers; - -import java.io.PrintWriter; -import java.io.Writer; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.HashMap; - -/** - * Representation of all the parts of a Dalvik class that are generally - * "inflated" into an in-memory representation at runtime. Instances of - * this class are represented in a compact streamable form in a - * <code>dex</code> file, as opposed to a random-access form. - */ -public final class ClassDataItem extends OffsettedItem { - /** non-null; what class this data is for, just for listing generation */ - private final CstType thisClass; - - /** non-null; list of static fields */ - private final ArrayList<EncodedField> staticFields; - - /** non-null; list of initial values for static fields */ - private final HashMap<EncodedField, Constant> staticValues; - - /** non-null; list of instance fields */ - private final ArrayList<EncodedField> instanceFields; - - /** non-null; list of direct methods */ - private final ArrayList<EncodedMethod> directMethods; - - /** non-null; list of virtual methods */ - private final ArrayList<EncodedMethod> virtualMethods; - - /** null-ok; static initializer list; set in {@link #addContents} */ - private CstArray staticValuesConstant; - - /** - * null-ok; encoded form, ready for writing to a file; set during - * {@link #place0} - */ - private byte[] encodedForm; - - /** - * Constructs an instance. Its sets of members are initially - * empty. - * - * @param thisClass non-null; what class this data is for, just - * for listing generation - */ - public ClassDataItem(CstType thisClass) { - super(1, -1); - - if (thisClass == null) { - throw new NullPointerException("thisClass == null"); - } - - this.thisClass = thisClass; - this.staticFields = new ArrayList<EncodedField>(20); - this.staticValues = new HashMap<EncodedField, Constant>(40); - this.instanceFields = new ArrayList<EncodedField>(20); - this.directMethods = new ArrayList<EncodedMethod>(20); - this.virtualMethods = new ArrayList<EncodedMethod>(20); - this.staticValuesConstant = null; - } - - /** {@inheritDoc} */ - @Override - public ItemType itemType() { - return ItemType.TYPE_CLASS_DATA_ITEM; - } - - /** {@inheritDoc} */ - @Override - public String toHuman() { - return toString(); - } - - /** - * Returns whether this instance is empty. - * - * @return <code>true</code> if this instance is empty or - * <code>false</code> if at least one element has been added to it - */ - public boolean isEmpty() { - return staticFields.isEmpty() && instanceFields.isEmpty() - && directMethods.isEmpty() && virtualMethods.isEmpty(); - } - - /** - * Adds a static field. - * - * @param field non-null; the field to add - * @param value null-ok; initial value for the field, if any - */ - public void addStaticField(EncodedField field, Constant value) { - if (field == null) { - throw new NullPointerException("field == null"); - } - - if (staticValuesConstant != null) { - throw new UnsupportedOperationException( - "static fields already sorted"); - } - - staticFields.add(field); - staticValues.put(field, value); - } - - /** - * Adds an instance field. - * - * @param field non-null; the field to add - */ - public void addInstanceField(EncodedField field) { - if (field == null) { - throw new NullPointerException("field == null"); - } - - instanceFields.add(field); - } - - /** - * Adds a direct (<code>static</code> and/or <code>private</code>) method. - * - * @param method non-null; the method to add - */ - public void addDirectMethod(EncodedMethod method) { - if (method == null) { - throw new NullPointerException("method == null"); - } - - directMethods.add(method); - } - - /** - * Adds a virtual method. - * - * @param method non-null; the method to add - */ - public void addVirtualMethod(EncodedMethod method) { - if (method == null) { - throw new NullPointerException("method == null"); - } - - virtualMethods.add(method); - } - - /** - * Gets all the methods in this class. The returned list is not linked - * in any way to the underlying lists contained in this instance, but - * the objects contained in the list are shared. - * - * @return non-null; list of all methods - */ - public ArrayList<EncodedMethod> getMethods() { - int sz = directMethods.size() + virtualMethods.size(); - ArrayList<EncodedMethod> result = new ArrayList<EncodedMethod>(sz); - - result.addAll(directMethods); - result.addAll(virtualMethods); - - return result; - } - - - /** - * Prints out the contents of this instance, in a debugging-friendly - * way. - * - * @param out non-null; where to output to - * @param verbose whether to be verbose with the output - */ - public void debugPrint(Writer out, boolean verbose) { - PrintWriter pw = Writers.printWriterFor(out); - - int sz = staticFields.size(); - for (int i = 0; i < sz; i++) { - pw.println(" sfields[" + i + "]: " + staticFields.get(i)); - } - - sz = instanceFields.size(); - for (int i = 0; i < sz; i++) { - pw.println(" ifields[" + i + "]: " + instanceFields.get(i)); - } - - sz = directMethods.size(); - for (int i = 0; i < sz; i++) { - pw.println(" dmeths[" + i + "]:"); - directMethods.get(i).debugPrint(pw, verbose); - } - - sz = virtualMethods.size(); - for (int i = 0; i < sz; i++) { - pw.println(" vmeths[" + i + "]:"); - virtualMethods.get(i).debugPrint(pw, verbose); - } - } - - /** {@inheritDoc} */ - @Override - public void addContents(DexFile file) { - if (!staticFields.isEmpty()) { - getStaticValuesConstant(); // Force the fields to be sorted. - for (EncodedField field : staticFields) { - field.addContents(file); - } - } - - if (!instanceFields.isEmpty()) { - Collections.sort(instanceFields); - for (EncodedField field : instanceFields) { - field.addContents(file); - } - } - - if (!directMethods.isEmpty()) { - Collections.sort(directMethods); - for (EncodedMethod method : directMethods) { - method.addContents(file); - } - } - - if (!virtualMethods.isEmpty()) { - Collections.sort(virtualMethods); - for (EncodedMethod method : virtualMethods) { - method.addContents(file); - } - } - } - - /** - * Gets a {@link CstArray} corresponding to {@link #staticValues} if - * it contains any non-zero non-<code>null</code> values. - * - * @return null-ok; the corresponding constant or <code>null</code> if - * there are no values to encode - */ - public CstArray getStaticValuesConstant() { - if ((staticValuesConstant == null) && (staticFields.size() != 0)) { - staticValuesConstant = makeStaticValuesConstant(); - } - - return staticValuesConstant; - } - - /** - * Gets a {@link CstArray} corresponding to {@link #staticValues} if - * it contains any non-zero non-<code>null</code> values. - * - * @return null-ok; the corresponding constant or <code>null</code> if - * there are no values to encode - */ - private CstArray makeStaticValuesConstant() { - // First sort the statics into their final order. - Collections.sort(staticFields); - - /* - * Get the size of staticValues minus any trailing zeros/nulls (both - * nulls per se as well as instances of CstKnownNull). - */ - - int size = staticFields.size(); - while (size > 0) { - EncodedField field = staticFields.get(size - 1); - Constant cst = staticValues.get(field); - if (cst instanceof CstLiteralBits) { - // Note: CstKnownNull extends CstLiteralBits. - if (((CstLiteralBits) cst).getLongBits() != 0) { - break; - } - } else if (cst != null) { - break; - } - size--; - } - - if (size == 0) { - return null; - } - - // There is something worth encoding, so build up a result. - - CstArray.List list = new CstArray.List(size); - for (int i = 0; i < size; i++) { - EncodedField field = staticFields.get(i); - Constant cst = staticValues.get(field); - if (cst == null) { - cst = Zeroes.zeroFor(field.getRef().getType()); - } - list.set(i, cst); - } - list.setImmutable(); - - return new CstArray(list); - } - - /** {@inheritDoc} */ - @Override - protected void place0(Section addedTo, int offset) { - // Encode the data and note the size. - - ByteArrayAnnotatedOutput out = new ByteArrayAnnotatedOutput(); - - encodeOutput(addedTo.getFile(), out); - encodedForm = out.toByteArray(); - setWriteSize(encodedForm.length); - } - - /** - * Writes out the encoded form of this instance. - * - * @param file non-null; file this instance is part of - * @param out non-null; where to write to - */ - private void encodeOutput(DexFile file, AnnotatedOutput out) { - boolean annotates = out.annotates(); - int svSize = (staticValuesConstant == null) ? 0 : - staticValuesConstant.getList().size(); - - if (annotates) { - out.annotate(0, offsetString() + " class data for " + - thisClass.toHuman()); - } - - encodeSize(file, out, "static_fields", staticFields.size()); - encodeSize(file, out, "instance_fields", instanceFields.size()); - encodeSize(file, out, "direct_methods", directMethods.size()); - encodeSize(file, out, "virtual_methods", virtualMethods.size()); - - encodeList(file, out, "static_fields", staticFields); - encodeList(file, out, "instance_fields", instanceFields); - encodeList(file, out, "direct_methods", directMethods); - encodeList(file, out, "virtual_methods", virtualMethods); - - if (annotates) { - out.endAnnotation(); - } - } - - /** - * Helper for {@link #encodeOutput}, which writes out the given - * size value, annotating it as well (if annotations are enabled). - * - * @param file non-null; file this instance is part of - * @param out non-null; where to write to - * @param label non-null; the label for the purposes of annotation - * @param size >= 0; the size to write - */ - private static void encodeSize(DexFile file, AnnotatedOutput out, - String label, int size) { - if (out.annotates()) { - out.annotate(String.format(" %-21s %08x", label + "_size:", - size)); - } - - out.writeUnsignedLeb128(size); - } - - /** - * Helper for {@link #encodeOutput}, which writes out the given - * list. It also annotates the items (if any and if annotations - * are enabled). - * - * @param file non-null; file this instance is part of - * @param out non-null; where to write to - * @param label non-null; the label for the purposes of annotation - * @param list non-null; the list in question - */ - private static void encodeList(DexFile file, AnnotatedOutput out, - String label, ArrayList<? extends EncodedMember> list) { - int size = list.size(); - int lastIndex = 0; - - if (size == 0) { - return; - } - - if (out.annotates()) { - out.annotate(0, " " + label + ":"); - } - - for (int i = 0; i < size; i++) { - lastIndex = list.get(i).encode(file, out, lastIndex, i); - } - } - - /** {@inheritDoc} */ - @Override - public void writeTo0(DexFile file, AnnotatedOutput out) { - boolean annotates = out.annotates(); - - if (annotates) { - /* - * The output is to be annotated, so redo the work previously - * done by place0(), except this time annotations will actually - * get emitted. - */ - encodeOutput(file, out); - } else { - out.write(encodedForm); - } - } -} diff --git a/dx/src/com/android/dx/dex/file/ClassDefItem.java b/dx/src/com/android/dx/dex/file/ClassDefItem.java deleted file mode 100644 index 5a0b27c90..000000000 --- a/dx/src/com/android/dx/dex/file/ClassDefItem.java +++ /dev/null @@ -1,410 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.dx.dex.file; - -import com.android.dx.rop.annotation.Annotations; -import com.android.dx.rop.annotation.AnnotationsList; -import com.android.dx.rop.code.AccessFlags; -import com.android.dx.rop.cst.Constant; -import com.android.dx.rop.cst.CstArray; -import com.android.dx.rop.cst.CstFieldRef; -import com.android.dx.rop.cst.CstMethodRef; -import com.android.dx.rop.cst.CstType; -import com.android.dx.rop.cst.CstUtf8; -import com.android.dx.rop.type.StdTypeList; -import com.android.dx.rop.type.TypeList; -import com.android.dx.util.AnnotatedOutput; -import com.android.dx.util.Hex; -import com.android.dx.util.Writers; - -import java.io.PrintWriter; -import java.io.Writer; -import java.util.ArrayList; -import java.util.TreeSet; - -/** - * Representation of a Dalvik class, which is basically a set of - * members (fields or methods) along with a few more pieces of - * information. - */ -public final class ClassDefItem extends IndexedItem { - /** size of instances when written out to a file, in bytes */ - public static final int WRITE_SIZE = 32; - - /** non-null; type constant for this class */ - private final CstType thisClass; - - /** access flags */ - private final int accessFlags; - - /** - * null-ok; superclass or <code>null</code> if this class is a/the - * root class - */ - private final CstType superclass; - - /** null-ok; list of implemented interfaces */ - private TypeListItem interfaces; - - /** null-ok; source file name or <code>null</code> if unknown */ - private final CstUtf8 sourceFile; - - /** non-null; associated class data object */ - private final ClassDataItem classData; - - /** - * null-ok; item wrapper for the static values, initialized - * in {@link #addContents} - */ - private EncodedArrayItem staticValuesItem; - - /** non-null; annotations directory */ - private AnnotationsDirectoryItem annotationsDirectory; - - /** - * Constructs an instance. Its sets of members and annotations are - * initially empty. - * - * @param thisClass non-null; type constant for this class - * @param accessFlags access flags - * @param superclass null-ok; superclass or <code>null</code> if - * this class is a/the root class - * @param interfaces non-null; list of implemented interfaces - * @param sourceFile null-ok; source file name or - * <code>null</code> if unknown - */ - public ClassDefItem(CstType thisClass, int accessFlags, - CstType superclass, TypeList interfaces, CstUtf8 sourceFile) { - if (thisClass == null) { - throw new NullPointerException("thisClass == null"); - } - - /* - * TODO: Maybe check accessFlags and superclass, at - * least for easily-checked stuff? - */ - - if (interfaces == null) { - throw new NullPointerException("interfaces == null"); - } - - this.thisClass = thisClass; - this.accessFlags = accessFlags; - this.superclass = superclass; - this.interfaces = - (interfaces.size() == 0) ? null : new TypeListItem(interfaces); - this.sourceFile = sourceFile; - this.classData = new ClassDataItem(thisClass); - this.staticValuesItem = null; - this.annotationsDirectory = new AnnotationsDirectoryItem(); - } - - /** {@inheritDoc} */ - @Override - public ItemType itemType() { - return ItemType.TYPE_CLASS_DEF_ITEM; - } - - /** {@inheritDoc} */ - @Override - public int writeSize() { - return WRITE_SIZE; - } - - /** {@inheritDoc} */ - @Override - public void addContents(DexFile file) { - TypeIdsSection typeIds = file.getTypeIds(); - MixedItemSection byteData = file.getByteData(); - MixedItemSection wordData = file.getWordData(); - MixedItemSection typeLists = file.getTypeLists(); - StringIdsSection stringIds = file.getStringIds(); - - typeIds.intern(thisClass); - - if (!classData.isEmpty()) { - MixedItemSection classDataSection = file.getClassData(); - classDataSection.add(classData); - - CstArray staticValues = classData.getStaticValuesConstant(); - if (staticValues != null) { - staticValuesItem = - byteData.intern(new EncodedArrayItem(staticValues)); - } - } - - if (superclass != null) { - typeIds.intern(superclass); - } - - if (interfaces != null) { - interfaces = typeLists.intern(interfaces); - } - - if (sourceFile != null) { - stringIds.intern(sourceFile); - } - - if (! annotationsDirectory.isEmpty()) { - if (annotationsDirectory.isInternable()) { - annotationsDirectory = wordData.intern(annotationsDirectory); - } else { - wordData.add(annotationsDirectory); - } - } - } - - /** {@inheritDoc} */ - @Override - public void writeTo(DexFile file, AnnotatedOutput out) { - boolean annotates = out.annotates(); - TypeIdsSection typeIds = file.getTypeIds(); - int classIdx = typeIds.indexOf(thisClass); - int superIdx = (superclass == null) ? -1 : - typeIds.indexOf(superclass); - int interOff = OffsettedItem.getAbsoluteOffsetOr0(interfaces); - int annoOff = annotationsDirectory.isEmpty() ? 0 : - annotationsDirectory.getAbsoluteOffset(); - int sourceFileIdx = (sourceFile == null) ? -1 : - file.getStringIds().indexOf(sourceFile); - int dataOff = classData.isEmpty()? 0 : classData.getAbsoluteOffset(); - int staticValuesOff = - OffsettedItem.getAbsoluteOffsetOr0(staticValuesItem); - - if (annotates) { - out.annotate(0, indexString() + ' ' + thisClass.toHuman()); - out.annotate(4, " class_idx: " + Hex.u4(classIdx)); - out.annotate(4, " access_flags: " + - AccessFlags.classString(accessFlags)); - out.annotate(4, " superclass_idx: " + Hex.u4(superIdx) + - " // " + ((superclass == null) ? "<none>" : - superclass.toHuman())); - out.annotate(4, " interfaces_off: " + Hex.u4(interOff)); - if (interOff != 0) { - TypeList list = interfaces.getList(); - int sz = list.size(); - for (int i = 0; i < sz; i++) { - out.annotate(0, " " + list.getType(i).toHuman()); - } - } - out.annotate(4, " source_file_idx: " + Hex.u4(sourceFileIdx) + - " // " + ((sourceFile == null) ? "<none>" : - sourceFile.toHuman())); - out.annotate(4, " annotations_off: " + Hex.u4(annoOff)); - out.annotate(4, " class_data_off: " + Hex.u4(dataOff)); - out.annotate(4, " static_values_off: " + - Hex.u4(staticValuesOff)); - } - - out.writeInt(classIdx); - out.writeInt(accessFlags); - out.writeInt(superIdx); - out.writeInt(interOff); - out.writeInt(sourceFileIdx); - out.writeInt(annoOff); - out.writeInt(dataOff); - out.writeInt(staticValuesOff); - } - - /** - * Gets the constant corresponding to this class. - * - * @return non-null; the constant - */ - public CstType getThisClass() { - return thisClass; - } - - /** - * Gets the access flags. - * - * @return the access flags - */ - public int getAccessFlags() { - return accessFlags; - } - - /** - * Gets the superclass. - * - * @return null-ok; the superclass or <code>null</code> if - * this class is a/the root class - */ - public CstType getSuperclass() { - return superclass; - } - - /** - * Gets the list of interfaces implemented. - * - * @return non-null; the interfaces list - */ - public TypeList getInterfaces() { - if (interfaces == null) { - return StdTypeList.EMPTY; - } - - return interfaces.getList(); - } - - /** - * Gets the source file name. - * - * @return null-ok; the source file name or <code>null</code> if unknown - */ - public CstUtf8 getSourceFile() { - return sourceFile; - } - - /** - * Adds a static field. - * - * @param field non-null; the field to add - * @param value null-ok; initial value for the field, if any - */ - public void addStaticField(EncodedField field, Constant value) { - classData.addStaticField(field, value); - } - - /** - * Adds an instance field. - * - * @param field non-null; the field to add - */ - public void addInstanceField(EncodedField field) { - classData.addInstanceField(field); - } - - /** - * Adds a direct (<code>static</code> and/or <code>private</code>) method. - * - * @param method non-null; the method to add - */ - public void addDirectMethod(EncodedMethod method) { - classData.addDirectMethod(method); - } - - /** - * Adds a virtual method. - * - * @param method non-null; the method to add - */ - public void addVirtualMethod(EncodedMethod method) { - classData.addVirtualMethod(method); - } - - /** - * Gets all the methods in this class. The returned list is not linked - * in any way to the underlying lists contained in this instance, but - * the objects contained in the list are shared. - * - * @return non-null; list of all methods - */ - public ArrayList<EncodedMethod> getMethods() { - return classData.getMethods(); - } - - /** - * Sets the direct annotations on this class. These are annotations - * made on the class, per se, as opposed to on one of its members. - * It is only valid to call this method at most once per instance. - * - * @param annotations non-null; annotations to set for this class - */ - public void setClassAnnotations(Annotations annotations) { - annotationsDirectory.setClassAnnotations(annotations); - } - - /** - * Adds a field annotations item to this class. - * - * @param field non-null; field in question - * @param annotations non-null; associated annotations to add - */ - public void addFieldAnnotations(CstFieldRef field, - Annotations annotations) { - annotationsDirectory.addFieldAnnotations(field, annotations); - } - - /** - * Adds a method annotations item to this class. - * - * @param method non-null; method in question - * @param annotations non-null; associated annotations to add - */ - public void addMethodAnnotations(CstMethodRef method, - Annotations annotations) { - annotationsDirectory.addMethodAnnotations(method, annotations); - } - - /** - * Adds a parameter annotations item to this class. - * - * @param method non-null; method in question - * @param list non-null; associated list of annotation sets to add - */ - public void addParameterAnnotations(CstMethodRef method, - AnnotationsList list) { - annotationsDirectory.addParameterAnnotations(method, list); - } - - /** - * Gets the method annotations for a given method, if any. This is - * meant for use by debugging / dumping code. - * - * @param method non-null; the method - * @return null-ok; the method annotations, if any - */ - public Annotations getMethodAnnotations(CstMethodRef method) { - return annotationsDirectory.getMethodAnnotations(method); - } - - /** - * Gets the parameter annotations for a given method, if any. This is - * meant for use by debugging / dumping code. - * - * @param method non-null; the method - * @return null-ok; the parameter annotations, if any - */ - public AnnotationsList getParameterAnnotations(CstMethodRef method) { - return annotationsDirectory.getParameterAnnotations(method); - } - - /** - * Prints out the contents of this instance, in a debugging-friendly - * way. - * - * @param out non-null; where to output to - * @param verbose whether to be verbose with the output - */ - public void debugPrint(Writer out, boolean verbose) { - PrintWriter pw = Writers.printWriterFor(out); - - pw.println(getClass().getName() + " {"); - pw.println(" accessFlags: " + Hex.u2(accessFlags)); - pw.println(" superclass: " + superclass); - pw.println(" interfaces: " + - ((interfaces == null) ? "<none>" : interfaces)); - pw.println(" sourceFile: " + - ((sourceFile == null) ? "<none>" : sourceFile.toQuoted())); - - classData.debugPrint(out, verbose); - annotationsDirectory.debugPrint(pw); - - pw.println("}"); - } -} diff --git a/dx/src/com/android/dx/dex/file/ClassDefsSection.java b/dx/src/com/android/dx/dex/file/ClassDefsSection.java deleted file mode 100644 index cf61b4732..000000000 --- a/dx/src/com/android/dx/dex/file/ClassDefsSection.java +++ /dev/null @@ -1,187 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.dx.dex.file; - -import com.android.dx.rop.cst.Constant; -import com.android.dx.rop.cst.CstType; -import com.android.dx.rop.type.Type; -import com.android.dx.rop.type.TypeList; -import com.android.dx.util.AnnotatedOutput; -import com.android.dx.util.Hex; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.TreeMap; - -/** - * Class definitions list section of a <code>.dex</code> file. - */ -public final class ClassDefsSection extends UniformItemSection { - /** - * non-null; map from type constants for classes to {@link - * ClassDefItem} instances that define those classes - */ - private final TreeMap<Type, ClassDefItem> classDefs; - - /** null-ok; ordered list of classes; set in {@link #orderItems} */ - private ArrayList<ClassDefItem> orderedDefs; - - /** - * Constructs an instance. The file offset is initially unknown. - * - * @param file non-null; file that this instance is part of - */ - public ClassDefsSection(DexFile file) { - super("class_defs", file, 4); - - classDefs = new TreeMap<Type, ClassDefItem>(); - orderedDefs = null; - } - - /** {@inheritDoc} */ - @Override - public Collection<? extends Item> items() { - if (orderedDefs != null) { - return orderedDefs; - } - - return classDefs.values(); - } - - /** {@inheritDoc} */ - @Override - public IndexedItem get(Constant cst) { - if (cst == null) { - throw new NullPointerException("cst == null"); - } - - throwIfNotPrepared(); - - Type type = ((CstType) cst).getClassType(); - IndexedItem result = classDefs.get(type); - - if (result == null) { - throw new IllegalArgumentException("not found"); - } - - return result; - } - - /** - * Writes the portion of the file header that refers to this instance. - * - * @param out non-null; where to write - */ - public void writeHeaderPart(AnnotatedOutput out) { - throwIfNotPrepared(); - - int sz = classDefs.size(); - int offset = (sz == 0) ? 0 : getFileOffset(); - - if (out.annotates()) { - out.annotate(4, "class_defs_size: " + Hex.u4(sz)); - out.annotate(4, "class_defs_off: " + Hex.u4(offset)); - } - - out.writeInt(sz); - out.writeInt(offset); - } - - /** - * Adds an element to this instance. It is illegal to attempt to add more - * than one class with the same name. - * - * @param clazz non-null; the class def to add - */ - public void add(ClassDefItem clazz) { - Type type; - - try { - type = clazz.getThisClass().getClassType(); - } catch (NullPointerException ex) { - // Elucidate the exception. - throw new NullPointerException("clazz == null"); - } - - throwIfPrepared(); - - if (classDefs.get(type) != null) { - throw new IllegalArgumentException("already added: " + type); - } - - classDefs.put(type, clazz); - } - - /** {@inheritDoc} */ - @Override - protected void orderItems() { - int sz = classDefs.size(); - int idx = 0; - - orderedDefs = new ArrayList<ClassDefItem>(sz); - - /* - * Iterate over all the classes, recursively assigning an - * index to each, implicitly skipping the ones that have - * already been assigned by the time this (top-level) - * iteration reaches them. - */ - for (Type type : classDefs.keySet()) { - idx = orderItems0(type, idx, sz - idx); - } - } - - /** - * Helper for {@link #orderItems}, which recursively assigns indices - * to classes. - * - * @param type null-ok; type ref to assign, if any - * @param idx >= 0; the next index to assign - * @param maxDepth maximum recursion depth; if negative, this will - * throw an exception indicating class definition circularity - * @return >= 0; the next index to assign - */ - private int orderItems0(Type type, int idx, int maxDepth) { - ClassDefItem c = classDefs.get(type); - - if ((c == null) || (c.hasIndex())) { - return idx; - } - - if (maxDepth < 0) { - throw new RuntimeException("class circularity with " + type); - } - - maxDepth--; - - CstType superclassCst = c.getSuperclass(); - if (superclassCst != null) { - Type superclass = superclassCst.getClassType(); - idx = orderItems0(superclass, idx, maxDepth); - } - - TypeList interfaces = c.getInterfaces(); - int sz = interfaces.size(); - for (int i = 0; i < sz; i++) { - idx = orderItems0(interfaces.getType(i), idx, maxDepth); - } - - c.setIndex(idx); - orderedDefs.add(c); - return idx + 1; - } -} diff --git a/dx/src/com/android/dx/dex/file/CodeItem.java b/dx/src/com/android/dx/dex/file/CodeItem.java deleted file mode 100644 index dc0bb5272..000000000 --- a/dx/src/com/android/dx/dex/file/CodeItem.java +++ /dev/null @@ -1,335 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.dx.dex.file; - -import com.android.dx.dex.code.CstInsn; -import com.android.dx.dex.code.CatchTable; -import com.android.dx.dex.code.DalvCode; -import com.android.dx.dex.code.DalvInsn; -import com.android.dx.dex.code.DalvInsnList; -import com.android.dx.dex.code.LocalList; -import com.android.dx.dex.code.PositionList; -import com.android.dx.rop.cst.Constant; -import com.android.dx.rop.cst.CstMemberRef; -import com.android.dx.rop.cst.CstMethodRef; -import com.android.dx.rop.cst.CstType; -import com.android.dx.rop.type.StdTypeList; -import com.android.dx.rop.type.Type; -import com.android.dx.rop.type.TypeList; -import com.android.dx.util.AnnotatedOutput; -import com.android.dx.util.ExceptionWithContext; -import com.android.dx.util.Hex; - -import java.io.PrintWriter; -import java.util.HashSet; - -/** - * Representation of all the parts needed for concrete methods in a - * <code>dex</code> file. - */ -public final class CodeItem extends OffsettedItem { - /** file alignment of this class, in bytes */ - private static final int ALIGNMENT = 4; - - /** write size of the header of this class, in bytes */ - private static final int HEADER_SIZE = 16; - - /** non-null; method that this code implements */ - private final CstMethodRef ref; - - /** non-null; the bytecode instructions and associated data */ - private final DalvCode code; - - /** null-ok; the catches, if needed; set in {@link #addContents} */ - private CatchStructs catches; - - /** whether this instance is for a <code>static</code> method */ - private final boolean isStatic; - - /** - * non-null; list of possibly-thrown exceptions; just used in - * generating debugging output (listings) - */ - private final TypeList throwsList; - - /** - * null-ok; the debug info or <code>null</code> if there is none; - * set in {@link #addContents} - */ - private DebugInfoItem debugInfo; - - /** - * Constructs an instance. - * - * @param ref non-null; method that this code implements - * @param code non-null; the underlying code - * @param isStatic whether this instance is for a <code>static</code> - * method - * @param throwsList non-null; list of possibly-thrown exceptions, - * just used in generating debugging output (listings) - */ - public CodeItem(CstMethodRef ref, DalvCode code, boolean isStatic, - TypeList throwsList) { - super(ALIGNMENT, -1); - - if (ref == null) { - throw new NullPointerException("ref == null"); - } - - if (code == null) { - throw new NullPointerException("code == null"); - } - - if (throwsList == null) { - throw new NullPointerException("throwsList == null"); - } - - this.ref = ref; - this.code = code; - this.isStatic = isStatic; - this.throwsList = throwsList; - this.catches = null; - this.debugInfo = null; - } - - /** {@inheritDoc} */ - @Override - public ItemType itemType() { - return ItemType.TYPE_CODE_ITEM; - } - - /** {@inheritDoc} */ - public void addContents(DexFile file) { - MixedItemSection wordData = file.getWordData(); - MixedItemSection byteData = file.getByteData(); - TypeIdsSection typeIds = file.getTypeIds(); - - if (code.hasPositions() || code.hasLocals()) { - debugInfo = new DebugInfoItem(code, isStatic, ref); - byteData.add(debugInfo); - } - - if (code.hasAnyCatches()) { - for (Type type : code.getCatchTypes()) { - typeIds.intern(type); - } - catches = new CatchStructs(code); - } - - for (Constant c : code.getInsnConstants()) { - file.internIfAppropriate(c); - } - } - - /** {@inheritDoc} */ - @Override - public String toString() { - return "CodeItem{" + toHuman() + "}"; - } - - /** {@inheritDoc} */ - @Override - public String toHuman() { - return ref.toHuman(); - } - - /** - * Gets the reference to the method this instance implements. - * - * @return non-null; the method reference - */ - public CstMethodRef getRef() { - return ref; - } - - /** - * Does a human-friendly dump of this instance. - * - * @param out non-null; where to dump - * @param prefix non-null; per-line prefix to use - * @param verbose whether to be verbose with the output - */ - public void debugPrint(PrintWriter out, String prefix, boolean verbose) { - out.println(ref.toHuman() + ":"); - - DalvInsnList insns = code.getInsns(); - out.println("regs: " + Hex.u2(getRegistersSize()) + - "; ins: " + Hex.u2(getInsSize()) + "; outs: " + - Hex.u2(getOutsSize())); - - insns.debugPrint(out, prefix, verbose); - - String prefix2 = prefix + " "; - - if (catches != null) { - out.print(prefix); - out.println("catches"); - catches.debugPrint(out, prefix2); - } - - if (debugInfo != null) { - out.print(prefix); - out.println("debug info"); - debugInfo.debugPrint(out, prefix2); - } - } - - /** {@inheritDoc} */ - @Override - protected void place0(Section addedTo, int offset) { - final DexFile file = addedTo.getFile(); - int catchesSize; - - /* - * In order to get the catches and insns, all the code's - * constants need to be assigned indices. - */ - code.assignIndices(new DalvCode.AssignIndicesCallback() { - public int getIndex(Constant cst) { - IndexedItem item = file.findItemOrNull(cst); - if (item == null) { - return -1; - } - return item.getIndex(); - } - }); - - if (catches != null) { - catches.encode(file); - catchesSize = catches.writeSize(); - } else { - catchesSize = 0; - } - - /* - * The write size includes the header, two bytes per code - * unit, post-code padding if necessary, and however much - * space the catches need. - */ - - int insnsSize = code.getInsns().codeSize(); - if ((insnsSize & 1) != 0) { - insnsSize++; - } - - setWriteSize(HEADER_SIZE + (insnsSize * 2) + catchesSize); - } - - /** {@inheritDoc} */ - @Override - protected void writeTo0(DexFile file, AnnotatedOutput out) { - boolean annotates = out.annotates(); - int regSz = getRegistersSize(); - int outsSz = getOutsSize(); - int insSz = getInsSize(); - int insnsSz = code.getInsns().codeSize(); - boolean needPadding = (insnsSz & 1) != 0; - int triesSz = (catches == null) ? 0 : catches.triesSize(); - int debugOff = (debugInfo == null) ? 0 : debugInfo.getAbsoluteOffset(); - - if (annotates) { - out.annotate(0, offsetString() + ' ' + ref.toHuman()); - out.annotate(2, " registers_size: " + Hex.u2(regSz)); - out.annotate(2, " ins_size: " + Hex.u2(insSz)); - out.annotate(2, " outs_size: " + Hex.u2(outsSz)); - out.annotate(2, " tries_size: " + Hex.u2(triesSz)); - out.annotate(4, " debug_off: " + Hex.u4(debugOff)); - out.annotate(4, " insns_size: " + Hex.u4(insnsSz)); - - // This isn't represented directly here, but it is useful to see. - int size = throwsList.size(); - if (size != 0) { - out.annotate(0, " throws " + StdTypeList.toHuman(throwsList)); - } - } - - out.writeShort(regSz); - out.writeShort(insSz); - out.writeShort(outsSz); - out.writeShort(triesSz); - out.writeInt(debugOff); - out.writeInt(insnsSz); - - writeCodes(file, out); - - if (catches != null) { - if (needPadding) { - if (annotates) { - out.annotate(2, " padding: 0"); - } - out.writeShort(0); - } - - catches.writeTo(file, out); - } - - if (annotates) { - /* - * These are pointed at in the code header (above), but it's less - * distracting to expand on them at the bottom of the code. - */ - if (debugInfo != null) { - out.annotate(0, " debug info"); - debugInfo.annotateTo(file, out, " "); - } - } - } - - /** - * Helper for {@link #writeTo0} which writes out the actual bytecode. - * - * @param file non-null; file we are part of - * @param out non-null; where to write to - */ - private void writeCodes(DexFile file, AnnotatedOutput out) { - DalvInsnList insns = code.getInsns(); - - try { - insns.writeTo(out); - } catch (RuntimeException ex) { - throw ExceptionWithContext.withContext(ex, "...while writing " + - "instructions for " + ref.toHuman()); - } - } - - /** - * Get the in registers count. - * - * @return the count - */ - private int getInsSize() { - return ref.getParameterWordCount(isStatic); - } - - /** - * Get the out registers count. - * - * @return the count - */ - private int getOutsSize() { - return code.getInsns().getOutsSize(); - } - - /** - * Get the total registers count. - * - * @return the count - */ - private int getRegistersSize() { - return code.getInsns().getRegistersSize(); - } -} diff --git a/dx/src/com/android/dx/dex/file/DebugInfoConstants.java b/dx/src/com/android/dx/dex/file/DebugInfoConstants.java deleted file mode 100644 index 010acb434..000000000 --- a/dx/src/com/android/dx/dex/file/DebugInfoConstants.java +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.dx.dex.file; - -/** - * Constants for the dex debug info state machine format. - */ -public interface DebugInfoConstants { - - /* - * normal opcodes - */ - - /** - * Terminates a debug info sequence for a method.<p> - * Args: none - * - */ - static final int DBG_END_SEQUENCE = 0x00; - - /** - * Advances the program counter/address register without emitting - * a positions entry.<p> - * - * Args: - * <ol> - * <li>Unsigned LEB128 — amount to advance pc by - * </ol> - */ - static final int DBG_ADVANCE_PC = 0x01; - - /** - * Advances the line register without emitting - * a positions entry.<p> - * - * Args: - * <ol> - * <li>Signed LEB128 — amount to change line register by. - * </ol> - */ - static final int DBG_ADVANCE_LINE = 0x02; - - /** - * Introduces a local variable at the current address.<p> - * - * Args: - * <ol> - * <li>Unsigned LEB128 — register that will contain local. - * <li>Unsigned LEB128 — string index (shifted by 1) of local name. - * <li>Unsigned LEB128 — type index (shifted by 1) of type. - * </ol> - */ - static final int DBG_START_LOCAL = 0x03; - - /** - * Introduces a local variable at the current address with a type - * signature specified.<p> - * - * Args: - * <ol> - * <li>Unsigned LEB128 — register that will contain local. - * <li>Unsigned LEB128 — string index (shifted by 1) of local name. - * <li>Unsigned LEB128 — type index (shifted by 1) of type. - * <li>Unsigned LEB128 — string index (shifted by 1) of - * type signature. - * </ol> - */ - static final int DBG_START_LOCAL_EXTENDED = 0x04; - - /** - * Marks a currently-live local variable as out of scope at the - * current address.<p> - * - * Args: - * <ol> - * <li>Unsigned LEB128 — register that contained local - * </ol> - */ - static final int DBG_END_LOCAL = 0x05; - - /** - * Re-introduces a local variable at the current address. The name - * and type are the same as the last local that was live in the specified - * register.<p> - * - * Args: - * <ol> - * <li>Unsigned LEB128 — register to re-start. - * </ol> - */ - static final int DBG_RESTART_LOCAL = 0x06; - - - /** - * Sets the "prologue_end" state machine register, indicating that the - * next position entry that is added should be considered the end of - * a method prologue (an appropriate place for a method breakpoint).<p> - * - * The prologue_end register is cleared by any special (>= OPCODE_BASE) - * opcode. - */ - static final int DBG_SET_PROLOGUE_END = 0x07; - - /** - * Sets the "epilogue_begin" state machine register, indicating that the - * next position entry that is added should be considered the beginning of - * a method epilogue (an appropriate place to suspend execution before - * method exit).<p> - * - * The epilogue_begin register is cleared by any special (>= OPCODE_BASE) - * opcode. - */ - static final int DBG_SET_EPILOGUE_BEGIN = 0x08; - - /** - * Sets the current file that that line numbers refer to. All subsequent - * line number entries make reference to this source file name, instead - * of the default name specified in code_item. - * - * Args: - * <ol> - * <li>Unsigned LEB128 — string index (shifted by 1) of source - * file name. - * </ol> - */ - static final int DBG_SET_FILE = 0x09; - - /* IF YOU ADD A NEW OPCODE, increase OPCODE_BASE */ - - /* - * "special opcode" configuration, essentially what's found in - * the line number program header in DWARFv3, Section 6.2.4 - */ - - /** the smallest value a special opcode can take */ - static final int DBG_FIRST_SPECIAL = 0x0a; - static final int DBG_LINE_BASE = -4; - static final int DBG_LINE_RANGE = 15; - // MIN_INSN_LENGTH is always 1 -} diff --git a/dx/src/com/android/dx/dex/file/DebugInfoDecoder.java b/dx/src/com/android/dx/dex/file/DebugInfoDecoder.java deleted file mode 100644 index 519452b64..000000000 --- a/dx/src/com/android/dx/dex/file/DebugInfoDecoder.java +++ /dev/null @@ -1,563 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.dx.dex.file; - -import com.android.dx.dex.code.LocalList; -import com.android.dx.dex.code.PositionList; -import com.android.dx.rop.cst.CstMethodRef; -import com.android.dx.rop.cst.CstUtf8; -import com.android.dx.rop.type.Prototype; -import com.android.dx.rop.type.StdTypeList; -import com.android.dx.rop.type.Type; -import com.android.dx.util.ExceptionWithContext; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.List; - -import static com.android.dx.dex.file.DebugInfoConstants.*; - -/** - * A decoder for the dex debug info state machine format. - * This code exists mostly as a reference implementation and test for - * for the <code>DebugInfoEncoder</code> - */ -public class DebugInfoDecoder { - /** encoded debug info */ - private final byte[] encoded; - /** positions decoded */ - private final ArrayList<PositionEntry> positions; - /** locals decoded */ - private final ArrayList<LocalEntry> locals; - /** size of code block in code units */ - private final int codesize; - /** indexed by register, the last local variable live in a reg */ - private final LocalEntry[] lastEntryForReg; - /** method descriptor of method this debug info is for */ - private final Prototype desc; - /** true if method is static */ - private final boolean isStatic; - /** dex file this debug info will be stored in */ - private final DexFile file; - /** - * register size, in register units, of the register space - * used by this method - */ - private final int regSize; - - /** current decoding state: line number */ - private int line = 1; - - /** current decoding state: bytecode address */ - private int address = 0; - - /** string index of the string "this" */ - private final int thisStringIdx; - - /** - * Constructs an instance. - * - * @param encoded encoded debug info - * @param codesize size of code block in code units - * @param regSize register size, in register units, of the register space - * used by this method - * @param isStatic true if method is static - * @param ref method descriptor of method this debug info is for - * @param file dex file this debug info will be stored in - */ - DebugInfoDecoder (byte[] encoded, int codesize, int regSize, - boolean isStatic, CstMethodRef ref, DexFile file) { - - this.encoded = encoded; - this.isStatic = isStatic; - this.desc = ref.getPrototype(); - this.file = file; - this.regSize = regSize; - - positions = new ArrayList(); - locals = new ArrayList(); - this.codesize = codesize; - lastEntryForReg = new LocalEntry[regSize]; - - thisStringIdx = file.getStringIds().indexOf(new CstUtf8("this")); - } - - /** - * An entry in the resulting postions table - */ - static class PositionEntry { - /** bytecode address */ - int address; - /** line number */ - int line; - - PositionEntry(int address, int line) { - this.address = address; - this.line = line; - } - } - - /** - * An entry in the resulting locals table - */ - static class LocalEntry { - LocalEntry(int start, int reg, int nameIndex, int typeIndex, - int signatureIndex) { - this.start = start; - this.reg = reg; - this.nameIndex = nameIndex; - this.typeIndex = typeIndex; - this.signatureIndex = signatureIndex; - } - - /** start of address range */ - int start; - - /** - * End of address range. Initialized to MAX_VALUE here but will - * be set to no more than 1 + max bytecode address of method. - */ - int end = Integer.MAX_VALUE; - - /** register number */ - int reg; - - /** index of name in strings table */ - int nameIndex; - - /** index of type in types table */ - int typeIndex; - - /** index of type signature in strings table */ - int signatureIndex; - - } - - /** - * Gets the decoded positions list. - * Valid after calling <code>decode</code>. - * - * @return positions list in ascending address order. - */ - public List<PositionEntry> getPositionList() { - return positions; - } - - /** - * Gets the decoded locals list, in ascending start-address order. - * Valid after calling <code>decode</code>. - * - * @return locals list in ascending address order. - */ - public List<LocalEntry> getLocals() { - // TODO move this loop: - // Any variable that didnt end ends now - for (LocalEntry local: locals) { - if (local.end == Integer.MAX_VALUE) { - local.end = codesize; - } - } - return locals; - } - - /** - * Decodes the debug info sequence. - */ - public void decode() { - try { - decode0(); - } catch (Exception ex) { - throw ExceptionWithContext.withContext(ex, - "...while decoding debug info"); - } - } - - /** - * Reads a string index. String indicies are offset by 1, and a 0 value - * in the stream (-1 as returned by this method) means "null" - * - * @param bs - * @return index into file's string ids table, -1 means null - * @throws IOException - */ - private int readStringIndex(InputStream bs) throws IOException { - int offsetIndex = readUnsignedLeb128(bs); - - return offsetIndex - 1; - } - - /** - * Gets the register that begins the method's parameter range (including - * the 'this' parameter for non-static methods). The range continues until - * <code>regSize</code> - * - * @return register as noted above. - */ - private int getParamBase() { - return regSize - - desc.getParameterTypes().getWordCount() - (isStatic? 0 : 1); - } - - private void decode0() throws IOException { - ByteArrayInputStream bs = new ByteArrayInputStream(encoded); - - line = readUnsignedLeb128(bs); - int szParams = readUnsignedLeb128(bs); - StdTypeList params = desc.getParameterTypes(); - int curReg = getParamBase(); - - if (szParams != params.size()) { - throw new RuntimeException( - "Mismatch between parameters_size and prototype"); - } - - if (!isStatic) { - // Start off with implicit 'this' entry - LocalEntry thisEntry - = new LocalEntry(0, curReg, thisStringIdx, 0, 0); - locals.add(thisEntry); - lastEntryForReg[curReg] = thisEntry; - curReg++; - } - - for (int i = 0; i < szParams; i++) { - Type paramType = params.getType(i); - LocalEntry le; - - int nameIdx = readStringIndex(bs); - - if(nameIdx == -1) { - // unnamed parameter - } else { - // final '0' should be idx of paramType.getDescriptor() - le = new LocalEntry(0, curReg, nameIdx, 0, 0); - locals.add(le); - lastEntryForReg[curReg] = le; - } - - curReg += paramType.getCategory(); - } - - for (;;) { - int opcode = bs.read(); - - if (opcode < 0) { - throw new RuntimeException - ("Reached end of debug stream without " - + "encountering end marker"); - } - - switch (opcode) { - case DBG_START_LOCAL: { - int reg = readUnsignedLeb128(bs); - int nameIdx = readStringIndex(bs); - int typeIdx = readStringIndex(bs); - LocalEntry le = new LocalEntry( - address, reg, nameIdx, typeIdx, 0); - - // a "start" is implicitly the "end" of whatever was - // previously defined in the register - if (lastEntryForReg[reg] != null - && lastEntryForReg[reg].end == Integer.MAX_VALUE) { - - lastEntryForReg[reg].end = address; - } - - locals.add(le); - lastEntryForReg[reg] = le; - } - break; - - case DBG_START_LOCAL_EXTENDED: { - int reg = readUnsignedLeb128(bs); - int nameIdx = readStringIndex(bs); - int typeIdx = readStringIndex(bs); - int sigIdx = readStringIndex(bs); - LocalEntry le = new LocalEntry( - address, reg, nameIdx, typeIdx, sigIdx); - - // a "start" is implicitly the "end" of whatever was - // previously defined in the register - if (lastEntryForReg[reg] != null - && lastEntryForReg[reg].end == Integer.MAX_VALUE) { - - lastEntryForReg[reg].end = address; - - // A 0-length entry. Almost certainly a "this" - // with a signature. - if (lastEntryForReg[reg].start == address) { - locals.remove(lastEntryForReg[reg]); - } - } - - locals.add(le); - lastEntryForReg[reg] = le; - } - break; - - case DBG_RESTART_LOCAL: { - int reg = readUnsignedLeb128(bs); - LocalEntry prevle; - LocalEntry le; - - try { - prevle = lastEntryForReg[reg]; - - if (lastEntryForReg[reg].end == Integer.MAX_VALUE) { - throw new RuntimeException ("nonsensical " - + "RESTART_LOCAL on live register v"+reg); - } - le = new LocalEntry(address, reg, - prevle.nameIndex, prevle.typeIndex, 0); - - } catch (NullPointerException ex) { - throw new RuntimeException - ("Encountered RESTART_LOCAL on new v" +reg); - } - - locals.add(le); - lastEntryForReg[reg] = le; - } - break; - - case DBG_END_LOCAL: { - int reg = readUnsignedLeb128(bs); - boolean found = false; - for (int i = locals.size() - 1; i >= 0; i--) { - if (locals.get(i).reg == reg) { - locals.get(i).end = address; - found = true; - break; - } - } - - if (!found) { - throw new RuntimeException( - "Encountered LOCAL_END without local start: v" - + reg); - } - } - break; - - case DBG_END_SEQUENCE: - // all done - return; - - case DBG_ADVANCE_PC: - address += readUnsignedLeb128(bs); - break; - - case DBG_ADVANCE_LINE: - line += readSignedLeb128(bs); - break; - - case DBG_SET_PROLOGUE_END: - //TODO do something with this. - break; - - case DBG_SET_EPILOGUE_BEGIN: - //TODO do something with this. - break; - - case DBG_SET_FILE: - //TODO do something with this. - break; - - default: - if (opcode < DBG_FIRST_SPECIAL) { - throw new RuntimeException( - "Invalid extended opcode encountered " - + opcode); - } - - int adjopcode = opcode - DBG_FIRST_SPECIAL; - - address += adjopcode / DBG_LINE_RANGE; - line += DBG_LINE_BASE + (adjopcode % DBG_LINE_RANGE); - - positions.add(new PositionEntry(address, line)); - break; - - } - } - } - - /** - * Validates an encoded debug info stream against data used to encode it, - * throwing an exception if they do not match. Used to validate the - * encoder. - * - * @param linecodes encoded debug info - * @param codeSize size of insn block in code units - * @param countRegisters size of used register block in register units - * @param pl position list to verify against - * @param ll locals list to verify against. - */ - public static void validateEncode(byte[] linecodes, int codeSize, - int countRegisters, PositionList pl, LocalList ll, - boolean isStatic, CstMethodRef ref, DexFile file) { - - try { - validateEncode0(linecodes, codeSize, countRegisters, - isStatic, ref, file, pl, ll); - } catch (RuntimeException ex) { -// System.err.println(ex.toString() -// + " while processing " + ref.toHuman()); - throw ExceptionWithContext.withContext(ex, - "while processing " + ref.toHuman()); - } - } - - - private static void validateEncode0(byte[] linecodes, int codeSize, - int countRegisters, boolean isStatic, CstMethodRef ref, - DexFile file, PositionList pl, LocalList ll) { - DebugInfoDecoder decoder - = new DebugInfoDecoder(linecodes, codeSize, countRegisters, - isStatic, ref, file); - - decoder.decode(); - - List<PositionEntry> decodedEntries; - - decodedEntries = decoder.getPositionList(); - - if (decodedEntries.size() != pl.size()) { - throw new RuntimeException( - "Decoded positions table not same size was " - + decodedEntries.size() + " expected " + pl.size()); - } - - for (PositionEntry entry: decodedEntries) { - boolean found = false; - for (int i = pl.size() - 1; i >= 0; i--) { - PositionList.Entry ple = pl.get(i); - - if (entry.line == ple.getPosition().getLine() - && entry.address == ple.getAddress()) { - found = true; - break; - } - } - - if (!found) { - throw new RuntimeException ("Could not match position entry: " - + entry.address + ", " + entry.line); - } - } - - List<LocalEntry> decodedLocals; - - decodedLocals = decoder.getLocals(); - - int paramBase = decoder.getParamBase(); - - int matchedLocalsEntries = 0; - - for (LocalEntry entry: decodedLocals) { - boolean found = false; - for (int i = ll.size() - 1; i >= 0; i--) { - LocalList.Entry le = ll.get(i); - - /* - * If an entry is a method parameter, then the original - * entry may not be marked as starting at 0. However, the - * end address should still match. - */ - if ((entry.start == le.getStart() - || (entry.start == 0 && entry.reg >= paramBase)) - && entry.end == le.getEnd() - && entry.reg == le.getRegister()) { - found = true; - matchedLocalsEntries++; - break; - } - } - - if (!found) { - throw new RuntimeException("Could not match local entry"); - } - } - - if (matchedLocalsEntries != ll.size()) { - throw new RuntimeException("Locals tables did not match"); - } - } - - /** - * Reads a DWARFv3-style signed LEB128 integer to the specified stream. - * See DWARF v3 section 7.6. An invalid sequence produces an IOException. - * - * @param bs stream to input from - * @return read value - * @throws IOException on invalid sequence in addition to - * those caused by the InputStream - */ - public static int readSignedLeb128(InputStream bs) throws IOException { - int result = 0; - int cur; - int count = 0; - int signBits = -1; - - do { - cur = bs.read(); - result |= (cur & 0x7f) << (count * 7); - signBits <<= 7; - count++; - } while (((cur & 0x80) == 0x80) && count < 5); - - if ((cur & 0x80) == 0x80) { - throw new IOException ("invalid LEB128 sequence"); - } - - // Sign extend if appropriate - if (((signBits >> 1) & result) != 0 ) { - result |= signBits; - } - - return result; - } - - /** - * Reads a DWARFv3-style unsigned LEB128 integer to the specified stream. - * See DWARF v3 section 7.6. An invalid sequence produces an IOException. - * - * @param bs stream to input from - * @return read value, which should be treated as an unsigned value. - * @throws IOException on invalid sequence in addition to - * those caused by the InputStream - */ - public static int readUnsignedLeb128(InputStream bs) throws IOException { - int result = 0; - int cur; - int count = 0; - - do { - cur = bs.read(); - result |= (cur & 0x7f) << (count * 7); - count++; - } while (((cur & 0x80) == 0x80) && count < 5); - - if ((cur & 0x80) == 0x80) { - throw new IOException ("invalid LEB128 sequence"); - } - - return result; - } -} diff --git a/dx/src/com/android/dx/dex/file/DebugInfoEncoder.java b/dx/src/com/android/dx/dex/file/DebugInfoEncoder.java deleted file mode 100644 index 49781bdd8..000000000 --- a/dx/src/com/android/dx/dex/file/DebugInfoEncoder.java +++ /dev/null @@ -1,1035 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.dx.dex.file; - -import com.android.dx.dex.code.LocalList; -import com.android.dx.dex.code.PositionList; -import com.android.dx.rop.code.RegisterSpec; -import com.android.dx.rop.code.SourcePosition; -import com.android.dx.rop.cst.CstMethodRef; -import com.android.dx.rop.cst.CstType; -import com.android.dx.rop.cst.CstUtf8; -import com.android.dx.rop.type.Prototype; -import com.android.dx.rop.type.StdTypeList; -import com.android.dx.rop.type.Type; -import com.android.dx.util.ByteArrayAnnotatedOutput; -import com.android.dx.util.AnnotatedOutput; -import com.android.dx.util.ExceptionWithContext; - -import java.io.IOException; -import java.io.PrintWriter; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.BitSet; - -import static com.android.dx.dex.file.DebugInfoConstants.*; - -/** - * An encoder for the dex debug info state machine format. The format - * for each method enrty is as follows: - * <ol> - * <li> signed LEB128: initial value for line register. - * <li> n instances of signed LEB128: string indicies (offset by 1) - * for each method argument in left-to-right order - * with <code>this</code> excluded. A value of '0' indicates "no name" - * <li> A sequence of special or normal opcodes as defined in - * <code>DebugInfoConstants</code>. - * <li> A single terminating <code>OP_END_SEQUENCE</code> - * </ol> - */ -public final class DebugInfoEncoder { - private static final boolean DEBUG = false; - - /** null-ok; positions (line numbers) to encode */ - private final PositionList positionlist; - - /** null-ok; local variables to encode */ - private final LocalList locallist; - - private final ByteArrayAnnotatedOutput output; - private final DexFile file; - private final int codeSize; - private final int regSize; - - private final Prototype desc; - private final boolean isStatic; - - /** current encoding state: bytecode address */ - private int address = 0; - - /** current encoding state: line number */ - private int line = 1; - - /** - * if non-null: the output to write annotations to. No normal - * output is written to this. - */ - private AnnotatedOutput annotateTo; - - /** if non-null: another possible output for annotations */ - private PrintWriter debugPrint; - - /** if non-null: the prefix for each annotation or debugPrint line */ - private String prefix; - - /** true if output should be consumed during annotation */ - private boolean shouldConsume; - - /** indexed by register; last local alive in register */ - private final LocalList.Entry[] lastEntryForReg; - - /** - * Creates an instance. - * - * @param pl null-ok; positions (line numbers) to encode - * @param ll null-ok; local variables to encode - * @param file null-ok; may only be <code>null</code> if simply using - * this class to do a debug print - * @param codeSize - * @param regSize - * @param isStatic - * @param ref - */ - public DebugInfoEncoder(PositionList pl, LocalList ll, - DexFile file, int codeSize, int regSize, - boolean isStatic, CstMethodRef ref) { - this.positionlist = pl; - this.locallist = ll; - this.file = file; - output = new ByteArrayAnnotatedOutput(); - this.desc = ref.getPrototype(); - this.isStatic = isStatic; - - this.codeSize = codeSize; - this.regSize = regSize; - - lastEntryForReg = new LocalList.Entry[regSize]; - } - - /** - * Annotates or writes a message to the <code>debugPrint</code> writer - * if applicable. - * - * @param length the number of bytes associated with this message - * @param message the message itself - */ - private void annotate(int length, String message) { - if (prefix != null) { - message = prefix + message; - } - - if (annotateTo != null) { - annotateTo.annotate(shouldConsume ? length : 0, message); - } - - if (debugPrint != null) { - debugPrint.println(message); - } - } - - /** - * Converts this (PositionList, LocalList) pair into a state machine - * sequence. - * - * @return encoded byte sequence without padding and - * terminated with a <code>'\00'</code> - */ - public byte[] convert() { - try { - byte[] ret; - ret = convert0(); - - if (DEBUG) { - for (int i = 0 ; i < ret.length; i++) { - System.err.printf("byte %02x\n", (0xff & ret[i])); - } - } - - return ret; - } catch (IOException ex) { - throw ExceptionWithContext - .withContext(ex, "...while encoding debug info"); - } - } - - /** - * Converts and produces annotations on a stream. Does not write - * actual bits to the <code>AnnotatedOutput</code>. - * - * @param prefix null-ok; prefix to attach to each line of output - * @param debugPrint null-ok; if specified, an alternate output for - * annotations - * @param out null-ok; if specified, where annotations should go - * @param consume whether to claim to have consumed output for - * <code>out</code> - * @return output sequence - */ - public byte[] convertAndAnnotate(String prefix, PrintWriter debugPrint, - AnnotatedOutput out, boolean consume) { - this.prefix = prefix; - this.debugPrint = debugPrint; - annotateTo = out; - shouldConsume = consume; - - byte[] result = convert(); - - return result; - } - - private byte[] convert0() throws IOException { - ArrayList<PositionList.Entry> sortedPositions = buildSortedPositions(); - ArrayList<LocalList.Entry> sortedLocalsStart = buildLocalsStart(); - - // Parameter locals are removed from sortedLocalsStart here. - ArrayList<LocalList.Entry> methodArgs - = extractMethodArguments(sortedLocalsStart); - - ArrayList<LocalList.Entry> sortedLocalsEnd - = buildLocalsEnd(sortedLocalsStart); - - emitHeader(sortedPositions, methodArgs); - - // TODO: Make this mark the actual prologue end. - output.writeByte(DBG_SET_PROLOGUE_END); - - if (annotateTo != null || debugPrint != null) { - annotate(1, String.format("%04x: prologue end",address)); - } - - int szp = sortedPositions.size(); - int szl = sortedLocalsStart.size(); - - // Current index in sortedPositions - int curp = 0; - // Current index in sortedLocalsStart - int curls = 0; - // Current index in sortedLocalsEnd - int curle = 0; - - for (;;) { - /* - * Emit any information for the current address. - */ - - curle = emitLocalEndsAtAddress(curle, sortedLocalsEnd, curls, - sortedLocalsStart); - - /* - * Our locals-sorted-by-range-end has reached the end - * of the code block. Ignore everything else. - */ - if (address == codeSize) { - curle = szl; - } - - curls = emitLocalStartsAtAddress(curls, sortedLocalsStart); - - curp = emitPositionsAtAddress(curp, sortedPositions); - - /* - * Figure out what the next important address is. - */ - - int nextAddrLS = Integer.MAX_VALUE; // local start - int nextAddrLE = Integer.MAX_VALUE; // local end - int nextAddrP = Integer.MAX_VALUE; // position (line number) - - if (curls < szl) { - nextAddrLS = sortedLocalsStart.get(curls).getStart(); - } - - if (curle < szl) { - nextAddrLE = sortedLocalsEnd.get(curle).getEnd(); - } - - if (curp < szp) { - nextAddrP = sortedPositions.get(curp).getAddress(); - } - - int next = Math.min(nextAddrP, Math.min(nextAddrLS, nextAddrLE)); - - // No next important address == done. - if (next == Integer.MAX_VALUE) { - break; - } - - /* - * If the only work remaining are local ends at the end of the - * block, stop here. Those are implied anyway. - */ - if (next == codeSize - && nextAddrLS == Integer.MAX_VALUE - && nextAddrP == Integer.MAX_VALUE) { - break; - } - - if (next == nextAddrP) { - // Combined advance PC + position entry - emitPosition(sortedPositions.get(curp++)); - } else { - emitAdvancePc(next - address); - } - } - - emitEndSequence(); - - return output.toByteArray(); - } - - /** - * Emits all local ends that occur at the current <code>address</code> - * - * @param curle Current index in sortedLocalsEnd - * @param sortedLocalsEnd Locals, sorted by ascending end address - * @param curls Current index in sortedLocalsStart - * @param sortedLocalsStart Locals, sorted by ascending start address - * @return new value for <code>curle</code> - * @throws IOException - */ - private int emitLocalEndsAtAddress(int curle, - ArrayList<LocalList.Entry> sortedLocalsEnd, int curls, - ArrayList<LocalList.Entry> sortedLocalsStart) - throws IOException { - - int szl = sortedLocalsEnd.size(); - - // Ignore "local ends" at end of code. - while (curle < szl - && sortedLocalsEnd.get(curle).getEnd() == address - && address != codeSize) { - - boolean skipLocalEnd = false; - - /* - * Check to see if there's a range-start that appears at - * the same address for the same register. If so, the - * end-range is implicit so skip it. - */ - for (int j = curls; j < szl - && sortedLocalsStart.get(j).getStart() == address - ; j++) { - - if (sortedLocalsStart.get(j).getRegister() - == sortedLocalsEnd.get(curle).getRegister()) { - skipLocalEnd = true; - - if (DEBUG) { - System.err.printf("skip local end v%d\n", - sortedLocalsEnd.get(curle).getRegister()); - } - break; - } - } - - if (!skipLocalEnd) { - emitLocalEnd(sortedLocalsEnd.get(curle)); - } - - curle++; - } - return curle; - } - - /** - * Emits all local starts that occur at the current <code>address</code> - * - * @param curls Current index in sortedLocalsStart - * @param sortedLocalsStart Locals, sorted by ascending start address - * @return new value for <code>curls</code> - * @throws IOException - */ - private int emitLocalStartsAtAddress(int curls, - ArrayList<LocalList.Entry> sortedLocalsStart) - throws IOException { - - int szl = sortedLocalsStart.size(); - - while (curls < szl - && sortedLocalsStart.get(curls).getStart() == address) { - LocalList.Entry lle = sortedLocalsStart.get(curls++); - int reg = lle.getRegister(); - LocalList.Entry prevlle = lastEntryForReg[reg]; - - if (lle == prevlle) { - /* - * Here we ignore locals entries for parameters, - * which have already been represented and placed in the - * lastEntryForReg array. - */ - continue; - } - - // At this point we have a new live entry one way or another. - lastEntryForReg[reg] = lle; - - if ((prevlle != null) && lle.matches(prevlle)) { - if (prevlle.getEnd() == lle.getStart()) { - /* - * There is nothing more to do in this case: It's - * an adjacent range with the same register. The - * previous emitLocalEndsAtAddress() call skipped - * this local end, so we'll skip this local start - * as well. - */ - } else { - emitLocalRestart(lle); - } - } else { - emitLocalStart(lle); - } - } - return curls; - } - - /** - * Emits all positions that occur at the current <code>address</code> - * - * @param curp Current index in sortedPositions - * @param sortedPositions positions, sorted by ascending address - * @return new value for <code>curp</code> - * @throws IOException - */ - private int emitPositionsAtAddress(int curp, - ArrayList<PositionList.Entry> sortedPositions) - throws IOException { - - int szp = sortedPositions.size(); - while (curp < szp - && sortedPositions.get(curp).getAddress() == address) { - emitPosition(sortedPositions.get(curp++)); - } - return curp; - } - - /** - * Emits the header sequence, which consists of LEB128-encoded initial - * line number and string indicies for names of all non-"this" arguments. - * - * @param sortedPositions positions, sorted by ascending address - * @param methodArgs local list entries for method argumens arguments, - * in left-to-right order omitting "this" - * @throws IOException - */ - private void emitHeader(ArrayList<PositionList.Entry> sortedPositions, - ArrayList<LocalList.Entry> methodArgs) throws IOException { - boolean annotate = (annotateTo != null) || (debugPrint != null); - int mark = output.getCursor(); - - // Start by initializing the line number register. - if (sortedPositions.size() > 0) { - PositionList.Entry entry = sortedPositions.get(0); - line = entry.getPosition().getLine(); - } - output.writeUnsignedLeb128(line); - - if (annotate) { - annotate(output.getCursor() - mark, "line_start: " + line); - } - - int curParam = getParamBase(); - // paramTypes will not include 'this' - StdTypeList paramTypes = desc.getParameterTypes(); - int szParamTypes = paramTypes.size(); - - /* - * Initialize lastEntryForReg to have an initial - * entry for the 'this' pointer. - */ - if (!isStatic) { - for (LocalList.Entry arg: methodArgs) { - if (curParam == arg.getRegister()) { - lastEntryForReg[curParam] = arg; - break; - } - } - curParam++; - } - - // Write out the number of parameter entries that will follow. - mark = output.getCursor(); - output.writeUnsignedLeb128(szParamTypes); - - if (annotate) { - annotate(output.getCursor() - mark, - String.format("parameters_size: %04x", szParamTypes)); - } - - /* - * Then emit the string indicies of all the method parameters. - * Note that 'this', if applicable, is excluded. - */ - for (int i = 0; i < szParamTypes; i++) { - Type pt = paramTypes.get(i); - LocalList.Entry found = null; - - mark = output.getCursor(); - - for (LocalList.Entry arg: methodArgs) { - if (curParam == arg.getRegister()) { - found = arg; - - if (arg.getSignature() != null) { - /* - * Parameters with signatures will be re-emitted - * in complete as LOCAL_START_EXTENDED's below. - */ - emitStringIndex(null); - } else { - emitStringIndex(arg.getName()); - } - lastEntryForReg[curParam] = arg; - - break; - } - } - - if (found == null) { - /* - * Emit a null symbol for "unnamed." This is common - * for, e.g., synthesized methods and inner-class - * this$0 arguments. - */ - emitStringIndex(null); - } - - if (annotate) { - String parameterName - = (found == null || found.getSignature() != null) - ? "<unnamed>" : found.getName().toHuman(); - annotate(output.getCursor() - mark, - "parameter " + parameterName + " " - + RegisterSpec.PREFIX + curParam); - } - - curParam += pt.getCategory(); - } - - /* - * If anything emitted above has a type signature, emit it again as - * a LOCAL_RESTART_EXTENDED - */ - - for (LocalList.Entry arg: lastEntryForReg) { - if (arg == null) { - continue; - } - - CstUtf8 signature = arg.getSignature(); - - if (signature != null) { - emitLocalStartExtended(arg); - } - } - } - - /** - * Builds a list of position entries, sorted by ascending address. - * - * @return A sorted positions list - */ - private ArrayList<PositionList.Entry> buildSortedPositions() { - int sz = (positionlist == null) ? 0 : positionlist.size(); - ArrayList<PositionList.Entry> result = new ArrayList(sz); - - for (int i = 0; i < sz; i++) { - result.add(positionlist.get(i)); - } - - // Sort ascending by address. - Collections.sort (result, new Comparator<PositionList.Entry>() { - public int compare (PositionList.Entry a, PositionList.Entry b) { - return a.getAddress() - b.getAddress(); - } - - public boolean equals (Object obj) { - return obj == this; - } - }); - return result; - } - - /** - * Builds a list of locals entries sorted by ascending start address. - * - * @return A sorted locals list list - */ - private ArrayList<LocalList.Entry> buildLocalsStart() { - int sz = (locallist == null) ? 0 : locallist.size(); - ArrayList<LocalList.Entry> result = new ArrayList(sz); - - // Add all the entries - for (int i = 0; i < sz; i++) { - LocalList.Entry e = locallist.get(i); - result.add(locallist.get(i)); - } - - // Sort ascending by start address. - Collections.sort (result, new Comparator<LocalList.Entry>() { - public int compare (LocalList.Entry a, LocalList.Entry b) { - return a.getStart() - b.getStart(); - } - - public boolean equals (Object obj) { - return obj == this; - } - }); - return result; - } - - /** - * Builds a list of locals entries sorted by ascending end address. - * - * @param list locals list in any order - * @return a sorted locals list - */ - private ArrayList<LocalList.Entry> buildLocalsEnd( - ArrayList<LocalList.Entry> list) { - - ArrayList<LocalList.Entry> sortedLocalsEnd = new ArrayList(list); - - // Sort ascending by end address. - Collections.sort (sortedLocalsEnd, new Comparator<LocalList.Entry>() { - public int compare (LocalList.Entry a, LocalList.Entry b) { - return a.getEnd() - b.getEnd(); - } - - public boolean equals (Object obj) { - return obj == this; - } - }); - return sortedLocalsEnd; - } - - /** - * Gets the register that begins the method's parameter range (including - * the 'this' parameter for non-static methods). The range continues until - * <code>regSize</code> - * - * @return register as noted above - */ - private int getParamBase() { - return regSize - - desc.getParameterTypes().getWordCount() - (isStatic? 0 : 1); - } - - /** - * Extracts method arguments from a locals list. These will be collected - * from the input list and sorted by ascending register in the - * returned list. - * - * @param sortedLocals locals list, sorted by ascending start address, - * to process; left unmodified - * @return list of non-<code>this</code> method argument locals, - * sorted by ascending register - */ - private ArrayList<LocalList.Entry> extractMethodArguments ( - ArrayList<LocalList.Entry> sortedLocals) { - - ArrayList<LocalList.Entry> result - = new ArrayList(desc.getParameterTypes().size()); - - int argBase = getParamBase(); - - BitSet seen = new BitSet(regSize - argBase); - - int sz = sortedLocals.size(); - for (int i = 0; i < sz; i++) { - LocalList.Entry e = sortedLocals.get(i); - int reg = e.getRegister(); - - if (reg < argBase) { - continue; - } - - // only the lowest-start-address entry is included. - if (seen.get(reg - argBase)) { - continue; - } - - seen.set(reg - argBase); - result.add(e); - } - - // Sort by ascending register. - Collections.sort (result, new Comparator<LocalList.Entry>() { - public int compare (LocalList.Entry a, LocalList.Entry b) { - return a.getRegister() - b.getRegister(); - } - - public boolean equals (Object obj) { - return obj == this; - } - }); - - return result; - } - - /** - * Returns a string representation of this LocalList entry that is - * appropriate for emitting as an annotation. - * - * @param e non-null; entry - * @return non-null; annotation string - */ - private String entryAnnotationString(LocalList.Entry e) { - StringBuilder sb = new StringBuilder(); - - sb.append(RegisterSpec.PREFIX); - sb.append(e.getRegister()); - sb.append(' '); - - CstUtf8 name = e.getName(); - if (name == null) { - sb.append("null"); - } else { - sb.append(name.toHuman()); - } - sb.append(' '); - - CstType type = e.getType(); - if (type == null) { - sb.append("null"); - } else { - sb.append(type.toHuman()); - } - - CstUtf8 signature = e.getSignature(); - - if (signature != null) { - sb.append(' '); - sb.append(signature.toHuman()); - } - - return sb.toString(); - } - - /** - * Emits a {@link DebugInfoConstants#DBG_RESTART_LOCAL DBG_RESTART_LOCAL} - * sequence. - * - * @param entry entry associated with this restart - * @throws IOException - */ - private void emitLocalRestart(LocalList.Entry entry) - throws IOException { - - int mark = output.getCursor(); - - output.writeByte(DBG_RESTART_LOCAL); - emitUnsignedLeb128(entry.getRegister()); - - if (annotateTo != null || debugPrint != null) { - annotate(output.getCursor() - mark, - String.format("%04x: +local restart %s", - address, entryAnnotationString(entry))); - } - - if (DEBUG) { - System.err.println("emit local restart"); - } - } - - /** - * Emits a string index as an unsigned LEB128. The actual value written - * is shifted by 1, so that the '0' value is reserved for "null". The - * null symbol is used in some cases by the parameter name list - * at the beginning of the sequence. - * - * @param string null-ok; string to emit - * @throws IOException - */ - private void emitStringIndex(CstUtf8 string) throws IOException { - if ((string == null) || (file == null)) { - output.writeUnsignedLeb128(0); - } else { - output.writeUnsignedLeb128( - 1 + file.getStringIds().indexOf(string)); - } - - if (DEBUG) { - System.err.printf("Emit string %s\n", - string == null ? "<null>" : string.toQuoted()); - } - } - - /** - * Emits a type index as an unsigned LEB128. The actual value written - * is shifted by 1, so that the '0' value is reserved for "null". - * - * @param type null-ok; type to emit - * @throws IOException - */ - private void emitTypeIndex(CstType type) throws IOException { - if ((type == null) || (file == null)) { - output.writeUnsignedLeb128(0); - } else { - output.writeUnsignedLeb128( - 1 + file.getTypeIds().indexOf(type)); - } - - if (DEBUG) { - System.err.printf("Emit type %s\n", - type == null ? "<null>" : type.toHuman()); - } - } - - /** - * Emits a {@link DebugInfoConstants#DBG_START_LOCAL DBG_START_LOCAL} or - * {@link DebugInfoConstants#DBG_START_LOCAL_EXTENDED - * DBG_START_LOCAL_EXTENDED} sequence. - * - * @param entry entry to emit - * @throws IOException - */ - private void emitLocalStart(LocalList.Entry entry) - throws IOException { - - if (entry.getSignature() != null) { - emitLocalStartExtended(entry); - return; - } - - int mark = output.getCursor(); - - output.writeByte(DBG_START_LOCAL); - - emitUnsignedLeb128(entry.getRegister()); - emitStringIndex(entry.getName()); - emitTypeIndex(entry.getType()); - - if (annotateTo != null || debugPrint != null) { - annotate(output.getCursor() - mark, - String.format("%04x: +local %s", address, - entryAnnotationString(entry))); - } - - if (DEBUG) { - System.err.println("emit local start"); - } - } - - /** - * Emits a {@link DebugInfoConstants#DBG_START_LOCAL_EXTENDED - * DBG_START_LOCAL_EXTENDED} sequence. - * - * @param entry entry to emit - * @throws IOException - */ - private void emitLocalStartExtended(LocalList.Entry entry) - throws IOException { - - int mark = output.getCursor(); - - output.writeByte(DBG_START_LOCAL_EXTENDED); - - emitUnsignedLeb128(entry.getRegister()); - emitStringIndex(entry.getName()); - emitTypeIndex(entry.getType()); - emitStringIndex(entry.getSignature()); - - if (annotateTo != null || debugPrint != null) { - annotate(output.getCursor() - mark, - String.format("%04x: +localx %s", address, - entryAnnotationString(entry))); - } - - if (DEBUG) { - System.err.println("emit local start"); - } - } - - /** - * Emits a {@link DebugInfoConstants#DBG_END_LOCAL DBG_END_LOCAL} sequence. - * - * @param entry entry non-null; entry associated with end. - * @throws IOException - */ - private void emitLocalEnd(LocalList.Entry entry) - throws IOException { - - int mark = output.getCursor(); - - output.writeByte(DBG_END_LOCAL); - output.writeUnsignedLeb128(entry.getRegister()); - - if (annotateTo != null || debugPrint != null) { - annotate(output.getCursor() - mark, - String.format("%04x: -local %s", address, - entryAnnotationString(entry))); - } - - if (DEBUG) { - System.err.println("emit local end"); - } - } - - /** - * Emits the necessary byte sequences to emit the given position table - * entry. This will typically be a single special opcode, although - * it may also require DBG_ADVANCE_PC or DBG_ADVANCE_LINE. - * - * @param entry position entry to emit. - * @throws IOException - */ - private void emitPosition(PositionList.Entry entry) - throws IOException { - - SourcePosition pos = entry.getPosition(); - int newLine = pos.getLine(); - int newAddress = entry.getAddress(); - - int opcode; - - int deltaLines = newLine - line; - int deltaAddress = newAddress - address; - - if (deltaAddress < 0) { - throw new RuntimeException( - "Position entries must be in ascending address order"); - } - - if ((deltaLines < DBG_LINE_BASE) - || (deltaLines > (DBG_LINE_BASE + DBG_LINE_RANGE -1))) { - emitAdvanceLine(deltaLines); - deltaLines = 0; - } - - opcode = computeOpcode (deltaLines, deltaAddress); - - if ((opcode & ~0xff) > 0) { - emitAdvancePc(deltaAddress); - deltaAddress = 0; - opcode = computeOpcode (deltaLines, deltaAddress); - - if ((opcode & ~0xff) > 0) { - emitAdvanceLine(deltaLines); - deltaLines = 0; - opcode = computeOpcode (deltaLines, deltaAddress); - } - } - - output.writeByte(opcode); - - line += deltaLines; - address += deltaAddress; - - if (annotateTo != null || debugPrint != null) { - annotate(1, - String.format("%04x: line %d", address, line)); - } - } - - /** - * Computes a special opcode that will encode the given position change. - * If the return value is > 0xff, then the request cannot be fulfilled. - * Essentially the same as described in "DWARF Debugging Format Version 3" - * section 6.2.5.1. - * - * @param deltaLines >= DBG_LINE_BASE and <= DBG_LINE_BASE + - * DBG_LINE_RANGE, the line change to encode - * @param deltaAddress >= 0; the address change to encode - * @return <= 0xff if in range, otherwise parameters are out of range - */ - private static int computeOpcode(int deltaLines, int deltaAddress) { - if (deltaLines < DBG_LINE_BASE - || deltaLines > (DBG_LINE_BASE + DBG_LINE_RANGE -1)) { - - throw new RuntimeException("Parameter out of range"); - } - - return (deltaLines - DBG_LINE_BASE) - + (DBG_LINE_RANGE * deltaAddress) + DBG_FIRST_SPECIAL; - } - - /** - * Emits an {@link DebugInfoConstants#DBG_ADVANCE_LINE DBG_ADVANCE_LINE} - * sequence. - * - * @param deltaLines amount to change line number register by - * @throws IOException - */ - private void emitAdvanceLine(int deltaLines) throws IOException { - int mark = output.getCursor(); - - output.writeByte(DBG_ADVANCE_LINE); - output.writeSignedLeb128(deltaLines); - line += deltaLines; - - if (annotateTo != null || debugPrint != null) { - annotate(output.getCursor() - mark, - String.format("line = %d", line)); - } - - if (DEBUG) { - System.err.printf("Emitting advance_line for %d\n", deltaLines); - } - } - - /** - * Emits an {@link DebugInfoConstants#DBG_ADVANCE_PC DBG_ADVANCE_PC} - * sequence. - * - * @param deltaAddress >= 0 amount to change program counter by - * @throws IOException - */ - private void emitAdvancePc(int deltaAddress) throws IOException { - int mark = output.getCursor(); - - output.writeByte(DBG_ADVANCE_PC); - output.writeUnsignedLeb128(deltaAddress); - address += deltaAddress; - - if (annotateTo != null || debugPrint != null) { - annotate(output.getCursor() - mark, - String.format("%04x: advance pc", address)); - } - - if (DEBUG) { - System.err.printf("Emitting advance_pc for %d\n", deltaAddress); - } - } - - /** - * Emits an unsigned LEB128 value. - * - * @param n >= 0 vallue to emit. Note that, although this can represent - * integers larger than Integer.MAX_VALUE, we currently don't allow that. - * @throws IOException - */ - private void emitUnsignedLeb128(int n) throws IOException { - // We'll never need the top end of the unsigned range anyway. - if (n < 0) { - throw new RuntimeException( - "Signed value where unsigned required: " + n); - } - - output.writeSignedLeb128(n); - } - - /** - * Emits the {@link DebugInfoConstants#DBG_END_SEQUENCE DBG_END_SEQUENCE} - * bytecode. - */ - private void emitEndSequence() { - output.writeByte(DBG_END_SEQUENCE); - - if (annotateTo != null || debugPrint != null) { - annotate(1, "end sequence"); - } - } -} diff --git a/dx/src/com/android/dx/dex/file/DebugInfoItem.java b/dx/src/com/android/dx/dex/file/DebugInfoItem.java deleted file mode 100644 index b0745935d..000000000 --- a/dx/src/com/android/dx/dex/file/DebugInfoItem.java +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.dx.dex.file; - -import com.android.dx.dex.code.DalvCode; -import com.android.dx.dex.code.DalvInsnList; -import com.android.dx.dex.code.LocalList; -import com.android.dx.dex.code.PositionList; -import com.android.dx.rop.cst.CstMethodRef; -import com.android.dx.rop.cst.CstType; -import com.android.dx.rop.cst.CstUtf8; -import com.android.dx.util.AnnotatedOutput; -import com.android.dx.util.ExceptionWithContext; - -import java.io.PrintWriter; - -public class DebugInfoItem extends OffsettedItem { - /** the required alignment for instances of this class */ - private static final int ALIGNMENT = 1; - - private static final boolean ENABLE_ENCODER_SELF_CHECK = false; - - /** non-null; the code this item represents */ - private final DalvCode code; - - private byte[] encoded; - - private final boolean isStatic; - private final CstMethodRef ref; - - public DebugInfoItem(DalvCode code, boolean isStatic, CstMethodRef ref) { - // We don't know the write size yet. - super (ALIGNMENT, -1); - - if (code == null) { - throw new NullPointerException("code == null"); - } - - this.code = code; - this.isStatic = isStatic; - this.ref = ref; - } - - /** {@inheritDoc} */ - @Override - public ItemType itemType() { - return ItemType.TYPE_DEBUG_INFO_ITEM; - } - - /** {@inheritDoc} */ - @Override - public void addContents(DexFile file) { - // No contents to add. - } - - /** {@inheritDoc} */ - @Override - protected void place0(Section addedTo, int offset) { - // Encode the data and note the size. - - try { - encoded = encode(addedTo.getFile(), null, null, null, false); - setWriteSize(encoded.length); - } catch (RuntimeException ex) { - throw ExceptionWithContext.withContext(ex, - "...while placing debug info for " + ref.toHuman()); - } - } - - /** {@inheritDoc} */ - @Override - public String toHuman() { - throw new RuntimeException("unsupported"); - } - - /** - * Writes annotations for the elements of this list, as - * zero-length. This is meant to be used for dumping this instance - * directly after a code dump (with the real local list actually - * existing elsewhere in the output). - * - * @param file non-null; the file to use for referencing other sections - * @param out non-null; where to annotate to - * @param prefix null-ok; prefix to attach to each line of output - */ - public void annotateTo(DexFile file, AnnotatedOutput out, String prefix) { - encode(file, prefix, null, out, false); - } - - /** - * Does a human-friendly dump of this instance. - * - * @param out non-null; where to dump - * @param prefix non-null; prefix to attach to each line of output - */ - public void debugPrint(PrintWriter out, String prefix) { - encode(null, prefix, out, null, false); - } - - /** {@inheritDoc} */ - @Override - protected void writeTo0(DexFile file, AnnotatedOutput out) { - if (out.annotates()) { - /* - * Re-run the encoder to generate the annotations, - * but write the bits from the original encode - */ - - out.annotate(offsetString() + " debug info"); - encode(file, null, null, out, true); - } - - out.write(encoded); - } - - /** - * Performs debug info encoding. - * - * @param file null-ok; file to refer to during encoding - * @param prefix null-ok; prefix to attach to each line of output - * @param debugPrint null-ok; if specified, an alternate output for - * annotations - * @param out null-ok; if specified, where annotations should go - * @param consume whether to claim to have consumed output for - * <code>out</code> - * @return non-null; the encoded array - */ - private byte[] encode(DexFile file, String prefix, PrintWriter debugPrint, - AnnotatedOutput out, boolean consume) { - PositionList positions = code.getPositions(); - LocalList locals = code.getLocals(); - DalvInsnList insns = code.getInsns(); - int codeSize = insns.codeSize(); - int regSize = insns.getRegistersSize(); - - DebugInfoEncoder encoder = - new DebugInfoEncoder(positions, locals, - file, codeSize, regSize, isStatic, ref); - - byte[] result; - - if ((debugPrint == null) && (out == null)) { - result = encoder.convert(); - } else { - result = encoder.convertAndAnnotate( - prefix, debugPrint, out, consume); - } - - if (ENABLE_ENCODER_SELF_CHECK && (file != null)) { - DebugInfoDecoder.validateEncode(encoded, codeSize, - regSize, positions, locals, isStatic, ref, file); - } - - return result; - } -} diff --git a/dx/src/com/android/dx/dex/file/DexFile.java b/dx/src/com/android/dx/dex/file/DexFile.java deleted file mode 100644 index 8a4075d67..000000000 --- a/dx/src/com/android/dx/dex/file/DexFile.java +++ /dev/null @@ -1,647 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.dx.dex.file; - -import com.android.dx.rop.cst.Constant; -import com.android.dx.rop.cst.CstBaseMethodRef; -import com.android.dx.rop.cst.CstEnumRef; -import com.android.dx.rop.cst.CstFieldRef; -import com.android.dx.rop.cst.CstString; -import com.android.dx.rop.cst.CstType; -import com.android.dx.rop.cst.CstUtf8; -import com.android.dx.rop.type.Type; -import com.android.dx.util.ByteArrayAnnotatedOutput; -import com.android.dx.util.ExceptionWithContext; - -import java.io.IOException; -import java.io.OutputStream; -import java.io.Writer; -import java.security.DigestException; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.zip.Adler32; - -import static com.android.dx.dex.file.MixedItemSection.SortType; - -/** - * Representation of an entire <code>.dex</code> (Dalvik EXecutable) - * file, which itself consists of a set of Dalvik classes. - */ -public final class DexFile { - /** non-null; word data section */ - private final MixedItemSection wordData; - - /** - * non-null; type lists section. This is word data, but separating - * it from {@link #wordData} helps break what would otherwise be a - * circular dependency between the that and {@link #protoIds}. - */ - private final MixedItemSection typeLists; - - /** - * non-null; map section. The map needs to be in a section by itself - * for the self-reference mechanics to work in a reasonably - * straightforward way. See {@link MapItem#addMap} for more detail. - */ - private final MixedItemSection map; - - /** non-null; string data section */ - private final MixedItemSection stringData; - - /** non-null; string identifiers section */ - private final StringIdsSection stringIds; - - /** non-null; type identifiers section */ - private final TypeIdsSection typeIds; - - /** non-null; prototype identifiers section */ - private final ProtoIdsSection protoIds; - - /** non-null; field identifiers section */ - private final FieldIdsSection fieldIds; - - /** non-null; method identifiers section */ - private final MethodIdsSection methodIds; - - /** non-null; class definitions section */ - private final ClassDefsSection classDefs; - - /** non-null; class data section */ - private final MixedItemSection classData; - - /** non-null; byte data section */ - private final MixedItemSection byteData; - - /** non-null; file header */ - private final HeaderSection header; - - /** - * non-null; array of sections in the order they will appear in the - * final output file - */ - private final Section[] sections; - - /** >= -1; total file size or <code>-1</code> if unknown */ - private int fileSize; - - /** >= 40; maximum width of the file dump */ - private int dumpWidth; - - /** - * Constructs an instance. It is initially empty. - */ - public DexFile() { - header = new HeaderSection(this); - typeLists = new MixedItemSection(null, this, 4, SortType.NONE); - wordData = new MixedItemSection("word_data", this, 4, SortType.TYPE); - stringData = - new MixedItemSection("string_data", this, 1, SortType.INSTANCE); - classData = new MixedItemSection(null, this, 1, SortType.NONE); - byteData = new MixedItemSection("byte_data", this, 1, SortType.TYPE); - stringIds = new StringIdsSection(this); - typeIds = new TypeIdsSection(this); - protoIds = new ProtoIdsSection(this); - fieldIds = new FieldIdsSection(this); - methodIds = new MethodIdsSection(this); - classDefs = new ClassDefsSection(this); - map = new MixedItemSection("map", this, 4, SortType.NONE); - - /* - * This is the list of sections in the order they appear in - * the final output. - */ - sections = new Section[] { - header, stringIds, typeIds, protoIds, fieldIds, methodIds, - classDefs, wordData, typeLists, stringData, byteData, - classData, map }; - - fileSize = -1; - dumpWidth = 79; - } - - /** - * Adds a class to this instance. It is illegal to attempt to add more - * than one class with the same name. - * - * @param clazz non-null; the class to add - */ - public void add(ClassDefItem clazz) { - classDefs.add(clazz); - } - - /** - * Gets the class definition with the given name, if any. - * - * @param name non-null; the class name to look for - * @return null-ok; the class with the given name, or <code>null</code> - * if there is no such class - */ - public ClassDefItem getClassOrNull(String name) { - try { - Type type = Type.internClassName(name); - return (ClassDefItem) classDefs.get(new CstType(type)); - } catch (IllegalArgumentException ex) { - // Translate exception, per contract. - return null; - } - } - - /** - * Writes the contents of this instance as either a binary or a - * human-readable form, or both. - * - * @param out null-ok; where to write to - * @param humanOut null-ok; where to write human-oriented output to - * @param verbose whether to be verbose when writing human-oriented output - */ - public void writeTo(OutputStream out, Writer humanOut, boolean verbose) - throws IOException { - boolean annotate = (humanOut != null); - ByteArrayAnnotatedOutput result = toDex0(annotate, verbose); - - if (out != null) { - out.write(result.getArray()); - } - - if (annotate) { - result.writeAnnotationsTo(humanOut); - } - } - - /** - * Returns the contents of this instance as a <code>.dex</code> file, - * in <code>byte[]</code> form. - * - * @param humanOut null-ok; where to write human-oriented output to - * @param verbose whether to be verbose when writing human-oriented output - * @return non-null; a <code>.dex</code> file for this instance - */ - public byte[] toDex(Writer humanOut, boolean verbose) - throws IOException { - boolean annotate = (humanOut != null); - ByteArrayAnnotatedOutput result = toDex0(annotate, verbose); - - if (annotate) { - result.writeAnnotationsTo(humanOut); - } - - return result.getArray(); - } - - /** - * Sets the maximum width of the human-oriented dump of the instance. - * - * @param dumpWidth >= 40; the width - */ - public void setDumpWidth(int dumpWidth) { - if (dumpWidth < 40) { - throw new IllegalArgumentException("dumpWidth < 40"); - } - - this.dumpWidth = dumpWidth; - } - - /** - * Gets the total file size, if known. - * - * <p>This is package-scope in order to allow - * the {@link HeaderSection} to set itself up properly.</p> - * - * @return >= 0; the total file size - * @throws RuntimeException thrown if the file size is not yet known - */ - /*package*/ int getFileSize() { - if (fileSize < 0) { - throw new RuntimeException("file size not yet known"); - } - - return fileSize; - } - - /** - * Gets the string data section. - * - * <p>This is package-scope in order to allow - * the various {@link Item} instances to add items to the - * instance.</p> - * - * @return non-null; the string data section - */ - /*package*/ MixedItemSection getStringData() { - return stringData; - } - - /** - * Gets the word data section. - * - * <p>This is package-scope in order to allow - * the various {@link Item} instances to add items to the - * instance.</p> - * - * @return non-null; the word data section - */ - /*package*/ MixedItemSection getWordData() { - return wordData; - } - - /** - * Gets the type lists section. - * - * <p>This is package-scope in order to allow - * the various {@link Item} instances to add items to the - * instance.</p> - * - * @return non-null; the word data section - */ - /*package*/ MixedItemSection getTypeLists() { - return typeLists; - } - - /** - * Gets the map section. - * - * <p>This is package-scope in order to allow the header section - * to query it.</p> - * - * @return non-null; the map section - */ - /*package*/ MixedItemSection getMap() { - return map; - } - - /** - * Gets the string identifiers section. - * - * <p>This is package-scope in order to allow - * the various {@link Item} instances to add items to the - * instance.</p> - * - * @return non-null; the string identifiers section - */ - /*package*/ StringIdsSection getStringIds() { - return stringIds; - } - - /** - * Gets the class definitions section. - * - * <p>This is package-scope in order to allow - * the various {@link Item} instances to add items to the - * instance.</p> - * - * @return non-null; the class definitions section - */ - /*package*/ ClassDefsSection getClassDefs() { - return classDefs; - } - - /** - * Gets the class data section. - * - * <p>This is package-scope in order to allow - * the various {@link Item} instances to add items to the - * instance.</p> - * - * @return non-null; the class data section - */ - /*package*/ MixedItemSection getClassData() { - return classData; - } - - /** - * Gets the type identifiers section. - * - * <p>This is package-scope in order to allow - * the various {@link Item} instances to add items to the - * instance.</p> - * - * @return non-null; the class identifiers section - */ - /*package*/ TypeIdsSection getTypeIds() { - return typeIds; - } - - /** - * Gets the prototype identifiers section. - * - * <p>This is package-scope in order to allow - * the various {@link Item} instances to add items to the - * instance.</p> - * - * @return non-null; the prototype identifiers section - */ - /*package*/ ProtoIdsSection getProtoIds() { - return protoIds; - } - - /** - * Gets the field identifiers section. - * - * <p>This is package-scope in order to allow - * the various {@link Item} instances to add items to the - * instance.</p> - * - * @return non-null; the field identifiers section - */ - /*package*/ FieldIdsSection getFieldIds() { - return fieldIds; - } - - /** - * Gets the method identifiers section. - * - * <p>This is package-scope in order to allow - * the various {@link Item} instances to add items to the - * instance.</p> - * - * @return non-null; the method identifiers section - */ - /*package*/ MethodIdsSection getMethodIds() { - return methodIds; - } - - /** - * Gets the byte data section. - * - * <p>This is package-scope in order to allow - * the various {@link Item} instances to add items to the - * instance.</p> - * - * @return non-null; the byte data section - */ - /*package*/ MixedItemSection getByteData() { - return byteData; - } - - /** - * Gets the first section of the file that is to be considered - * part of the data section. - * - * <p>This is package-scope in order to allow the header section - * to query it.</p> - * - * @return non-null; the section - */ - /*package*/ Section getFirstDataSection() { - return wordData; - } - - /** - * Gets the last section of the file that is to be considered - * part of the data section. - * - * <p>This is package-scope in order to allow the header section - * to query it.</p> - * - * @return non-null; the section - */ - /*package*/ Section getLastDataSection() { - return map; - } - - /** - * Interns the given constant in the appropriate section of this - * instance, or do nothing if the given constant isn't the sort - * that should be interned. - * - * @param cst non-null; constant to possibly intern - */ - /*package*/ void internIfAppropriate(Constant cst) { - if (cst instanceof CstString) { - stringIds.intern((CstString) cst); - } else if (cst instanceof CstUtf8) { - stringIds.intern((CstUtf8) cst); - } else if (cst instanceof CstType) { - typeIds.intern((CstType) cst); - } else if (cst instanceof CstBaseMethodRef) { - methodIds.intern((CstBaseMethodRef) cst); - } else if (cst instanceof CstFieldRef) { - fieldIds.intern((CstFieldRef) cst); - } else if (cst instanceof CstEnumRef) { - fieldIds.intern(((CstEnumRef) cst).getFieldRef()); - } else if (cst == null) { - throw new NullPointerException("cst == null"); - } - } - - /** - * Gets the {@link IndexedItem} corresponding to the given constant, - * if it is a constant that has such a correspondence, or return - * <code>null</code> if it isn't such a constant. This will throw - * an exception if the given constant <i>should</i> have been found - * but wasn't. - * - * @param cst non-null; the constant to look up - * @return null-ok; its corresponding item, if it has a corresponding - * item, or <code>null</code> if it's not that sort of constant - */ - /*package*/ IndexedItem findItemOrNull(Constant cst) { - IndexedItem item; - - if (cst instanceof CstString) { - return stringIds.get(cst); - } else if (cst instanceof CstType) { - return typeIds.get(cst); - } else if (cst instanceof CstBaseMethodRef) { - return methodIds.get(cst); - } else if (cst instanceof CstFieldRef) { - return fieldIds.get(cst); - } else { - return null; - } - } - - /** - * Returns the contents of this instance as a <code>.dex</code> file, - * in a {@link ByteArrayAnnotatedOutput} instance. - * - * @param annotate whether or not to keep annotations - * @param verbose if annotating, whether to be verbose - * @return non-null; a <code>.dex</code> file for this instance - */ - private ByteArrayAnnotatedOutput toDex0(boolean annotate, - boolean verbose) { - /* - * The following is ordered so that the prepare() calls which - * add items happen before the calls to the sections that get - * added to. - */ - - classDefs.prepare(); - classData.prepare(); - wordData.prepare(); - byteData.prepare(); - methodIds.prepare(); - fieldIds.prepare(); - protoIds.prepare(); - typeLists.prepare(); - typeIds.prepare(); - stringIds.prepare(); - stringData.prepare(); - header.prepare(); - - // Place the sections within the file. - - int count = sections.length; - int offset = 0; - - for (int i = 0; i < count; i++) { - Section one = sections[i]; - int placedAt = one.setFileOffset(offset); - if (placedAt < offset) { - throw new RuntimeException("bogus placement for section " + i); - } - - try { - if (one == map) { - /* - * Inform the map of all the sections, and add it - * to the file. This can only be done after all - * the other items have been sorted and placed. - */ - MapItem.addMap(sections, map); - map.prepare(); - } - - if (one instanceof MixedItemSection) { - /* - * Place the items of a MixedItemSection that just - * got placed. - */ - ((MixedItemSection) one).placeItems(); - } - - offset = placedAt + one.writeSize(); - } catch (RuntimeException ex) { - throw ExceptionWithContext.withContext(ex, - "...while writing section " + i); - } - } - - // Write out all the sections. - - fileSize = offset; - byte[] barr = new byte[fileSize]; - ByteArrayAnnotatedOutput out = new ByteArrayAnnotatedOutput(barr); - - if (annotate) { - out.enableAnnotations(dumpWidth, verbose); - } - - for (int i = 0; i < count; i++) { - try { - Section one = sections[i]; - int zeroCount = one.getFileOffset() - out.getCursor(); - if (zeroCount < 0) { - throw new ExceptionWithContext("excess write of " + - (-zeroCount)); - } - out.writeZeroes(one.getFileOffset() - out.getCursor()); - one.writeTo(out); - } catch (RuntimeException ex) { - ExceptionWithContext ec; - if (ex instanceof ExceptionWithContext) { - ec = (ExceptionWithContext) ex; - } else { - ec = new ExceptionWithContext(ex); - } - ec.addContext("...while writing section " + i); - throw ec; - } - } - - if (out.getCursor() != fileSize) { - throw new RuntimeException("foreshortened write"); - } - - // Perform final bookkeeping. - - calcSignature(barr); - calcChecksum(barr); - - if (annotate) { - wordData.writeIndexAnnotation(out, ItemType.TYPE_CODE_ITEM, - "\nmethod code index:\n\n"); - getStatistics().writeAnnotation(out); - out.finishAnnotating(); - } - - return out; - } - - /** - * Generates and returns statistics for all the items in the file. - * - * @return non-null; the statistics - */ - public Statistics getStatistics() { - Statistics stats = new Statistics(); - - for (Section s : sections) { - stats.addAll(s); - } - - return stats; - } - - /** - * Calculates the signature for the <code>.dex</code> file in the - * given array, and modify the array to contain it. - * - * @param bytes non-null; the bytes of the file - */ - private static void calcSignature(byte[] bytes) { - MessageDigest md; - - try { - md = MessageDigest.getInstance("SHA-1"); - } catch (NoSuchAlgorithmException ex) { - throw new RuntimeException(ex); - } - - md.update(bytes, 32, bytes.length - 32); - - try { - int amt = md.digest(bytes, 12, 20); - if (amt != 20) { - throw new RuntimeException("unexpected digest write: " + amt + - " bytes"); - } - } catch (DigestException ex) { - throw new RuntimeException(ex); - } - } - - /** - * Calculates the checksum for the <code>.dex</code> file in the - * given array, and modify the array to contain it. - * - * @param bytes non-null; the bytes of the file - */ - private static void calcChecksum(byte[] bytes) { - Adler32 a32 = new Adler32(); - - a32.update(bytes, 12, bytes.length - 12); - - int sum = (int) a32.getValue(); - - bytes[8] = (byte) sum; - bytes[9] = (byte) (sum >> 8); - bytes[10] = (byte) (sum >> 16); - bytes[11] = (byte) (sum >> 24); - } -} diff --git a/dx/src/com/android/dx/dex/file/EncodedArrayItem.java b/dx/src/com/android/dx/dex/file/EncodedArrayItem.java deleted file mode 100644 index 9ec72fa42..000000000 --- a/dx/src/com/android/dx/dex/file/EncodedArrayItem.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.dx.dex.file; - -import com.android.dx.rop.annotation.Annotation; -import com.android.dx.rop.annotation.AnnotationVisibility; -import com.android.dx.rop.annotation.NameValuePair; -import com.android.dx.rop.cst.Constant; -import com.android.dx.rop.cst.CstAnnotation; -import com.android.dx.rop.cst.CstArray; -import com.android.dx.rop.cst.CstUtf8; -import com.android.dx.util.ByteArrayAnnotatedOutput; -import com.android.dx.util.AnnotatedOutput; - -import java.util.Arrays; -import java.util.Comparator; - -/** - * Encoded array of constant values. - */ -public final class EncodedArrayItem extends OffsettedItem { - /** the required alignment for instances of this class */ - private static final int ALIGNMENT = 1; - - /** non-null; the array to represent */ - private final CstArray array; - - /** - * null-ok; encoded form, ready for writing to a file; set during - * {@link #place0} - */ - private byte[] encodedForm; - - /** - * Constructs an instance. - * - * @param array non-null; array to represent - */ - public EncodedArrayItem(CstArray array) { - /* - * The write size isn't known up-front because (the variable-lengthed) - * leb128 type is used to represent some things. - */ - super(ALIGNMENT, -1); - - if (array == null) { - throw new NullPointerException("array == null"); - } - - this.array = array; - this.encodedForm = null; - } - - /** {@inheritDoc} */ - @Override - public ItemType itemType() { - return ItemType.TYPE_ENCODED_ARRAY_ITEM; - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - return array.hashCode(); - } - - /** {@inheritDoc} */ - @Override - protected int compareTo0(OffsettedItem other) { - EncodedArrayItem otherArray = (EncodedArrayItem) other; - - return array.compareTo(otherArray.array); - } - - /** {@inheritDoc} */ - @Override - public String toHuman() { - return array.toHuman(); - } - - /** {@inheritDoc} */ - public void addContents(DexFile file) { - ValueEncoder.addContents(file, array); - } - - /** {@inheritDoc} */ - @Override - protected void place0(Section addedTo, int offset) { - // Encode the data and note the size. - - ByteArrayAnnotatedOutput out = new ByteArrayAnnotatedOutput(); - ValueEncoder encoder = new ValueEncoder(addedTo.getFile(), out); - - encoder.writeArray(array, false); - encodedForm = out.toByteArray(); - setWriteSize(encodedForm.length); - } - - /** {@inheritDoc} */ - @Override - protected void writeTo0(DexFile file, AnnotatedOutput out) { - boolean annotates = out.annotates(); - - if (annotates) { - out.annotate(0, offsetString() + " encoded array"); - - /* - * The output is to be annotated, so redo the work previously - * done by place0(), except this time annotations will actually - * get emitted. - */ - ValueEncoder encoder = new ValueEncoder(file, out); - encoder.writeArray(array, true); - } else { - out.write(encodedForm); - } - } -} diff --git a/dx/src/com/android/dx/dex/file/EncodedField.java b/dx/src/com/android/dx/dex/file/EncodedField.java deleted file mode 100644 index 62a5789d4..000000000 --- a/dx/src/com/android/dx/dex/file/EncodedField.java +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.dx.dex.file; - -import com.android.dx.rop.code.AccessFlags; -import com.android.dx.rop.cst.CstFieldRef; -import com.android.dx.rop.cst.CstUtf8; -import com.android.dx.util.AnnotatedOutput; -import com.android.dx.util.Hex; -import com.android.dx.util.Leb128Utils; - -import java.io.PrintWriter; - -/** - * Representation of a field of a class, of any sort. - */ -public final class EncodedField extends EncodedMember - implements Comparable<EncodedField> { - /** non-null; constant for the field */ - private final CstFieldRef field; - - /** - * Constructs an instance. - * - * @param field non-null; constant for the field - * @param accessFlags access flags - */ - public EncodedField(CstFieldRef field, int accessFlags) { - super(accessFlags); - - if (field == null) { - throw new NullPointerException("field == null"); - } - - /* - * TODO: Maybe check accessFlags, at least for - * easily-checked stuff? - */ - - this.field = field; - } - - /** {@inheritDoc} */ - public int hashCode() { - return field.hashCode(); - } - - /** {@inheritDoc} */ - public boolean equals(Object other) { - if (! (other instanceof EncodedField)) { - return false; - } - - return compareTo((EncodedField) other) == 0; - } - - /** - * {@inheritDoc} - * - * <p><b>Note:</b> This compares the method constants only, - * ignoring any associated code, because it should never be the - * case that two different items with the same method constant - * ever appear in the same list (or same file, even).</p> - */ - public int compareTo(EncodedField other) { - return field.compareTo(other.field); - } - - /** {@inheritDoc} */ - @Override - public String toString() { - StringBuffer sb = new StringBuffer(100); - - sb.append(getClass().getName()); - sb.append('{'); - sb.append(Hex.u2(getAccessFlags())); - sb.append(' '); - sb.append(field); - sb.append('}'); - return sb.toString(); - } - - /** {@inheritDoc} */ - @Override - public void addContents(DexFile file) { - FieldIdsSection fieldIds = file.getFieldIds(); - fieldIds.intern(field); - } - - /** {@inheritDoc} */ - @Override - public CstUtf8 getName() { - return field.getNat().getName(); - } - - /** {@inheritDoc} */ - public String toHuman() { - return field.toHuman(); - } - - /** {@inheritDoc} */ - @Override - public void debugPrint(PrintWriter out, boolean verbose) { - // TODO: Maybe put something better here? - out.println(toString()); - } - - /** - * Gets the constant for the field. - * - * @return non-null; the constant - */ - public CstFieldRef getRef() { - return field; - } - - /** {@inheritDoc} */ - @Override - public int encode(DexFile file, AnnotatedOutput out, - int lastIndex, int dumpSeq) { - int fieldIdx = file.getFieldIds().indexOf(field); - int diff = fieldIdx - lastIndex; - int accessFlags = getAccessFlags(); - - if (out.annotates()) { - out.annotate(0, String.format(" [%x] %s", dumpSeq, - field.toHuman())); - out.annotate(Leb128Utils.unsignedLeb128Size(diff), - " field_idx: " + Hex.u4(fieldIdx)); - out.annotate(Leb128Utils.unsignedLeb128Size(accessFlags), - " access_flags: " + - AccessFlags.fieldString(accessFlags)); - } - - out.writeUnsignedLeb128(diff); - out.writeUnsignedLeb128(accessFlags); - - return fieldIdx; - } -} diff --git a/dx/src/com/android/dx/dex/file/EncodedMember.java b/dx/src/com/android/dx/dex/file/EncodedMember.java deleted file mode 100644 index 3ae0d0902..000000000 --- a/dx/src/com/android/dx/dex/file/EncodedMember.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.dx.dex.file; - -import com.android.dx.rop.cst.CstUtf8; -import com.android.dx.util.AnnotatedOutput; -import com.android.dx.util.ToHuman; - -import java.io.PrintWriter; - -/** - * Representation of a member (field or method) of a class, for the - * purposes of encoding it inside a {@link ClassDataItem}. - */ -public abstract class EncodedMember implements ToHuman { - /** access flags */ - private final int accessFlags; - - /** - * Constructs an instance. - * - * @param accessFlags access flags for the member - */ - public EncodedMember(int accessFlags) { - this.accessFlags = accessFlags; - } - - /** - * Gets the access flags. - * - * @return the access flags - */ - public final int getAccessFlags() { - return accessFlags; - } - - /** - * Gets the name. - * - * @return non-null; the name - */ - public abstract CstUtf8 getName(); - - /** - * Does a human-friendly dump of this instance. - * - * @param out non-null; where to dump - * @param verbose whether to be verbose with the output - */ - public abstract void debugPrint(PrintWriter out, boolean verbose); - - /** - * Populates a {@link DexFile} with items from within this instance. - * - * @param file non-null; the file to populate - */ - public abstract void addContents(DexFile file); - - /** - * Encodes this instance to the given output. - * - * @param file non-null; file this instance is part of - * @param out non-null; where to write to - * @param lastIndex >= 0; the previous member index value encoded, or - * <code>0</code> if this is the first element to encode - * @param dumpSeq >= 0; sequence number of this instance for - * annotation purposes - * @return >= 0; the member index value that was encoded - */ - public abstract int encode(DexFile file, AnnotatedOutput out, - int lastIndex, int dumpSeq); -} diff --git a/dx/src/com/android/dx/dex/file/EncodedMethod.java b/dx/src/com/android/dx/dex/file/EncodedMethod.java deleted file mode 100644 index 319fbb72b..000000000 --- a/dx/src/com/android/dx/dex/file/EncodedMethod.java +++ /dev/null @@ -1,196 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.dx.dex.file; - -import com.android.dx.dex.code.DalvCode; -import com.android.dx.rop.code.AccessFlags; -import com.android.dx.rop.cst.CstMethodRef; -import com.android.dx.rop.cst.CstUtf8; -import com.android.dx.rop.type.TypeList; -import com.android.dx.util.AnnotatedOutput; -import com.android.dx.util.Hex; -import com.android.dx.util.Leb128Utils; - -import java.io.PrintWriter; - -/** - * Class that representats a method of a class. - */ -public final class EncodedMethod extends EncodedMember - implements Comparable<EncodedMethod> { - /** non-null; constant for the method */ - private final CstMethodRef method; - - /** - * null-ok; code for the method, if the method is neither - * <code>abstract</code> nor <code>native</code> - */ - private final CodeItem code; - - /** - * Constructs an instance. - * - * @param method non-null; constant for the method - * @param accessFlags access flags - * @param code null-ok; code for the method, if it is neither - * <code>abstract</code> nor <code>native</code> - * @param throwsList non-null; list of possibly-thrown exceptions, - * just used in generating debugging output (listings) - */ - public EncodedMethod(CstMethodRef method, int accessFlags, - DalvCode code, TypeList throwsList) { - super(accessFlags); - - if (method == null) { - throw new NullPointerException("method == null"); - } - - this.method = method; - - if (code == null) { - this.code = null; - } else { - boolean isStatic = (accessFlags & AccessFlags.ACC_STATIC) != 0; - this.code = new CodeItem(method, code, isStatic, throwsList); - } - } - - /** {@inheritDoc} */ - public boolean equals(Object other) { - if (! (other instanceof EncodedMethod)) { - return false; - } - - return compareTo((EncodedMethod) other) == 0; - } - - /** - * {@inheritDoc} - * - * <p><b>Note:</b> This compares the method constants only, - * ignoring any associated code, because it should never be the - * case that two different items with the same method constant - * ever appear in the same list (or same file, even).</p> - */ - public int compareTo(EncodedMethod other) { - return method.compareTo(other.method); - } - - /** {@inheritDoc} */ - @Override - public String toString() { - StringBuffer sb = new StringBuffer(100); - - sb.append(getClass().getName()); - sb.append('{'); - sb.append(Hex.u2(getAccessFlags())); - sb.append(' '); - sb.append(method); - - if (code != null) { - sb.append(' '); - sb.append(code); - } - - sb.append('}'); - - return sb.toString(); - } - - /** {@inheritDoc} */ - @Override - public void addContents(DexFile file) { - MethodIdsSection methodIds = file.getMethodIds(); - MixedItemSection wordData = file.getWordData(); - - methodIds.intern(method); - - if (code != null) { - wordData.add(code); - } - } - - /** {@inheritDoc} */ - public final String toHuman() { - return method.toHuman(); - } - - /** {@inheritDoc} */ - @Override - public final CstUtf8 getName() { - return method.getNat().getName(); - } - - /** {@inheritDoc} */ - @Override - public void debugPrint(PrintWriter out, boolean verbose) { - if (code == null) { - out.println(getRef().toHuman() + ": abstract or native"); - } else { - code.debugPrint(out, " ", verbose); - } - } - - /** - * Gets the constant for the method. - * - * @return non-null; the constant - */ - public final CstMethodRef getRef() { - return method; - } - - /** {@inheritDoc} */ - @Override - public int encode(DexFile file, AnnotatedOutput out, - int lastIndex, int dumpSeq) { - int methodIdx = file.getMethodIds().indexOf(method); - int diff = methodIdx - lastIndex; - int accessFlags = getAccessFlags(); - int codeOff = OffsettedItem.getAbsoluteOffsetOr0(code); - boolean hasCode = (codeOff != 0); - boolean shouldHaveCode = (accessFlags & - (AccessFlags.ACC_ABSTRACT | AccessFlags.ACC_NATIVE)) == 0; - - /* - * Verify that code appears if and only if a method is - * declared to have it. - */ - if (hasCode != shouldHaveCode) { - throw new UnsupportedOperationException( - "code vs. access_flags mismatch"); - } - - if (out.annotates()) { - out.annotate(0, String.format(" [%x] %s", dumpSeq, - method.toHuman())); - out.annotate(Leb128Utils.unsignedLeb128Size(diff), - " method_idx: " + Hex.u4(methodIdx)); - out.annotate(Leb128Utils.unsignedLeb128Size(accessFlags), - " access_flags: " + - AccessFlags.methodString(accessFlags)); - out.annotate(Leb128Utils.unsignedLeb128Size(codeOff), - " code_off: " + Hex.u4(codeOff)); - } - - out.writeUnsignedLeb128(diff); - out.writeUnsignedLeb128(accessFlags); - out.writeUnsignedLeb128(codeOff); - - return methodIdx; - } -} diff --git a/dx/src/com/android/dx/dex/file/FieldAnnotationStruct.java b/dx/src/com/android/dx/dex/file/FieldAnnotationStruct.java deleted file mode 100644 index e6169bd21..000000000 --- a/dx/src/com/android/dx/dex/file/FieldAnnotationStruct.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.dx.dex.file; - -import com.android.dx.rop.annotation.Annotations; -import com.android.dx.rop.cst.CstFieldRef; -import com.android.dx.util.AnnotatedOutput; -import com.android.dx.util.Hex; -import com.android.dx.util.ToHuman; - -/** - * Association of a field and its annotations. - */ -public final class FieldAnnotationStruct - implements ToHuman, Comparable<FieldAnnotationStruct> { - /** non-null; the field in question */ - private final CstFieldRef field; - - /** non-null; the associated annotations */ - private AnnotationSetItem annotations; - - /** - * Constructs an instance. - * - * @param field non-null; the field in question - * @param annotations non-null; the associated annotations - */ - public FieldAnnotationStruct(CstFieldRef field, - AnnotationSetItem annotations) { - if (field == null) { - throw new NullPointerException("field == null"); - } - - if (annotations == null) { - throw new NullPointerException("annotations == null"); - } - - this.field = field; - this.annotations = annotations; - } - - /** {@inheritDoc} */ - public int hashCode() { - return field.hashCode(); - } - - /** {@inheritDoc} */ - public boolean equals(Object other) { - if (! (other instanceof FieldAnnotationStruct)) { - return false; - } - - return field.equals(((FieldAnnotationStruct) other).field); - } - - /** {@inheritDoc} */ - public int compareTo(FieldAnnotationStruct other) { - return field.compareTo(other.field); - } - - /** {@inheritDoc} */ - public void addContents(DexFile file) { - FieldIdsSection fieldIds = file.getFieldIds(); - MixedItemSection wordData = file.getWordData(); - - fieldIds.intern(field); - annotations = wordData.intern(annotations); - } - - /** {@inheritDoc} */ - public void writeTo(DexFile file, AnnotatedOutput out) { - int fieldIdx = file.getFieldIds().indexOf(field); - int annotationsOff = annotations.getAbsoluteOffset(); - - if (out.annotates()) { - out.annotate(0, " " + field.toHuman()); - out.annotate(4, " field_idx: " + Hex.u4(fieldIdx)); - out.annotate(4, " annotations_off: " + - Hex.u4(annotationsOff)); - } - - out.writeInt(fieldIdx); - out.writeInt(annotationsOff); - } - - /** {@inheritDoc} */ - public String toHuman() { - return field.toHuman() + ": " + annotations; - } - - /** - * Gets the field this item is for. - * - * @return non-null; the field - */ - public CstFieldRef getField() { - return field; - } - - /** - * Gets the associated annotations. - * - * @return non-null; the annotations - */ - public Annotations getAnnotations() { - return annotations.getAnnotations(); - } -} diff --git a/dx/src/com/android/dx/dex/file/FieldIdItem.java b/dx/src/com/android/dx/dex/file/FieldIdItem.java deleted file mode 100644 index d098d52ab..000000000 --- a/dx/src/com/android/dx/dex/file/FieldIdItem.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.dx.dex.file; - -import com.android.dx.rop.cst.CstFieldRef; - -/** - * Representation of a field reference inside a Dalvik file. - */ -public final class FieldIdItem extends MemberIdItem { - /** - * Constructs an instance. - * - * @param field non-null; the constant for the field - */ - public FieldIdItem(CstFieldRef field) { - super(field); - } - - /** {@inheritDoc} */ - @Override - public ItemType itemType() { - return ItemType.TYPE_FIELD_ID_ITEM; - } - - /** {@inheritDoc} */ - @Override - public void addContents(DexFile file) { - super.addContents(file); - - TypeIdsSection typeIds = file.getTypeIds(); - typeIds.intern(getFieldRef().getType()); - } - - /** - * Gets the field constant. - * - * @return non-null; the constant - */ - public CstFieldRef getFieldRef() { - return (CstFieldRef) getRef(); - } - - /** {@inheritDoc} */ - @Override - protected int getTypoidIdx(DexFile file) { - TypeIdsSection typeIds = file.getTypeIds(); - return typeIds.indexOf(getFieldRef().getType()); - } - - /** {@inheritDoc} */ - @Override - protected String getTypoidName() { - return "type_idx"; - } -} diff --git a/dx/src/com/android/dx/dex/file/FieldIdsSection.java b/dx/src/com/android/dx/dex/file/FieldIdsSection.java deleted file mode 100644 index fddf55f47..000000000 --- a/dx/src/com/android/dx/dex/file/FieldIdsSection.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.dx.dex.file; - -import com.android.dx.rop.cst.Constant; -import com.android.dx.rop.cst.CstFieldRef; -import com.android.dx.util.AnnotatedOutput; -import com.android.dx.util.Hex; - -import java.util.Collection; -import java.util.TreeMap; - -/** - * Field refs list section of a <code>.dex</code> file. - */ -public final class FieldIdsSection extends MemberIdsSection { - /** - * non-null; map from field constants to {@link - * FieldIdItem} instances - */ - private final TreeMap<CstFieldRef, FieldIdItem> fieldIds; - - /** - * Constructs an instance. The file offset is initially unknown. - * - * @param file non-null; file that this instance is part of - */ - public FieldIdsSection(DexFile file) { - super("field_ids", file); - - fieldIds = new TreeMap<CstFieldRef, FieldIdItem>(); - } - - /** {@inheritDoc} */ - @Override - public Collection<? extends Item> items() { - return fieldIds.values(); - } - - /** {@inheritDoc} */ - @Override - public IndexedItem get(Constant cst) { - if (cst == null) { - throw new NullPointerException("cst == null"); - } - - throwIfNotPrepared(); - - IndexedItem result = fieldIds.get((CstFieldRef) cst); - - if (result == null) { - throw new IllegalArgumentException("not found"); - } - - return result; - } - - /** - * Writes the portion of the file header that refers to this instance. - * - * @param out non-null; where to write - */ - public void writeHeaderPart(AnnotatedOutput out) { - throwIfNotPrepared(); - - int sz = fieldIds.size(); - int offset = (sz == 0) ? 0 : getFileOffset(); - - if (out.annotates()) { - out.annotate(4, "field_ids_size: " + Hex.u4(sz)); - out.annotate(4, "field_ids_off: " + Hex.u4(offset)); - } - - out.writeInt(sz); - out.writeInt(offset); - } - - /** - * Interns an element into this instance. - * - * @param field non-null; the reference to intern - * @return non-null; the interned reference - */ - public FieldIdItem intern(CstFieldRef field) { - if (field == null) { - throw new NullPointerException("field == null"); - } - - throwIfPrepared(); - - FieldIdItem result = fieldIds.get(field); - - if (result == null) { - result = new FieldIdItem(field); - fieldIds.put(field, result); - } - - return result; - } - - /** - * Gets the index of the given reference, which must have been added - * to this instance. - * - * @param ref non-null; the reference to look up - * @return >= 0; the reference's index - */ - public int indexOf(CstFieldRef ref) { - if (ref == null) { - throw new NullPointerException("ref == null"); - } - - throwIfNotPrepared(); - - FieldIdItem item = fieldIds.get(ref); - - if (item == null) { - throw new IllegalArgumentException("not found"); - } - - return item.getIndex(); - } -} diff --git a/dx/src/com/android/dx/dex/file/HeaderItem.java b/dx/src/com/android/dx/dex/file/HeaderItem.java deleted file mode 100644 index 55c1f1c5f..000000000 --- a/dx/src/com/android/dx/dex/file/HeaderItem.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.dx.dex.file; - -import com.android.dx.rop.cst.CstUtf8; -import com.android.dx.util.AnnotatedOutput; -import com.android.dx.util.Hex; - -/** - * File header section of a <code>.dex</code> file. - */ -public final class HeaderItem extends IndexedItem { - /** - * non-null; the file format magic number, represented as the - * low-order bytes of a string - */ - private static final String MAGIC = "dex\n035\0"; - - /** size of this section, in bytes */ - private static final int HEADER_SIZE = 0x70; - - /** the endianness tag */ - private static final int ENDIAN_TAG = 0x12345678; - - /** - * Constructs an instance. - */ - public HeaderItem() { - // This space intentionally left blank. - } - - /** {@inheritDoc} */ - @Override - public ItemType itemType() { - return ItemType.TYPE_HEADER_ITEM; - } - - /** {@inheritDoc} */ - @Override - public int writeSize() { - return HEADER_SIZE; - } - - /** {@inheritDoc} */ - @Override - public void addContents(DexFile file) { - // Nothing to do here. - } - - /** {@inheritDoc} */ - @Override - public void writeTo(DexFile file, AnnotatedOutput out) { - int mapOff = file.getMap().getFileOffset(); - Section firstDataSection = file.getFirstDataSection(); - Section lastDataSection = file.getLastDataSection(); - int dataOff = firstDataSection.getFileOffset(); - int dataSize = lastDataSection.getFileOffset() + - lastDataSection.writeSize() - dataOff; - - if (out.annotates()) { - out.annotate(8, "magic: " + new CstUtf8(MAGIC).toQuoted()); - out.annotate(4, "checksum"); - out.annotate(20, "signature"); - out.annotate(4, "file_size: " + - Hex.u4(file.getFileSize())); - out.annotate(4, "header_size: " + Hex.u4(HEADER_SIZE)); - out.annotate(4, "endian_tag: " + Hex.u4(ENDIAN_TAG)); - out.annotate(4, "link_size: 0"); - out.annotate(4, "link_off: 0"); - out.annotate(4, "map_off: " + Hex.u4(mapOff)); - } - - // Write the magic number. - for (int i = 0; i < 8; i++) { - out.writeByte(MAGIC.charAt(i)); - } - - // Leave space for the checksum and signature. - out.writeZeroes(24); - - out.writeInt(file.getFileSize()); - out.writeInt(HEADER_SIZE); - out.writeInt(ENDIAN_TAG); - - /* - * Write zeroes for the link size and data, as the output - * isn't a staticly linked file. - */ - out.writeZeroes(8); - - out.writeInt(mapOff); - - // Write out each section's respective header part. - file.getStringIds().writeHeaderPart(out); - file.getTypeIds().writeHeaderPart(out); - file.getProtoIds().writeHeaderPart(out); - file.getFieldIds().writeHeaderPart(out); - file.getMethodIds().writeHeaderPart(out); - file.getClassDefs().writeHeaderPart(out); - - if (out.annotates()) { - out.annotate(4, "data_size: " + Hex.u4(dataSize)); - out.annotate(4, "data_off: " + Hex.u4(dataOff)); - } - - out.writeInt(dataSize); - out.writeInt(dataOff); - } -} diff --git a/dx/src/com/android/dx/dex/file/HeaderSection.java b/dx/src/com/android/dx/dex/file/HeaderSection.java deleted file mode 100644 index 9022e0f2b..000000000 --- a/dx/src/com/android/dx/dex/file/HeaderSection.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.dx.dex.file; - -import com.android.dx.rop.cst.Constant; - -import java.util.Collection; -import java.util.Collections; -import java.util.List; - -/** - * File header section of a <code>.dex</code> file. - */ -public final class HeaderSection extends UniformItemSection { - /** non-null; the list of the one item in the section */ - private final List<HeaderItem> list; - - /** - * Constructs an instance. The file offset is initially unknown. - * - * @param file non-null; file that this instance is part of - */ - public HeaderSection(DexFile file) { - super(null, file, 4); - - HeaderItem item = new HeaderItem(); - item.setIndex(0); - - this.list = Collections.singletonList(item); - } - - /** {@inheritDoc} */ - @Override - public IndexedItem get(Constant cst) { - return null; - } - - /** {@inheritDoc} */ - @Override - public Collection<? extends Item> items() { - return list; - } - - /** {@inheritDoc} */ - @Override - protected void orderItems() { - // Nothing to do here. - } -} diff --git a/dx/src/com/android/dx/dex/file/IdItem.java b/dx/src/com/android/dx/dex/file/IdItem.java deleted file mode 100644 index 8342514be..000000000 --- a/dx/src/com/android/dx/dex/file/IdItem.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.dx.dex.file; - -import com.android.dx.rop.cst.CstType; - -/** - * Representation of a reference to an item inside a Dalvik file. - */ -public abstract class IdItem extends IndexedItem { - /** - * non-null; the type constant for the defining class of - * the reference - */ - private final CstType type; - - /** - * Constructs an instance. - * - * @param type non-null; the type constant for the defining - * class of the reference - */ - public IdItem(CstType type) { - if (type == null) { - throw new NullPointerException("type == null"); - } - - this.type = type; - } - - /** {@inheritDoc} */ - @Override - public void addContents(DexFile file) { - TypeIdsSection typeIds = file.getTypeIds(); - typeIds.intern(type); - } - - /** - * Gets the type constant for the defining class of the - * reference. - * - * @return non-null; the type constant - */ - public final CstType getDefiningClass() { - return type; - } -} diff --git a/dx/src/com/android/dx/dex/file/IndexedItem.java b/dx/src/com/android/dx/dex/file/IndexedItem.java deleted file mode 100644 index 9bf7fd29a..000000000 --- a/dx/src/com/android/dx/dex/file/IndexedItem.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.dx.dex.file; - -/** - * An item in a Dalvik file which is referenced by index. - */ -public abstract class IndexedItem extends Item { - /** >= -1; assigned index of the item, or <code>-1</code> if not - * yet assigned */ - private int index; - - /** - * Constructs an instance. The index is initially unassigned. - */ - public IndexedItem() { - index = -1; - } - - /** - * Gets whether or not this instance has been assigned an index. - * - * @return <code>true</code> iff this instance has been assigned an index - */ - public final boolean hasIndex() { - return (index >= 0); - } - - /** - * Gets the item index. - * - * @return >= 0; the index - * @throws RuntimeException thrown if the item index is not yet assigned - */ - public final int getIndex() { - if (index < 0) { - throw new RuntimeException("index not yet set"); - } - - return index; - } - - /** - * Sets the item index. This method may only ever be called once - * per instance, and this will throw a <code>RuntimeException</code> if - * called a second (or subsequent) time. - * - * @param index >= 0; the item index - */ - public final void setIndex(int index) { - if (this.index != -1) { - throw new RuntimeException("index already set"); - } - - this.index = index; - } - - /** - * Gets the index of this item as a string, suitable for including in - * annotations. - * - * @return non-null; the index string - */ - public final String indexString() { - return '[' + Integer.toHexString(index) + ']'; - } -} diff --git a/dx/src/com/android/dx/dex/file/Item.java b/dx/src/com/android/dx/dex/file/Item.java deleted file mode 100644 index 3708d4561..000000000 --- a/dx/src/com/android/dx/dex/file/Item.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.dx.dex.file; - -import com.android.dx.util.AnnotatedOutput; - -/** - * Base class for any structurally-significant and (potentially) - * repeated piece of a Dalvik file. - */ -public abstract class Item { - /** - * Constructs an instance. - */ - public Item() { - // This space intentionally left blank. - } - - /** - * Returns the item type for this instance. - * - * @return non-null; the item type - */ - public abstract ItemType itemType(); - - /** - * Returns the human name for the particular type of item this - * instance is. - * - * @return non-null; the name - */ - public final String typeName() { - return itemType().toHuman(); - } - - /** - * Gets the size of this instance when written, in bytes. - * - * @return >= 0; the write size - */ - public abstract int writeSize(); - - /** - * Populates a {@link DexFile} with items from within this instance. - * This will <i>not</i> add an item to the file for this instance itself - * (which should have been done by whatever refers to this instance). - * - * <p><b>Note:</b> Subclasses must override this to do something - * appropriate.</p> - * - * @param file non-null; the file to populate - */ - public abstract void addContents(DexFile file); - - /** - * Writes the representation of this instance to the given data section, - * using the given {@link DexFile} to look things up as needed. - * If this instance keeps track of its offset, then this method will - * note the written offset and will also throw an exception if this - * instance has already been written. - * - * @param file non-null; the file to use for reference - * @param out non-null; where to write to - */ - public abstract void writeTo(DexFile file, AnnotatedOutput out); -} diff --git a/dx/src/com/android/dx/dex/file/ItemType.java b/dx/src/com/android/dx/dex/file/ItemType.java deleted file mode 100644 index ffa65735f..000000000 --- a/dx/src/com/android/dx/dex/file/ItemType.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.dx.dex.file; - -import com.android.dx.util.ToHuman; - -/** - * Enumeration of all the top-level item types. - */ -public enum ItemType implements ToHuman { - TYPE_HEADER_ITEM( 0x0000, "header_item"), - TYPE_STRING_ID_ITEM( 0x0001, "string_id_item"), - TYPE_TYPE_ID_ITEM( 0x0002, "type_id_item"), - TYPE_PROTO_ID_ITEM( 0x0003, "proto_id_item"), - TYPE_FIELD_ID_ITEM( 0x0004, "field_id_item"), - TYPE_METHOD_ID_ITEM( 0x0005, "method_id_item"), - TYPE_CLASS_DEF_ITEM( 0x0006, "class_def_item"), - TYPE_MAP_LIST( 0x1000, "map_list"), - TYPE_TYPE_LIST( 0x1001, "type_list"), - TYPE_ANNOTATION_SET_REF_LIST( 0x1002, "annotation_set_ref_list"), - TYPE_ANNOTATION_SET_ITEM( 0x1003, "annotation_set_item"), - TYPE_CLASS_DATA_ITEM( 0x2000, "class_data_item"), - TYPE_CODE_ITEM( 0x2001, "code_item"), - TYPE_STRING_DATA_ITEM( 0x2002, "string_data_item"), - TYPE_DEBUG_INFO_ITEM( 0x2003, "debug_info_item"), - TYPE_ANNOTATION_ITEM( 0x2004, "annotation_item"), - TYPE_ENCODED_ARRAY_ITEM( 0x2005, "encoded_array_item"), - TYPE_ANNOTATIONS_DIRECTORY_ITEM(0x2006, "annotations_directory_item"), - TYPE_MAP_ITEM( -1, "map_item"), - TYPE_TYPE_ITEM( -1, "type_item"), - TYPE_EXCEPTION_HANDLER_ITEM( -1, "exception_handler_item"), - TYPE_ANNOTATION_SET_REF_ITEM( -1, "annotation_set_ref_item"); - - /** value when represented in a {@link MapItem} */ - private final int mapValue; - - /** non-null; name of the type */ - private final String typeName; - - /** non-null; the short human name */ - private final String humanName; - - /** - * Constructs an instance. - * - * @param mapValue value when represented in a {@link MapItem} - * @param typeName non-null; name of the type - */ - private ItemType(int mapValue, String typeName) { - this.mapValue = mapValue; - this.typeName = typeName; - - // Make the human name. - String human = typeName; - if (human.endsWith("_item")) { - human = human.substring(0, human.length() - 5); - } - this.humanName = human.replace('_', ' '); - } - - /** - * Gets the map value. - * - * @return the map value - */ - public int getMapValue() { - return mapValue; - } - - /** - * Gets the type name. - * - * @return non-null; the type name - */ - public String getTypeName() { - return typeName; - } - - /** {@inheritDoc} */ - public String toHuman() { - return humanName; - } -} diff --git a/dx/src/com/android/dx/dex/file/MapItem.java b/dx/src/com/android/dx/dex/file/MapItem.java deleted file mode 100644 index 5e7465ce0..000000000 --- a/dx/src/com/android/dx/dex/file/MapItem.java +++ /dev/null @@ -1,235 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.dx.dex.file; - -import com.android.dx.util.AnnotatedOutput; -import com.android.dx.util.Hex; - -import java.util.ArrayList; - -/** - * Class that represents a map item. - */ -public final class MapItem extends OffsettedItem { - /** file alignment of this class, in bytes */ - private static final int ALIGNMENT = 4; - - /** write size of this class, in bytes: three <code>uint</code>s */ - private static final int WRITE_SIZE = (4 * 3); - - /** non-null; item type this instance covers */ - private final ItemType type; - - /** non-null; section this instance covers */ - private final Section section; - - /** - * null-ok; first item covered or <code>null</code> if this is - * a self-reference - */ - private final Item firstItem; - - /** - * null-ok; last item covered or <code>null</code> if this is - * a self-reference - */ - private final Item lastItem; - - /** - * > 0; count of items covered; <code>1</code> if this - * is a self-reference - */ - private final int itemCount; - - /** - * Constructs a list item with instances of this class representing - * the contents of the given array of sections, adding it to the - * given map section. - * - * @param sections non-null; the sections - * @param mapSection non-null; the section that the resulting map - * should be added to; it should be empty on entry to this method - */ - public static void addMap(Section[] sections, - MixedItemSection mapSection) { - if (sections == null) { - throw new NullPointerException("sections == null"); - } - - if (mapSection.items().size() != 0) { - throw new IllegalArgumentException( - "mapSection.items().size() != 0"); - } - - ArrayList<MapItem> items = new ArrayList<MapItem>(50); - - for (Section section : sections) { - ItemType currentType = null; - Item firstItem = null; - Item lastItem = null; - int count = 0; - - for (Item item : section.items()) { - ItemType type = item.itemType(); - if (type != currentType) { - if (count != 0) { - items.add(new MapItem(currentType, section, - firstItem, lastItem, count)); - } - currentType = type; - firstItem = item; - count = 0; - } - lastItem = item; - count++; - } - - if (count != 0) { - // Add a MapItem for the final items in the section. - items.add(new MapItem(currentType, section, - firstItem, lastItem, count)); - } else if (section == mapSection) { - // Add a MapItem for the self-referential section. - items.add(new MapItem(mapSection)); - } - } - - mapSection.add( - new UniformListItem<MapItem>(ItemType.TYPE_MAP_LIST, items)); - } - - /** - * Constructs an instance. - * - * @param type non-null; item type this instance covers - * @param section non-null; section this instance covers - * @param firstItem non-null; first item covered - * @param lastItem non-null; last item covered - * @param itemCount > 0; count of items covered - */ - private MapItem(ItemType type, Section section, Item firstItem, - Item lastItem, int itemCount) { - super(ALIGNMENT, WRITE_SIZE); - - if (type == null) { - throw new NullPointerException("type == null"); - } - - if (section == null) { - throw new NullPointerException("section == null"); - } - - if (firstItem == null) { - throw new NullPointerException("firstItem == null"); - } - - if (lastItem == null) { - throw new NullPointerException("lastItem == null"); - } - - if (itemCount <= 0) { - throw new IllegalArgumentException("itemCount <= 0"); - } - - this.type = type; - this.section = section; - this.firstItem = firstItem; - this.lastItem = lastItem; - this.itemCount = itemCount; - } - - /** - * Constructs a self-referential instance. This instance is meant to - * represent the section containing the <code>map_list</code>. - * - * @param section non-null; section this instance covers - */ - private MapItem(Section section) { - super(ALIGNMENT, WRITE_SIZE); - - if (section == null) { - throw new NullPointerException("section == null"); - } - - this.type = ItemType.TYPE_MAP_LIST; - this.section = section; - this.firstItem = null; - this.lastItem = null; - this.itemCount = 1; - } - - /** {@inheritDoc} */ - @Override - public ItemType itemType() { - return ItemType.TYPE_MAP_ITEM; - } - - /** {@inheritDoc} */ - @Override - public String toString() { - StringBuffer sb = new StringBuffer(100); - - sb.append(getClass().getName()); - sb.append('{'); - sb.append(section.toString()); - sb.append(' '); - sb.append(type.toHuman()); - sb.append('}'); - - return sb.toString(); - } - - /** {@inheritDoc} */ - @Override - public void addContents(DexFile file) { - // We have nothing to add. - } - - /** {@inheritDoc} */ - @Override - public final String toHuman() { - return toString(); - } - - /** {@inheritDoc} */ - @Override - protected void writeTo0(DexFile file, AnnotatedOutput out) { - int value = type.getMapValue(); - int offset; - - if (firstItem == null) { - offset = section.getFileOffset(); - } else { - offset = section.getAbsoluteItemOffset(firstItem); - } - - if (out.annotates()) { - out.annotate(0, offsetString() + ' ' + type.getTypeName() + - " map"); - out.annotate(2, " type: " + Hex.u2(value) + " // " + - type.toString()); - out.annotate(2, " unused: 0"); - out.annotate(4, " size: " + Hex.u4(itemCount)); - out.annotate(4, " offset: " + Hex.u4(offset)); - } - - out.writeShort(value); - out.writeShort(0); // unused - out.writeInt(itemCount); - out.writeInt(offset); - } -} diff --git a/dx/src/com/android/dx/dex/file/MemberIdItem.java b/dx/src/com/android/dx/dex/file/MemberIdItem.java deleted file mode 100644 index d43715259..000000000 --- a/dx/src/com/android/dx/dex/file/MemberIdItem.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.dx.dex.file; - -import com.android.dx.rop.cst.CstMemberRef; -import com.android.dx.rop.cst.CstNat; -import com.android.dx.util.AnnotatedOutput; -import com.android.dx.util.Hex; - -/** - * Representation of a member (field or method) reference inside a - * Dalvik file. - */ -public abstract class MemberIdItem extends IdItem { - /** size of instances when written out to a file, in bytes */ - public static final int WRITE_SIZE = 8; - - /** non-null; the constant for the member */ - private final CstMemberRef cst; - - /** - * Constructs an instance. - * - * @param cst non-null; the constant for the member - */ - public MemberIdItem(CstMemberRef cst) { - super(cst.getDefiningClass()); - - this.cst = cst; - } - - /** {@inheritDoc} */ - @Override - public int writeSize() { - return WRITE_SIZE; - } - - /** {@inheritDoc} */ - @Override - public void addContents(DexFile file) { - super.addContents(file); - - StringIdsSection stringIds = file.getStringIds(); - stringIds.intern(getRef().getNat().getName()); - } - - /** {@inheritDoc} */ - @Override - public final void writeTo(DexFile file, AnnotatedOutput out) { - TypeIdsSection typeIds = file.getTypeIds(); - StringIdsSection stringIds = file.getStringIds(); - CstNat nat = cst.getNat(); - int classIdx = typeIds.indexOf(getDefiningClass()); - int nameIdx = stringIds.indexOf(nat.getName()); - int typoidIdx = getTypoidIdx(file); - - if (out.annotates()) { - out.annotate(0, indexString() + ' ' + cst.toHuman()); - out.annotate(2, " class_idx: " + Hex.u2(classIdx)); - out.annotate(2, String.format(" %-10s %s", getTypoidName() + ':', - Hex.u2(typoidIdx))); - out.annotate(4, " name_idx: " + Hex.u4(nameIdx)); - } - - out.writeShort(classIdx); - out.writeShort(typoidIdx); - out.writeInt(nameIdx); - } - - /** - * Returns the index of the type-like thing associated with - * this item, in order that it may be written out. Subclasses must - * override this to get whatever it is they need to store. - * - * @param file non-null; the file being written - * @return the index in question - */ - protected abstract int getTypoidIdx(DexFile file); - - /** - * Returns the field name of the type-like thing associated with - * this item, for listing-generating purposes. Subclasses must override - * this. - * - * @return non-null; the name in question - */ - protected abstract String getTypoidName(); - - /** - * Gets the member constant. - * - * @return non-null; the constant - */ - public final CstMemberRef getRef() { - return cst; - } -} diff --git a/dx/src/com/android/dx/dex/file/MemberIdsSection.java b/dx/src/com/android/dx/dex/file/MemberIdsSection.java deleted file mode 100644 index 885b5590a..000000000 --- a/dx/src/com/android/dx/dex/file/MemberIdsSection.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.dx.dex.file; - -/** - * Member (field or method) refs list section of a <code>.dex</code> file. - */ -public abstract class MemberIdsSection extends UniformItemSection { - /** - * Constructs an instance. The file offset is initially unknown. - * - * @param name null-ok; the name of this instance, for annotation - * purposes - * @param file non-null; file that this instance is part of - */ - public MemberIdsSection(String name, DexFile file) { - super(name, file, 4); - } - - /** {@inheritDoc} */ - @Override - protected void orderItems() { - int idx = 0; - - for (Object i : items()) { - ((MemberIdItem) i).setIndex(idx); - idx++; - } - } -} diff --git a/dx/src/com/android/dx/dex/file/MethodAnnotationStruct.java b/dx/src/com/android/dx/dex/file/MethodAnnotationStruct.java deleted file mode 100644 index 175c1d29d..000000000 --- a/dx/src/com/android/dx/dex/file/MethodAnnotationStruct.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.dx.dex.file; - -import com.android.dx.rop.annotation.Annotations; -import com.android.dx.rop.cst.CstMethodRef; -import com.android.dx.util.AnnotatedOutput; -import com.android.dx.util.Hex; -import com.android.dx.util.ToHuman; - -/** - * Association of a method and its annotations. - */ -public final class MethodAnnotationStruct - implements ToHuman, Comparable<MethodAnnotationStruct> { - /** non-null; the method in question */ - private final CstMethodRef method; - - /** non-null; the associated annotations */ - private AnnotationSetItem annotations; - - /** - * Constructs an instance. - * - * @param method non-null; the method in question - * @param annotations non-null; the associated annotations - */ - public MethodAnnotationStruct(CstMethodRef method, - AnnotationSetItem annotations) { - if (method == null) { - throw new NullPointerException("method == null"); - } - - if (annotations == null) { - throw new NullPointerException("annotations == null"); - } - - this.method = method; - this.annotations = annotations; - } - - /** {@inheritDoc} */ - public int hashCode() { - return method.hashCode(); - } - - /** {@inheritDoc} */ - public boolean equals(Object other) { - if (! (other instanceof MethodAnnotationStruct)) { - return false; - } - - return method.equals(((MethodAnnotationStruct) other).method); - } - - /** {@inheritDoc} */ - public int compareTo(MethodAnnotationStruct other) { - return method.compareTo(other.method); - } - - /** {@inheritDoc} */ - public void addContents(DexFile file) { - MethodIdsSection methodIds = file.getMethodIds(); - MixedItemSection wordData = file.getWordData(); - - methodIds.intern(method); - annotations = wordData.intern(annotations); - } - - /** {@inheritDoc} */ - public void writeTo(DexFile file, AnnotatedOutput out) { - int methodIdx = file.getMethodIds().indexOf(method); - int annotationsOff = annotations.getAbsoluteOffset(); - - if (out.annotates()) { - out.annotate(0, " " + method.toHuman()); - out.annotate(4, " method_idx: " + Hex.u4(methodIdx)); - out.annotate(4, " annotations_off: " + - Hex.u4(annotationsOff)); - } - - out.writeInt(methodIdx); - out.writeInt(annotationsOff); - } - - /** {@inheritDoc} */ - public String toHuman() { - return method.toHuman() + ": " + annotations; - } - - /** - * Gets the method this item is for. - * - * @return non-null; the method - */ - public CstMethodRef getMethod() { - return method; - } - - /** - * Gets the associated annotations. - * - * @return non-null; the annotations - */ - public Annotations getAnnotations() { - return annotations.getAnnotations(); - } -} diff --git a/dx/src/com/android/dx/dex/file/MethodIdItem.java b/dx/src/com/android/dx/dex/file/MethodIdItem.java deleted file mode 100644 index 5d78e961c..000000000 --- a/dx/src/com/android/dx/dex/file/MethodIdItem.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.dx.dex.file; - -import com.android.dx.rop.cst.CstBaseMethodRef; - -/** - * Representation of a method reference inside a Dalvik file. - */ -public final class MethodIdItem extends MemberIdItem { - /** - * Constructs an instance. - * - * @param method non-null; the constant for the method - */ - public MethodIdItem(CstBaseMethodRef method) { - super(method); - } - - /** {@inheritDoc} */ - @Override - public ItemType itemType() { - return ItemType.TYPE_METHOD_ID_ITEM; - } - - /** {@inheritDoc} */ - @Override - public void addContents(DexFile file) { - super.addContents(file); - - ProtoIdsSection protoIds = file.getProtoIds(); - protoIds.intern(getMethodRef().getPrototype()); - } - - /** - * Gets the method constant. - * - * @return non-null; the constant - */ - public CstBaseMethodRef getMethodRef() { - return (CstBaseMethodRef) getRef(); - } - - /** {@inheritDoc} */ - @Override - protected int getTypoidIdx(DexFile file) { - ProtoIdsSection protoIds = file.getProtoIds(); - return protoIds.indexOf(getMethodRef().getPrototype()); - } - - /** {@inheritDoc} */ - @Override - protected String getTypoidName() { - return "proto_idx"; - } -} diff --git a/dx/src/com/android/dx/dex/file/MethodIdsSection.java b/dx/src/com/android/dx/dex/file/MethodIdsSection.java deleted file mode 100644 index 6ba7cac95..000000000 --- a/dx/src/com/android/dx/dex/file/MethodIdsSection.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.dx.dex.file; - -import com.android.dx.rop.cst.Constant; -import com.android.dx.rop.cst.CstBaseMethodRef; -import com.android.dx.util.AnnotatedOutput; -import com.android.dx.util.Hex; - -import java.util.Collection; -import java.util.TreeMap; - -/** - * Method refs list section of a <code>.dex</code> file. - */ -public final class MethodIdsSection extends MemberIdsSection { - /** - * non-null; map from method constants to {@link - * MethodIdItem} instances - */ - private final TreeMap<CstBaseMethodRef, MethodIdItem> methodIds; - - /** - * Constructs an instance. The file offset is initially unknown. - * - * @param file non-null; file that this instance is part of - */ - public MethodIdsSection(DexFile file) { - super("method_ids", file); - - methodIds = new TreeMap<CstBaseMethodRef, MethodIdItem>(); - } - - /** {@inheritDoc} */ - @Override - public Collection<? extends Item> items() { - return methodIds.values(); - } - - /** {@inheritDoc} */ - @Override - public IndexedItem get(Constant cst) { - if (cst == null) { - throw new NullPointerException("cst == null"); - } - - throwIfNotPrepared(); - - IndexedItem result = methodIds.get((CstBaseMethodRef) cst); - - if (result == null) { - throw new IllegalArgumentException("not found"); - } - - return result; - } - - /** - * Writes the portion of the file header that refers to this instance. - * - * @param out non-null; where to write - */ - public void writeHeaderPart(AnnotatedOutput out) { - throwIfNotPrepared(); - - int sz = methodIds.size(); - int offset = (sz == 0) ? 0 : getFileOffset(); - - if (out.annotates()) { - out.annotate(4, "method_ids_size: " + Hex.u4(sz)); - out.annotate(4, "method_ids_off: " + Hex.u4(offset)); - } - - out.writeInt(sz); - out.writeInt(offset); - } - - /** - * Interns an element into this instance. - * - * @param method non-null; the reference to intern - * @return non-null; the interned reference - */ - public MethodIdItem intern(CstBaseMethodRef method) { - if (method == null) { - throw new NullPointerException("method == null"); - } - - throwIfPrepared(); - - MethodIdItem result = methodIds.get(method); - - if (result == null) { - result = new MethodIdItem(method); - methodIds.put(method, result); - } - - return result; - } - - /** - * Gets the index of the given reference, which must have been added - * to this instance. - * - * @param ref non-null; the reference to look up - * @return >= 0; the reference's index - */ - public int indexOf(CstBaseMethodRef ref) { - if (ref == null) { - throw new NullPointerException("ref == null"); - } - - throwIfNotPrepared(); - - MethodIdItem item = methodIds.get(ref); - - if (item == null) { - throw new IllegalArgumentException("not found"); - } - - return item.getIndex(); - } -} diff --git a/dx/src/com/android/dx/dex/file/MixedItemSection.java b/dx/src/com/android/dx/dex/file/MixedItemSection.java deleted file mode 100644 index f03a9a387..000000000 --- a/dx/src/com/android/dx/dex/file/MixedItemSection.java +++ /dev/null @@ -1,362 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.dx.dex.file; - -import com.android.dx.util.AnnotatedOutput; -import com.android.dx.util.ExceptionWithContext; -import com.android.dx.util.Hex; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.Map; -import java.util.NoSuchElementException; -import java.util.TreeMap; - -/** - * A section of a <code>.dex</code> file which consists of a sequence of - * {@link OffsettedItem} objects, which may each be of a different concrete - * class and/or size. - * - * <b>Note:</b> It is invalid for an item in an instance of this class to - * have a larger alignment requirement than the alignment of this instance. - */ -public final class MixedItemSection extends Section { - static enum SortType { - /** no sorting */ - NONE, - - /** sort by type only */ - TYPE, - - /** sort in class-major order, with instances sorted per-class */ - INSTANCE; - }; - - /** non-null; sorter which sorts instances by type */ - private static final Comparator<OffsettedItem> TYPE_SORTER = - new Comparator<OffsettedItem>() { - public int compare(OffsettedItem item1, OffsettedItem item2) { - ItemType type1 = item1.itemType(); - ItemType type2 = item2.itemType(); - return type1.compareTo(type2); - } - }; - - /** non-null; the items in this part */ - private final ArrayList<OffsettedItem> items; - - /** non-null; items that have been explicitly interned */ - private final HashMap<OffsettedItem, OffsettedItem> interns; - - /** non-null; how to sort the items */ - private final SortType sort; - - /** - * >= -1; the current size of this part, in bytes, or <code>-1</code> - * if not yet calculated - */ - private int writeSize; - - /** - * Constructs an instance. The file offset is initially unknown. - * - * @param name null-ok; the name of this instance, for annotation - * purposes - * @param file non-null; file that this instance is part of - * @param alignment > 0; alignment requirement for the final output; - * must be a power of 2 - * @param sort how the items should be sorted in the final output - */ - public MixedItemSection(String name, DexFile file, int alignment, - SortType sort) { - super(name, file, alignment); - - this.items = new ArrayList<OffsettedItem>(100); - this.interns = new HashMap<OffsettedItem, OffsettedItem>(100); - this.sort = sort; - this.writeSize = -1; - } - - /** {@inheritDoc} */ - @Override - public Collection<? extends Item> items() { - return items; - } - - /** {@inheritDoc} */ - @Override - public int writeSize() { - throwIfNotPrepared(); - return writeSize; - } - - /** {@inheritDoc} */ - @Override - public int getAbsoluteItemOffset(Item item) { - OffsettedItem oi = (OffsettedItem) item; - return oi.getAbsoluteOffset(); - } - - /** - * Gets the size of this instance, in items. - * - * @return >= 0; the size - */ - public int size() { - return items.size(); - } - - /** - * Writes the portion of the file header that refers to this instance. - * - * @param out non-null; where to write - */ - public void writeHeaderPart(AnnotatedOutput out) { - throwIfNotPrepared(); - - if (writeSize == -1) { - throw new RuntimeException("write size not yet set"); - } - - int sz = writeSize; - int offset = (sz == 0) ? 0 : getFileOffset(); - String name = getName(); - - if (name == null) { - name = "<unnamed>"; - } - - int spaceCount = 15 - name.length(); - char[] spaceArr = new char[spaceCount]; - Arrays.fill(spaceArr, ' '); - String spaces = new String(spaceArr); - - if (out.annotates()) { - out.annotate(4, name + "_size:" + spaces + Hex.u4(sz)); - out.annotate(4, name + "_off: " + spaces + Hex.u4(offset)); - } - - out.writeInt(sz); - out.writeInt(offset); - } - - /** - * Adds an item to this instance. This will in turn tell the given item - * that it has been added to this instance. It is invalid to add the - * same item to more than one instance, nor to add the same items - * multiple times to a single instance. - * - * @param item non-null; the item to add - */ - public void add(OffsettedItem item) { - throwIfPrepared(); - - try { - if (item.getAlignment() > getAlignment()) { - throw new IllegalArgumentException( - "incompatible item alignment"); - } - } catch (NullPointerException ex) { - // Elucidate the exception. - throw new NullPointerException("item == null"); - } - - items.add(item); - } - - /** - * Interns an item in this instance, returning the interned instance - * (which may not be the one passed in). This will add the item if no - * equal item has been added. - * - * @param item non-null; the item to intern - * @return non-null; the equivalent interned instance - */ - public <T extends OffsettedItem> T intern(T item) { - throwIfPrepared(); - - OffsettedItem result = interns.get(item); - - if (result != null) { - return (T) result; - } - - add(item); - interns.put(item, item); - return item; - } - - /** - * Gets an item which was previously interned. - * - * @param item non-null; the item to look for - * @return non-null; the equivalent already-interned instance - */ - public <T extends OffsettedItem> T get(T item) { - throwIfNotPrepared(); - - OffsettedItem result = interns.get(item); - - if (result != null) { - return (T) result; - } - - throw new NoSuchElementException(item.toString()); - } - - /** - * Writes an index of contents of the items in this instance of the - * given type. If there are none, this writes nothing. If there are any, - * then the index is preceded by the given intro string. - * - * @param out non-null; where to write to - * @param itemType non-null; the item type of interest - * @param intro non-null; the introductory string for non-empty indices - */ - public void writeIndexAnnotation(AnnotatedOutput out, ItemType itemType, - String intro) { - throwIfNotPrepared(); - - TreeMap<String, OffsettedItem> index = - new TreeMap<String, OffsettedItem>(); - - for (OffsettedItem item : items) { - if (item.itemType() == itemType) { - String label = item.toHuman(); - index.put(label, item); - } - } - - if (index.size() == 0) { - return; - } - - out.annotate(0, intro); - - for (Map.Entry<String, OffsettedItem> entry : index.entrySet()) { - String label = entry.getKey(); - OffsettedItem item = entry.getValue(); - out.annotate(0, item.offsetString() + ' ' + label + '\n'); - } - } - - /** {@inheritDoc} */ - @Override - protected void prepare0() { - DexFile file = getFile(); - - /* - * It's okay for new items to be added as a result of an - * addContents() call; we just have to deal with the possibility. - */ - - int i = 0; - for (;;) { - int sz = items.size(); - if (i >= sz) { - break; - } - - for (/*i*/; i < sz; i++) { - OffsettedItem one = items.get(i); - one.addContents(file); - } - } - } - - /** - * Places all the items in this instance at particular offsets. This - * will call {@link OffsettedItem#place} on each item. If an item - * does not know its write size before the call to <code>place</code>, - * it is that call which is responsible for setting the write size. - * This method may only be called once per instance; subsequent calls - * will throw an exception. - */ - public void placeItems() { - throwIfNotPrepared(); - - switch (sort) { - case INSTANCE: { - Collections.sort(items); - break; - } - case TYPE: { - Collections.sort(items, TYPE_SORTER); - break; - } - } - - int sz = items.size(); - int outAt = 0; - for (int i = 0; i < sz; i++) { - OffsettedItem one = items.get(i); - try { - int placedAt = one.place(this, outAt); - - if (placedAt < outAt) { - throw new RuntimeException("bogus place() result for " + - one); - } - - outAt = placedAt + one.writeSize(); - } catch (RuntimeException ex) { - throw ExceptionWithContext.withContext(ex, - "...while placing " + one); - } - } - - writeSize = outAt; - } - - /** {@inheritDoc} */ - @Override - protected void writeTo0(AnnotatedOutput out) { - boolean annotates = out.annotates(); - boolean first = true; - DexFile file = getFile(); - int at = 0; - - for (OffsettedItem one : items) { - if (annotates) { - if (first) { - first = false; - } else { - out.annotate(0, "\n"); - } - } - - int alignMask = one.getAlignment() - 1; - int writeAt = (at + alignMask) & ~alignMask; - - if (at != writeAt) { - out.writeZeroes(writeAt - at); - at = writeAt; - } - - one.writeTo(file, out); - at += one.writeSize(); - } - - if (at != writeSize) { - throw new RuntimeException("output size mismatch"); - } - } -} diff --git a/dx/src/com/android/dx/dex/file/OffsettedItem.java b/dx/src/com/android/dx/dex/file/OffsettedItem.java deleted file mode 100644 index 030c37089..000000000 --- a/dx/src/com/android/dx/dex/file/OffsettedItem.java +++ /dev/null @@ -1,313 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.dx.dex.file; - -import com.android.dx.util.AnnotatedOutput; -import com.android.dx.util.ExceptionWithContext; - -/** - * An item in a Dalvik file which is referenced by absolute offset. - */ -public abstract class OffsettedItem extends Item - implements Comparable<OffsettedItem> { - /** > 0; alignment requirement */ - private final int alignment; - - /** >= -1; the size of this instance when written, in bytes, or - * <code>-1</code> if not yet known */ - private int writeSize; - - /** - * null-ok; section the item was added to, or <code>null</code> if - * not yet added - */ - private Section addedTo; - - /** - * >= -1; assigned offset of the item from the start of its section, - * or <code>-1</code> if not yet assigned - */ - private int offset; - - /** - * Gets the absolute offset of the given item, returning <code>0</code> - * if handed <code>null</code>. - * - * @param item null-ok; the item in question - * @return >= 0; the item's absolute offset, or <code>0</code> - * if <code>item == null</code> - */ - public static int getAbsoluteOffsetOr0(OffsettedItem item) { - if (item == null) { - return 0; - } - - return item.getAbsoluteOffset(); - } - - /** - * Constructs an instance. The offset is initially unassigned. - * - * @param alignment > 0; output alignment requirement; must be a - * power of 2 - * @param writeSize >= -1; the size of this instance when written, - * in bytes, or <code>-1</code> if not immediately known - */ - public OffsettedItem(int alignment, int writeSize) { - Section.validateAlignment(alignment); - - if (writeSize < -1) { - throw new IllegalArgumentException("writeSize < -1"); - } - - this.alignment = alignment; - this.writeSize = writeSize; - this.addedTo = null; - this.offset = -1; - } - - /** - * {@inheritDoc} - * - * Comparisons for this class are defined to be type-major (if the - * types don't match then the objects are not equal), with - * {@link #compareTo0} deciding same-type comparisons. - */ - @Override - public final boolean equals(Object other) { - if (this == other) { - return true; - } - - OffsettedItem otherItem = (OffsettedItem) other; - ItemType thisType = itemType(); - ItemType otherType = otherItem.itemType(); - - if (thisType != otherType) { - return false; - } - - return (compareTo0(otherItem) == 0); - } - - /** - * {@inheritDoc} - * - * Comparisons for this class are defined to be class-major (if the - * classes don't match then the objects are not equal), with - * {@link #compareTo0} deciding same-class comparisons. - */ - public final int compareTo(OffsettedItem other) { - if (this == other) { - return 0; - } - - ItemType thisType = itemType(); - ItemType otherType = other.itemType(); - - if (thisType != otherType) { - return thisType.compareTo(otherType); - } - - return compareTo0(other); - } - - /** - * Sets the write size of this item. This may only be called once - * per instance, and only if the size was unknown upon instance - * creation. - * - * @param writeSize > 0; the write size, in bytes - */ - public final void setWriteSize(int writeSize) { - if (writeSize < 0) { - throw new IllegalArgumentException("writeSize < 0"); - } - - if (this.writeSize >= 0) { - throw new UnsupportedOperationException("writeSize already set"); - } - - this.writeSize = writeSize; - } - - /** {@inheritDoc} - * - * @throws UnsupportedOperationException thrown if the write size - * is not yet known - */ - @Override - public final int writeSize() { - if (writeSize < 0) { - throw new UnsupportedOperationException("writeSize is unknown"); - } - - return writeSize; - } - - /** {@inheritDoc} */ - @Override - public final void writeTo(DexFile file, AnnotatedOutput out) { - out.alignTo(alignment); - - try { - if (writeSize < 0) { - throw new UnsupportedOperationException( - "writeSize is unknown"); - } - out.assertCursor(getAbsoluteOffset()); - } catch (RuntimeException ex) { - throw ExceptionWithContext.withContext(ex, - "...while writing " + this); - } - - writeTo0(file, out); - } - - /** - * Gets the relative item offset. The offset is from the start of - * the section which the instance was written to. - * - * @return >= 0; the offset - * @throws RuntimeException thrown if the offset is not yet known - */ - public final int getRelativeOffset() { - if (offset < 0) { - throw new RuntimeException("offset not yet known"); - } - - return offset; - } - - /** - * Gets the absolute item offset. The offset is from the start of - * the file which the instance was written to. - * - * @return >= 0; the offset - * @throws RuntimeException thrown if the offset is not yet known - */ - public final int getAbsoluteOffset() { - if (offset < 0) { - throw new RuntimeException("offset not yet known"); - } - - return addedTo.getAbsoluteOffset(offset); - } - - /** - * Indicates that this item has been added to the given section at - * the given offset. It is only valid to call this method once per - * instance. - * - * @param addedTo non-null; the section this instance has been added to - * @param offset >= 0; the desired offset from the start of the - * section where this instance was placed - * @return >= 0; the offset that this instance should be placed at - * in order to meet its alignment constraint - */ - public final int place(Section addedTo, int offset) { - if (addedTo == null) { - throw new NullPointerException("addedTo == null"); - } - - if (offset < 0) { - throw new IllegalArgumentException("offset < 0"); - } - - if (this.addedTo != null) { - throw new RuntimeException("already written"); - } - - int mask = alignment - 1; - offset = (offset + mask) & ~mask; - - this.addedTo = addedTo; - this.offset = offset; - - place0(addedTo, offset); - - return offset; - } - - /** - * Gets the alignment requirement of this instance. An instance should - * only be written when so aligned. - * - * @return > 0; the alignment requirement; must be a power of 2 - */ - public final int getAlignment() { - return alignment; - } - - /** - * Gets the absolute offset of this item as a string, suitable for - * including in annotations. - * - * @return non-null; the offset string - */ - public final String offsetString() { - return '[' + Integer.toHexString(getAbsoluteOffset()) + ']'; - } - - /** - * Gets a short human-readable string representing this instance. - * - * @return non-null; the human form - */ - public abstract String toHuman(); - - /** - * Compares this instance to another which is guaranteed to be of - * the same class. The default implementation of this method is to - * throw an exception (unsupported operation). If a particular - * class needs to actually sort, then it should override this - * method. - * - * @param other non-null; instance to compare to - * @return <code>-1</code>, <code>0</code>, or <code>1</code>, depending - * on the sort order of this instance and the other - */ - protected int compareTo0(OffsettedItem other) { - throw new UnsupportedOperationException("unsupported"); - } - - /** - * Does additional work required when placing an instance. The - * default implementation of this method is a no-op. If a - * particular class needs to do something special, then it should - * override this method. In particular, if this instance did not - * know its write size up-front, then this method is responsible - * for setting it. - * - * @param addedTo non-null; the section this instance has been added to - * @param offset >= 0; the offset from the start of the - * section where this instance was placed - */ - protected void place0(Section addedTo, int offset) { - // This space intentionally left blank. - } - - /** - * Performs the actual write of the contents of this instance to - * the given data section. This is called by {@link #writeTo}, - * which will have taken care of ensuring alignment. - * - * @param file non-null; the file to use for reference - * @param out non-null; where to write to - */ - protected abstract void writeTo0(DexFile file, AnnotatedOutput out); -} diff --git a/dx/src/com/android/dx/dex/file/ParameterAnnotationStruct.java b/dx/src/com/android/dx/dex/file/ParameterAnnotationStruct.java deleted file mode 100644 index 0c2d28692..000000000 --- a/dx/src/com/android/dx/dex/file/ParameterAnnotationStruct.java +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.dx.dex.file; - -import com.android.dx.rop.annotation.Annotations; -import com.android.dx.rop.annotation.AnnotationsList; -import com.android.dx.rop.cst.CstMethodRef; -import com.android.dx.util.AnnotatedOutput; -import com.android.dx.util.Hex; -import com.android.dx.util.ToHuman; - -import java.util.ArrayList; - -/** - * Association of a method and its parameter annotations. - */ -public final class ParameterAnnotationStruct - implements ToHuman, Comparable<ParameterAnnotationStruct> { - /** non-null; the method in question */ - private final CstMethodRef method; - - /** non-null; the associated annotations list */ - private final AnnotationsList annotationsList; - - /** non-null; the associated annotations list, as an item */ - private final UniformListItem<AnnotationSetRefItem> annotationsItem; - - /** - * Constructs an instance. - * - * @param method non-null; the method in question - * @param annotationsList non-null; the associated annotations list - */ - public ParameterAnnotationStruct(CstMethodRef method, - AnnotationsList annotationsList) { - if (method == null) { - throw new NullPointerException("method == null"); - } - - if (annotationsList == null) { - throw new NullPointerException("annotationsList == null"); - } - - this.method = method; - this.annotationsList = annotationsList; - - /* - * Construct an item for the annotations list. TODO: This - * requires way too much copying; fix it. - */ - - int size = annotationsList.size(); - ArrayList<AnnotationSetRefItem> arrayList = new - ArrayList<AnnotationSetRefItem>(size); - - for (int i = 0; i < size; i++) { - Annotations annotations = annotationsList.get(i); - AnnotationSetItem item = new AnnotationSetItem(annotations); - arrayList.add(new AnnotationSetRefItem(item)); - } - - this.annotationsItem = new UniformListItem<AnnotationSetRefItem>( - ItemType.TYPE_ANNOTATION_SET_REF_LIST, arrayList); - } - - /** {@inheritDoc} */ - public int hashCode() { - return method.hashCode(); - } - - /** {@inheritDoc} */ - public boolean equals(Object other) { - if (! (other instanceof ParameterAnnotationStruct)) { - return false; - } - - return method.equals(((ParameterAnnotationStruct) other).method); - } - - /** {@inheritDoc} */ - public int compareTo(ParameterAnnotationStruct other) { - return method.compareTo(other.method); - } - - /** {@inheritDoc} */ - public void addContents(DexFile file) { - MethodIdsSection methodIds = file.getMethodIds(); - MixedItemSection wordData = file.getWordData(); - - methodIds.intern(method); - wordData.add(annotationsItem); - } - - /** {@inheritDoc} */ - public void writeTo(DexFile file, AnnotatedOutput out) { - int methodIdx = file.getMethodIds().indexOf(method); - int annotationsOff = annotationsItem.getAbsoluteOffset(); - - if (out.annotates()) { - out.annotate(0, " " + method.toHuman()); - out.annotate(4, " method_idx: " + Hex.u4(methodIdx)); - out.annotate(4, " annotations_off: " + - Hex.u4(annotationsOff)); - } - - out.writeInt(methodIdx); - out.writeInt(annotationsOff); - } - - /** {@inheritDoc} */ - public String toHuman() { - StringBuilder sb = new StringBuilder(); - - sb.append(method.toHuman()); - sb.append(": "); - - boolean first = true; - for (AnnotationSetRefItem item : annotationsItem.getItems()) { - if (first) { - first = false; - } else { - sb.append(", "); - } - sb.append(item.toHuman()); - } - - return sb.toString(); - } - - /** - * Gets the method this item is for. - * - * @return non-null; the method - */ - public CstMethodRef getMethod() { - return method; - } - - /** - * Gets the associated annotations list. - * - * @return non-null; the annotations list - */ - public AnnotationsList getAnnotationsList() { - return annotationsList; - } -} diff --git a/dx/src/com/android/dx/dex/file/ProtoIdItem.java b/dx/src/com/android/dx/dex/file/ProtoIdItem.java deleted file mode 100644 index a144c304e..000000000 --- a/dx/src/com/android/dx/dex/file/ProtoIdItem.java +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.dx.dex.file; - -import com.android.dx.rop.cst.CstType; -import com.android.dx.rop.cst.CstUtf8; -import com.android.dx.rop.type.Prototype; -import com.android.dx.rop.type.StdTypeList; -import com.android.dx.rop.type.Type; -import com.android.dx.util.AnnotatedOutput; -import com.android.dx.util.Hex; - -/** - * Representation of a method prototype reference inside a Dalvik file. - */ -public final class ProtoIdItem extends IndexedItem { - /** size of instances when written out to a file, in bytes */ - public static final int WRITE_SIZE = 12; - - /** non-null; the wrapped prototype */ - private final Prototype prototype; - - /** non-null; the short-form of the prototype */ - private final CstUtf8 shortForm; - - /** - * null-ok; the list of parameter types or <code>null</code> if this - * prototype has no parameters - */ - private TypeListItem parameterTypes; - - /** - * Constructs an instance. - * - * @param prototype non-null; the constant for the prototype - */ - public ProtoIdItem(Prototype prototype) { - if (prototype == null) { - throw new NullPointerException("prototype == null"); - } - - this.prototype = prototype; - this.shortForm = makeShortForm(prototype); - - StdTypeList parameters = prototype.getParameterTypes(); - this.parameterTypes = (parameters.size() == 0) ? null - : new TypeListItem(parameters); - } - - /** - * Creates the short-form of the given prototype. - * - * @param prototype non-null; the prototype - * @return non-null; the short form - */ - private static CstUtf8 makeShortForm(Prototype prototype) { - StdTypeList parameters = prototype.getParameterTypes(); - int size = parameters.size(); - StringBuilder sb = new StringBuilder(size + 1); - - sb.append(shortFormCharFor(prototype.getReturnType())); - - for (int i = 0; i < size; i++) { - sb.append(shortFormCharFor(parameters.getType(i))); - } - - return new CstUtf8(sb.toString()); - } - - /** - * Gets the short-form character for the given type. - * - * @param type non-null; the type - * @return the corresponding short-form character - */ - private static char shortFormCharFor(Type type) { - char descriptorChar = type.getDescriptor().charAt(0); - - if (descriptorChar == '[') { - return 'L'; - } - - return descriptorChar; - } - - /** {@inheritDoc} */ - @Override - public ItemType itemType() { - return ItemType.TYPE_PROTO_ID_ITEM; - } - - /** {@inheritDoc} */ - @Override - public int writeSize() { - return WRITE_SIZE; - } - - /** {@inheritDoc} */ - @Override - public void addContents(DexFile file) { - StringIdsSection stringIds = file.getStringIds(); - TypeIdsSection typeIds = file.getTypeIds(); - MixedItemSection typeLists = file.getTypeLists(); - - typeIds.intern(prototype.getReturnType()); - stringIds.intern(shortForm); - - if (parameterTypes != null) { - parameterTypes = typeLists.intern(parameterTypes); - } - } - - /** {@inheritDoc} */ - @Override - public void writeTo(DexFile file, AnnotatedOutput out) { - int shortyIdx = file.getStringIds().indexOf(shortForm); - int returnIdx = file.getTypeIds().indexOf(prototype.getReturnType()); - int paramsOff = OffsettedItem.getAbsoluteOffsetOr0(parameterTypes); - - if (out.annotates()) { - StringBuilder sb = new StringBuilder(); - sb.append(prototype.getReturnType().toHuman()); - sb.append(" proto("); - - StdTypeList params = prototype.getParameterTypes(); - int size = params.size(); - - for (int i = 0; i < size; i++) { - if (i != 0) { - sb.append(", "); - } - sb.append(params.getType(i).toHuman()); - } - - sb.append(")"); - out.annotate(0, indexString() + ' ' + sb.toString()); - out.annotate(4, " shorty_idx: " + Hex.u4(shortyIdx) + - " // " + shortForm.toQuoted()); - out.annotate(4, " return_type_idx: " + Hex.u4(returnIdx) + - " // " + prototype.getReturnType().toHuman()); - out.annotate(4, " parameters_off: " + Hex.u4(paramsOff)); - } - - out.writeInt(shortyIdx); - out.writeInt(returnIdx); - out.writeInt(paramsOff); - } -} diff --git a/dx/src/com/android/dx/dex/file/ProtoIdsSection.java b/dx/src/com/android/dx/dex/file/ProtoIdsSection.java deleted file mode 100644 index 852ab9d5f..000000000 --- a/dx/src/com/android/dx/dex/file/ProtoIdsSection.java +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.dx.dex.file; - -import com.android.dx.rop.cst.Constant; -import com.android.dx.rop.type.Prototype; -import com.android.dx.util.AnnotatedOutput; -import com.android.dx.util.Hex; - -import java.util.Collection; -import java.util.TreeMap; - -/** - * Proto (method prototype) identifiers list section of a - * <code>.dex</code> file. - */ -public final class ProtoIdsSection extends UniformItemSection { - /** - * non-null; map from method prototypes to {@link ProtoIdItem} instances - */ - private final TreeMap<Prototype, ProtoIdItem> protoIds; - - /** - * Constructs an instance. The file offset is initially unknown. - * - * @param file non-null; file that this instance is part of - */ - public ProtoIdsSection(DexFile file) { - super("proto_ids", file, 4); - - protoIds = new TreeMap<Prototype, ProtoIdItem>(); - } - - /** {@inheritDoc} */ - @Override - public Collection<? extends Item> items() { - return protoIds.values(); - } - - /** {@inheritDoc} */ - @Override - public IndexedItem get(Constant cst) { - throw new UnsupportedOperationException("unsupported"); - } - - /** - * Writes the portion of the file header that refers to this instance. - * - * @param out non-null; where to write - */ - public void writeHeaderPart(AnnotatedOutput out) { - throwIfNotPrepared(); - - int sz = protoIds.size(); - int offset = (sz == 0) ? 0 : getFileOffset(); - - if (sz > 65536) { - throw new UnsupportedOperationException("too many proto ids"); - } - - if (out.annotates()) { - out.annotate(4, "proto_ids_size: " + Hex.u4(sz)); - out.annotate(4, "proto_ids_off: " + Hex.u4(offset)); - } - - out.writeInt(sz); - out.writeInt(offset); - } - - /** - * Interns an element into this instance. - * - * @param prototype non-null; the prototype to intern - * @return non-null; the interned reference - */ - public ProtoIdItem intern(Prototype prototype) { - if (prototype == null) { - throw new NullPointerException("prototype == null"); - } - - throwIfPrepared(); - - ProtoIdItem result = protoIds.get(prototype); - - if (result == null) { - result = new ProtoIdItem(prototype); - protoIds.put(prototype, result); - } - - return result; - } - - /** - * Gets the index of the given prototype, which must have - * been added to this instance. - * - * @param prototype non-null; the prototype to look up - * @return >= 0; the reference's index - */ - public int indexOf(Prototype prototype) { - if (prototype == null) { - throw new NullPointerException("prototype == null"); - } - - throwIfNotPrepared(); - - ProtoIdItem item = protoIds.get(prototype); - - if (item == null) { - throw new IllegalArgumentException("not found"); - } - - return item.getIndex(); - } - - /** {@inheritDoc} */ - @Override - protected void orderItems() { - int idx = 0; - - for (Object i : items()) { - ((ProtoIdItem) i).setIndex(idx); - idx++; - } - } -} diff --git a/dx/src/com/android/dx/dex/file/Section.java b/dx/src/com/android/dx/dex/file/Section.java deleted file mode 100644 index 9f7657c6c..000000000 --- a/dx/src/com/android/dx/dex/file/Section.java +++ /dev/null @@ -1,287 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.dx.dex.file; - -import com.android.dx.util.AnnotatedOutput; - -import java.util.Collection; - -/** - * A section of a <code>.dex</code> file. Each section consists of a list - * of items of some sort or other. - */ -public abstract class Section { - /** null-ok; name of this part, for annotation purposes */ - private final String name; - - /** non-null; file that this instance is part of */ - private final DexFile file; - - /** > 0; alignment requirement for the final output; - * must be a power of 2 */ - private final int alignment; - - /** >= -1; offset from the start of the file to this part, or - * <code>-1</code> if not yet known */ - private int fileOffset; - - /** whether {@link #prepare} has been called successfully on this - * instance */ - private boolean prepared; - - /** - * Validates an alignment. - * - * @param alignment the alignment - * @throws IllegalArgumentException thrown if <code>alignment</code> - * isn't a positive power of 2 - */ - public static void validateAlignment(int alignment) { - if ((alignment <= 0) || - (alignment & (alignment - 1)) != 0) { - throw new IllegalArgumentException("invalid alignment"); - } - } - - /** - * Constructs an instance. The file offset is initially unknown. - * - * @param name null-ok; the name of this instance, for annotation - * purposes - * @param file non-null; file that this instance is part of - * @param alignment > 0; alignment requirement for the final output; - * must be a power of 2 - */ - public Section(String name, DexFile file, int alignment) { - if (file == null) { - throw new NullPointerException("file == null"); - } - - validateAlignment(alignment); - - this.name = name; - this.file = file; - this.alignment = alignment; - this.fileOffset = -1; - this.prepared = false; - } - - /** - * Gets the file that this instance is part of. - * - * @return non-null; the file - */ - public final DexFile getFile() { - return file; - } - - /** - * Gets the alignment for this instance's final output. - * - * @return > 0; the alignment - */ - public final int getAlignment() { - return alignment; - } - - /** - * Gets the offset from the start of the file to this part. This - * throws an exception if the offset has not yet been set. - * - * @return >= 0; the file offset - */ - public final int getFileOffset() { - if (fileOffset < 0) { - throw new RuntimeException("fileOffset not set"); - } - - return fileOffset; - } - - /** - * Sets the file offset. It is only valid to call this method once - * once per instance. - * - * @param fileOffset >= 0; the desired offset from the start of the - * file where this for this instance - * @return >= 0; the offset that this instance should be placed at - * in order to meet its alignment constraint - */ - public final int setFileOffset(int fileOffset) { - if (fileOffset < 0) { - throw new IllegalArgumentException("fileOffset < 0"); - } - - if (this.fileOffset >= 0) { - throw new RuntimeException("fileOffset already set"); - } - - int mask = alignment - 1; - fileOffset = (fileOffset + mask) & ~mask; - - this.fileOffset = fileOffset; - - return fileOffset; - } - - /** - * Writes this instance to the given raw data object. - * - * @param out non-null; where to write to - */ - public final void writeTo(AnnotatedOutput out) { - throwIfNotPrepared(); - align(out); - - int cursor = out.getCursor(); - - if (fileOffset < 0) { - fileOffset = cursor; - } else if (fileOffset != cursor) { - throw new RuntimeException("alignment mismatch: for " + this + - ", at " + cursor + - ", but expected " + fileOffset); - } - - if (out.annotates()) { - if (name != null) { - out.annotate(0, "\n" + name + ":"); - } else if (cursor != 0) { - out.annotate(0, "\n"); - } - } - - writeTo0(out); - } - - /** - * Returns the absolute file offset, given an offset from the - * start of this instance's output. This is only valid to call - * once this instance has been assigned a file offset (via {@link - * #setFileOffset}). - * - * @param relative >= 0; the relative offset - * @return >= 0; the corresponding absolute file offset - */ - public final int getAbsoluteOffset(int relative) { - if (relative < 0) { - throw new IllegalArgumentException("relative < 0"); - } - - if (fileOffset < 0) { - throw new RuntimeException("fileOffset not yet set"); - } - - return fileOffset + relative; - } - - /** - * Returns the absolute file offset of the given item which must - * be contained in this section. This is only valid to call - * once this instance has been assigned a file offset (via {@link - * #setFileOffset}). - * - * <p><b>Note:</b> Subclasses must implement this as appropriate for - * their contents.</p> - * - * @param item non-null; the item in question - * @return >= 0; the item's absolute file offset - */ - public abstract int getAbsoluteItemOffset(Item item); - - /** - * Prepares this instance for writing. This performs any necessary - * prerequisites, including particularly adding stuff to other - * sections. This method may only be called once per instance; - * subsequent calls will throw an exception. - */ - public final void prepare() { - throwIfPrepared(); - prepare0(); - prepared = true; - } - - /** - * Gets the collection of all the items in this section. - * It is not valid to attempt to change the returned list. - * - * @return non-null; the items - */ - public abstract Collection<? extends Item> items(); - - /** - * Does the main work of {@link #prepare}. - */ - protected abstract void prepare0(); - - /** - * Gets the size of this instance when output, in bytes. - * - * @return >= 0; the size of this instance, in bytes - */ - public abstract int writeSize(); - - /** - * Throws an exception if {@link #prepare} has not been - * called on this instance. - */ - protected final void throwIfNotPrepared() { - if (!prepared) { - throw new RuntimeException("not prepared"); - } - } - - /** - * Throws an exception if {@link #prepare} has already been called - * on this instance. - */ - protected final void throwIfPrepared() { - if (prepared) { - throw new RuntimeException("already prepared"); - } - } - - /** - * Aligns the output of the given data to the alignment of this instance. - * - * @param out non-null; the output to align - */ - protected final void align(AnnotatedOutput out) { - out.alignTo(alignment); - } - - /** - * Writes this instance to the given raw data object. This gets - * called by {@link #writeTo} after aligning the cursor of - * <code>out</code> and verifying that either the assigned file - * offset matches the actual cursor <code>out</code> or that the - * file offset was not previously assigned, in which case it gets - * assigned to <code>out</code>'s cursor. - * - * @param out non-null; where to write to - */ - protected abstract void writeTo0(AnnotatedOutput out); - - /** - * Returns the name of this section, for annotation purposes. - * - * @return null-ok; name of this part, for annotation purposes - */ - protected final String getName() { - return name; - } -} diff --git a/dx/src/com/android/dx/dex/file/Statistics.java b/dx/src/com/android/dx/dex/file/Statistics.java deleted file mode 100644 index b11ab6eb1..000000000 --- a/dx/src/com/android/dx/dex/file/Statistics.java +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.dx.dex.file; - -import com.android.dx.util.AnnotatedOutput; - -import java.util.Collection; -import java.util.HashMap; -import java.util.TreeMap; - -/** - * Statistics about the contents of a file. - */ -public final class Statistics { - /** non-null; data about each type of item */ - private final HashMap<String, Data> dataMap; - - /** - * Constructs an instance. - */ - public Statistics() { - dataMap = new HashMap<String, Data>(50); - } - - /** - * Adds the given item to the statistics. - * - * @param item non-null; the item to add - */ - public void add(Item item) { - String typeName = item.typeName(); - Data data = dataMap.get(typeName); - - if (data == null) { - dataMap.put(typeName, new Data(item, typeName)); - } else { - data.add(item); - } - } - - /** - * Adds the given list of items to the statistics. - * - * @param list non-null; the list of items to add - */ - public void addAll(Section list) { - Collection<? extends Item> items = list.items(); - for (Item item : items) { - add(item); - } - } - - /** - * Writes the statistics as an annotation. - * - * @param out non-null; where to write to - */ - public final void writeAnnotation(AnnotatedOutput out) { - if (dataMap.size() == 0) { - return; - } - - out.annotate(0, "\nstatistics:\n"); - - TreeMap<String, Data> sortedData = new TreeMap<String, Data>(); - - for (Data data : dataMap.values()) { - sortedData.put(data.name, data); - } - - for (Data data : sortedData.values()) { - data.writeAnnotation(out); - } - } - - public String toHuman() { - StringBuilder sb = new StringBuilder(); - - sb.append("Statistics:\n"); - - TreeMap<String, Data> sortedData = new TreeMap<String, Data>(); - - for (Data data : dataMap.values()) { - sortedData.put(data.name, data); - } - - for (Data data : sortedData.values()) { - sb.append(data.toHuman()); - } - - return sb.toString(); - } - - /** - * Statistical data about a particular class. - */ - private static class Data { - /** non-null; name to use as a label */ - private final String name; - - /** >= 0; number of instances */ - private int count; - - /** >= 0; total size of instances in bytes */ - private int totalSize; - - /** >= 0; largest size of any individual item */ - private int largestSize; - - /** >= 0; smallest size of any individual item */ - private int smallestSize; - - /** - * Constructs an instance for the given item. - * - * @param item non-null; item in question - * @param name non-null; type name to use - */ - public Data(Item item, String name) { - int size = item.writeSize(); - - this.name = name; - this.count = 1; - this.totalSize = size; - this.largestSize = size; - this.smallestSize = size; - } - - /** - * Incorporates a new item. This assumes the type name matches. - * - * @param item non-null; item to incorporate - */ - public void add(Item item) { - int size = item.writeSize(); - - count++; - totalSize += size; - - if (size > largestSize) { - largestSize = size; - } - - if (size < smallestSize) { - smallestSize = size; - } - } - - /** - * Writes this instance as an annotation. - * - * @param out non-null; where to write to - */ - public void writeAnnotation(AnnotatedOutput out) { - out.annotate(toHuman()); - } - - /** - * Generates a human-readable string for this data item. - * - * @return string for human consumption. - */ - public String toHuman() { - StringBuilder sb = new StringBuilder(); - - sb.append(" " + name + ": " + - count + " item" + (count == 1 ? "" : "s") + "; " + - totalSize + " bytes total\n"); - - if (smallestSize == largestSize) { - sb.append(" " + smallestSize + " bytes/item\n"); - } else { - int average = totalSize / count; - sb.append(" " + smallestSize + ".." + largestSize + - " bytes/item; average " + average + "\n"); - } - - return sb.toString(); - } - } -} diff --git a/dx/src/com/android/dx/dex/file/StringDataItem.java b/dx/src/com/android/dx/dex/file/StringDataItem.java deleted file mode 100644 index 49eea5757..000000000 --- a/dx/src/com/android/dx/dex/file/StringDataItem.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.dx.dex.file; - -import com.android.dx.rop.cst.CstUtf8; -import com.android.dx.util.AnnotatedOutput; -import com.android.dx.util.ByteArray; -import com.android.dx.util.Hex; -import com.android.dx.util.Leb128Utils; - -/** - * Representation of string data for a particular string, in a Dalvik file. - */ -public final class StringDataItem extends OffsettedItem { - /** non-null; the string value */ - private final CstUtf8 value; - - /** - * Constructs an instance. - * - * @param value non-null; the string value - */ - public StringDataItem(CstUtf8 value) { - super(1, writeSize(value)); - - this.value = value; - } - - /** - * Gets the write size for a given value. - * - * @param value non-null; the string value - * @return >= 2 the write size, in bytes - */ - private static int writeSize(CstUtf8 value) { - int utf16Size = value.getUtf16Size(); - - // The +1 is for the '\0' termination byte. - return Leb128Utils.unsignedLeb128Size(utf16Size) - + value.getUtf8Size() + 1; - } - - /** {@inheritDoc} */ - @Override - public ItemType itemType() { - return ItemType.TYPE_STRING_DATA_ITEM; - } - - /** {@inheritDoc} */ - @Override - public void addContents(DexFile file) { - // Nothing to do here. - } - - /** {@inheritDoc} */ - @Override - public void writeTo0(DexFile file, AnnotatedOutput out) { - ByteArray bytes = value.getBytes(); - int utf16Size = value.getUtf16Size(); - - if (out.annotates()) { - out.annotate(Leb128Utils.unsignedLeb128Size(utf16Size), - "utf16_size: " + Hex.u4(utf16Size)); - out.annotate(bytes.size() + 1, value.toQuoted()); - } - - out.writeUnsignedLeb128(utf16Size); - out.write(bytes); - out.writeByte(0); - } - - /** {@inheritDoc} */ - @Override - public String toHuman() { - return value.toQuoted(); - } - - /** {@inheritDoc} */ - @Override - protected int compareTo0(OffsettedItem other) { - StringDataItem otherData = (StringDataItem) other; - - return value.compareTo(otherData.value); - } -} diff --git a/dx/src/com/android/dx/dex/file/StringIdItem.java b/dx/src/com/android/dx/dex/file/StringIdItem.java deleted file mode 100644 index e80a7f877..000000000 --- a/dx/src/com/android/dx/dex/file/StringIdItem.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.dx.dex.file; - -import com.android.dx.rop.cst.CstUtf8; -import com.android.dx.util.AnnotatedOutput; -import com.android.dx.util.Hex; - -/** - * Representation of a string inside a Dalvik file. - */ -public final class StringIdItem - extends IndexedItem implements Comparable { - /** size of instances when written out to a file, in bytes */ - public static final int WRITE_SIZE = 4; - - /** non-null; the string value */ - private final CstUtf8 value; - - /** null-ok; associated string data object, if known */ - private StringDataItem data; - - /** - * Constructs an instance. - * - * @param value non-null; the string value - */ - public StringIdItem(CstUtf8 value) { - if (value == null) { - throw new NullPointerException("value == null"); - } - - this.value = value; - this.data = null; - } - - /** {@inheritDoc} */ - @Override - public boolean equals(Object other) { - if (!(other instanceof StringIdItem)) { - return false; - } - - StringIdItem otherString = (StringIdItem) other; - return value.equals(otherString.value); - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - return value.hashCode(); - } - - /** {@inheritDoc} */ - public int compareTo(Object other) { - StringIdItem otherString = (StringIdItem) other; - return value.compareTo(otherString.value); - } - - /** {@inheritDoc} */ - @Override - public ItemType itemType() { - return ItemType.TYPE_STRING_ID_ITEM; - } - - /** {@inheritDoc} */ - @Override - public int writeSize() { - return WRITE_SIZE; - } - - /** {@inheritDoc} */ - @Override - public void addContents(DexFile file) { - if (data == null) { - // The string data hasn't yet been added, so add it. - MixedItemSection stringData = file.getStringData(); - data = new StringDataItem(value); - stringData.add(data); - } - } - - /** {@inheritDoc} */ - @Override - public void writeTo(DexFile file, AnnotatedOutput out) { - int dataOff = data.getAbsoluteOffset(); - - if (out.annotates()) { - out.annotate(0, indexString() + ' ' + value.toQuoted(100)); - out.annotate(4, " string_data_off: " + Hex.u4(dataOff)); - } - - out.writeInt(dataOff); - } - - /** - * Gets the string value. - * - * @return non-null; the value - */ - public CstUtf8 getValue() { - return value; - } - - /** - * Gets the associated data object for this instance, if known. - * - * @return null-ok; the associated data object or <code>null</code> - * if not yet known - */ - public StringDataItem getData() { - return data; - } -} diff --git a/dx/src/com/android/dx/dex/file/StringIdsSection.java b/dx/src/com/android/dx/dex/file/StringIdsSection.java deleted file mode 100644 index 17fbb578b..000000000 --- a/dx/src/com/android/dx/dex/file/StringIdsSection.java +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.dx.dex.file; - -import com.android.dx.rop.cst.Constant; -import com.android.dx.rop.cst.CstNat; -import com.android.dx.rop.cst.CstString; -import com.android.dx.rop.cst.CstUtf8; -import com.android.dx.util.AnnotatedOutput; -import com.android.dx.util.Hex; - -import java.util.Collection; -import java.util.TreeMap; - -/** - * Strings list section of a <code>.dex</code> file. - */ -public final class StringIdsSection - extends UniformItemSection { - /** - * non-null; map from string constants to {@link - * StringIdItem} instances - */ - private final TreeMap<CstUtf8, StringIdItem> strings; - - /** - * Constructs an instance. The file offset is initially unknown. - * - * @param file non-null; file that this instance is part of - */ - public StringIdsSection(DexFile file) { - super("string_ids", file, 4); - - strings = new TreeMap<CstUtf8, StringIdItem>(); - } - - /** {@inheritDoc} */ - @Override - public Collection<? extends Item> items() { - return strings.values(); - } - - /** {@inheritDoc} */ - @Override - public IndexedItem get(Constant cst) { - if (cst == null) { - throw new NullPointerException("cst == null"); - } - - throwIfNotPrepared(); - - if (cst instanceof CstString) { - cst = ((CstString) cst).getString(); - } - - IndexedItem result = strings.get((CstUtf8) cst); - - if (result == null) { - throw new IllegalArgumentException("not found"); - } - - return result; - } - - /** - * Writes the portion of the file header that refers to this instance. - * - * @param out non-null; where to write - */ - public void writeHeaderPart(AnnotatedOutput out) { - throwIfNotPrepared(); - - int sz = strings.size(); - int offset = (sz == 0) ? 0 : getFileOffset(); - - if (out.annotates()) { - out.annotate(4, "string_ids_size: " + Hex.u4(sz)); - out.annotate(4, "string_ids_off: " + Hex.u4(offset)); - } - - out.writeInt(sz); - out.writeInt(offset); - } - - /** - * Interns an element into this instance. - * - * @param string non-null; the string to intern, as a regular Java - * <code>String</code> - * @return non-null; the interned string - */ - public StringIdItem intern(String string) { - CstUtf8 utf8 = new CstUtf8(string); - return intern(new StringIdItem(utf8)); - } - - /** - * Interns an element into this instance. - * - * @param string non-null; the string to intern, as a {@link CstString} - * @return non-null; the interned string - */ - public StringIdItem intern(CstString string) { - CstUtf8 utf8 = string.getString(); - return intern(new StringIdItem(utf8)); - } - - /** - * Interns an element into this instance. - * - * @param string non-null; the string to intern, as a constant - * @return non-null; the interned string - */ - public StringIdItem intern(CstUtf8 string) { - return intern(new StringIdItem(string)); - } - - /** - * Interns an element into this instance. - * - * @param string non-null; the string to intern - * @return non-null; the interned string - */ - public StringIdItem intern(StringIdItem string) { - if (string == null) { - throw new NullPointerException("string == null"); - } - - throwIfPrepared(); - - CstUtf8 value = string.getValue(); - StringIdItem already = strings.get(value); - - if (already != null) { - return already; - } - - strings.put(value, string); - return string; - } - - /** - * Interns the components of a name-and-type into this instance. - * - * @param nat non-null; the name-and-type - */ - public void intern(CstNat nat) { - intern(nat.getName()); - intern(nat.getDescriptor()); - } - - /** - * Gets the index of the given string, which must have been added - * to this instance. - * - * @param string non-null; the string to look up - * @return >= 0; the string's index - */ - public int indexOf(CstUtf8 string) { - if (string == null) { - throw new NullPointerException("string == null"); - } - - throwIfNotPrepared(); - - StringIdItem s = strings.get(string); - - if (s == null) { - throw new IllegalArgumentException("not found"); - } - - return s.getIndex(); - } - - /** - * Gets the index of the given string, which must have been added - * to this instance. - * - * @param string non-null; the string to look up - * @return >= 0; the string's index - */ - public int indexOf(CstString string) { - return indexOf(string.getString()); - } - - /** {@inheritDoc} */ - @Override - protected void orderItems() { - int idx = 0; - - for (StringIdItem s : strings.values()) { - s.setIndex(idx); - idx++; - } - } -} diff --git a/dx/src/com/android/dx/dex/file/TypeIdItem.java b/dx/src/com/android/dx/dex/file/TypeIdItem.java deleted file mode 100644 index f3402e643..000000000 --- a/dx/src/com/android/dx/dex/file/TypeIdItem.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.dx.dex.file; - -import com.android.dx.rop.cst.CstType; -import com.android.dx.rop.cst.CstUtf8; -import com.android.dx.util.AnnotatedOutput; -import com.android.dx.util.Hex; - -/** - * Representation of a type reference inside a Dalvik file. - */ -public final class TypeIdItem extends IdItem { - /** size of instances when written out to a file, in bytes */ - public static final int WRITE_SIZE = 4; - - /** - * Constructs an instance. - * - * @param type non-null; the constant for the type - */ - public TypeIdItem(CstType type) { - super(type); - } - - /** {@inheritDoc} */ - @Override - public ItemType itemType() { - return ItemType.TYPE_TYPE_ID_ITEM; - } - - /** {@inheritDoc} */ - @Override - public int writeSize() { - return WRITE_SIZE; - } - - /** {@inheritDoc} */ - @Override - public void addContents(DexFile file) { - file.getStringIds().intern(getDefiningClass().getDescriptor()); - } - - /** {@inheritDoc} */ - @Override - public void writeTo(DexFile file, AnnotatedOutput out) { - CstType type = getDefiningClass(); - CstUtf8 descriptor = type.getDescriptor(); - int idx = file.getStringIds().indexOf(descriptor); - - if (out.annotates()) { - out.annotate(0, indexString() + ' ' + descriptor.toHuman()); - out.annotate(4, " descriptor_idx: " + Hex.u4(idx)); - } - - out.writeInt(idx); - } -} diff --git a/dx/src/com/android/dx/dex/file/TypeIdsSection.java b/dx/src/com/android/dx/dex/file/TypeIdsSection.java deleted file mode 100644 index 296263f09..000000000 --- a/dx/src/com/android/dx/dex/file/TypeIdsSection.java +++ /dev/null @@ -1,192 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.dx.dex.file; - -import com.android.dx.rop.cst.Constant; -import com.android.dx.rop.cst.CstType; -import com.android.dx.rop.type.Type; -import com.android.dx.util.AnnotatedOutput; -import com.android.dx.util.Hex; - -import java.util.Collection; -import java.util.TreeMap; - -/** - * Type identifiers list section of a <code>.dex</code> file. - */ -public final class TypeIdsSection extends UniformItemSection { - /** - * non-null; map from types to {@link TypeIdItem} instances - */ - private final TreeMap<Type, TypeIdItem> typeIds; - - /** - * Constructs an instance. The file offset is initially unknown. - * - * @param file non-null; file that this instance is part of - */ - public TypeIdsSection(DexFile file) { - super("type_ids", file, 4); - - typeIds = new TreeMap<Type, TypeIdItem>(); - } - - /** {@inheritDoc} */ - @Override - public Collection<? extends Item> items() { - return typeIds.values(); - } - - /** {@inheritDoc} */ - @Override - public IndexedItem get(Constant cst) { - if (cst == null) { - throw new NullPointerException("cst == null"); - } - - throwIfNotPrepared(); - - Type type = ((CstType) cst).getClassType(); - IndexedItem result = typeIds.get(type); - - if (result == null) { - throw new IllegalArgumentException("not found: " + cst); - } - - return result; - } - - /** - * Writes the portion of the file header that refers to this instance. - * - * @param out non-null; where to write - */ - public void writeHeaderPart(AnnotatedOutput out) { - throwIfNotPrepared(); - - int sz = typeIds.size(); - int offset = (sz == 0) ? 0 : getFileOffset(); - - if (sz > 65536) { - throw new UnsupportedOperationException("too many type ids"); - } - - if (out.annotates()) { - out.annotate(4, "type_ids_size: " + Hex.u4(sz)); - out.annotate(4, "type_ids_off: " + Hex.u4(offset)); - } - - out.writeInt(sz); - out.writeInt(offset); - } - - /** - * Interns an element into this instance. - * - * @param type non-null; the type to intern - * @return non-null; the interned reference - */ - public TypeIdItem intern(Type type) { - if (type == null) { - throw new NullPointerException("type == null"); - } - - throwIfPrepared(); - - TypeIdItem result = typeIds.get(type); - - if (result == null) { - result = new TypeIdItem(new CstType(type)); - typeIds.put(type, result); - } - - return result; - } - - /** - * Interns an element into this instance. - * - * @param type non-null; the type to intern - * @return non-null; the interned reference - */ - public TypeIdItem intern(CstType type) { - if (type == null) { - throw new NullPointerException("type == null"); - } - - throwIfPrepared(); - - Type typePerSe = type.getClassType(); - TypeIdItem result = typeIds.get(typePerSe); - - if (result == null) { - result = new TypeIdItem(type); - typeIds.put(typePerSe, result); - } - - return result; - } - - /** - * Gets the index of the given type, which must have - * been added to this instance. - * - * @param type non-null; the type to look up - * @return >= 0; the reference's index - */ - public int indexOf(Type type) { - if (type == null) { - throw new NullPointerException("type == null"); - } - - throwIfNotPrepared(); - - TypeIdItem item = typeIds.get(type); - - if (item == null) { - throw new IllegalArgumentException("not found: " + type); - } - - return item.getIndex(); - } - - /** - * Gets the index of the given type, which must have - * been added to this instance. - * - * @param type non-null; the type to look up - * @return >= 0; the reference's index - */ - public int indexOf(CstType type) { - if (type == null) { - throw new NullPointerException("type == null"); - } - - return indexOf(type.getClassType()); - } - - /** {@inheritDoc} */ - @Override - protected void orderItems() { - int idx = 0; - - for (Object i : items()) { - ((TypeIdItem) i).setIndex(idx); - idx++; - } - } -} diff --git a/dx/src/com/android/dx/dex/file/TypeListItem.java b/dx/src/com/android/dx/dex/file/TypeListItem.java deleted file mode 100644 index 6557ca415..000000000 --- a/dx/src/com/android/dx/dex/file/TypeListItem.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.dx.dex.file; - -import com.android.dx.rop.cst.CstType; -import com.android.dx.rop.type.StdTypeList; -import com.android.dx.rop.type.Type; -import com.android.dx.rop.type.TypeList; -import com.android.dx.util.AnnotatedOutput; -import com.android.dx.util.Hex; - -/** - * Representation of a list of class references. - */ -public final class TypeListItem extends OffsettedItem { - /** alignment requirement */ - private static final int ALIGNMENT = 4; - - /** element size in bytes */ - private static final int ELEMENT_SIZE = 2; - - /** header size in bytes */ - private static final int HEADER_SIZE = 4; - - /** non-null; the actual list */ - private final TypeList list; - - /** - * Constructs an instance. - * - * @param list non-null; the actual list - */ - public TypeListItem(TypeList list) { - super(ALIGNMENT, (list.size() * ELEMENT_SIZE) + HEADER_SIZE); - - this.list = list; - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - return StdTypeList.hashContents(list); - } - - /** {@inheritDoc} */ - @Override - public ItemType itemType() { - return ItemType.TYPE_TYPE_LIST; - } - - /** {@inheritDoc} */ - public void addContents(DexFile file) { - TypeIdsSection typeIds = file.getTypeIds(); - int sz = list.size(); - - for (int i = 0; i < sz; i++) { - typeIds.intern(list.getType(i)); - } - } - - /** {@inheritDoc} */ - @Override - public String toHuman() { - throw new RuntimeException("unsupported"); - } - - /** - * Gets the underlying list. - * - * @return non-null; the list - */ - public TypeList getList() { - return list; - } - - /** {@inheritDoc} */ - @Override - protected void writeTo0(DexFile file, AnnotatedOutput out) { - TypeIdsSection typeIds = file.getTypeIds(); - int sz = list.size(); - - if (out.annotates()) { - out.annotate(0, offsetString() + " type_list"); - out.annotate(HEADER_SIZE, " size: " + Hex.u4(sz)); - for (int i = 0; i < sz; i++) { - Type one = list.getType(i); - int idx = typeIds.indexOf(one); - out.annotate(ELEMENT_SIZE, - " " + Hex.u2(idx) + " // " + one.toHuman()); - } - } - - out.writeInt(sz); - - for (int i = 0; i < sz; i++) { - out.writeShort(typeIds.indexOf(list.getType(i))); - } - } - - /** {@inheritDoc} */ - @Override - protected int compareTo0(OffsettedItem other) { - TypeList thisList = this.list; - TypeList otherList = ((TypeListItem) other).list; - - return StdTypeList.compareContents(thisList, otherList); - } -} diff --git a/dx/src/com/android/dx/dex/file/UniformItemSection.java b/dx/src/com/android/dx/dex/file/UniformItemSection.java deleted file mode 100644 index 602bc2dcb..000000000 --- a/dx/src/com/android/dx/dex/file/UniformItemSection.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.dx.dex.file; - -import com.android.dx.rop.cst.Constant; -import com.android.dx.util.AnnotatedOutput; - -import java.util.Collection; - -/** - * A section of a <code>.dex</code> file which consists of a sequence of - * {@link Item} objects. Each of the items must have the same size in - * the output. - */ -public abstract class UniformItemSection extends Section { - /** - * Constructs an instance. The file offset is initially unknown. - * - * @param name null-ok; the name of this instance, for annotation - * purposes - * @param file non-null; file that this instance is part of - * @param alignment > 0; alignment requirement for the final output; - * must be a power of 2 - */ - public UniformItemSection(String name, DexFile file, int alignment) { - super(name, file, alignment); - } - - /** {@inheritDoc} */ - @Override - public final int writeSize() { - Collection<? extends Item> items = items(); - int sz = items.size(); - - if (sz == 0) { - return 0; - } - - // Since each item has to be the same size, we can pick any. - return sz * items.iterator().next().writeSize(); - } - - /** - * Gets the item corresponding to the given {@link Constant}. This - * will throw an exception if the constant is not found, including - * if this instance isn't the sort that maps constants to {@link - * IndexedItem} instances. - * - * @param cst non-null; constant to look for - * @return non-null; the corresponding item found in this instance - */ - public abstract IndexedItem get(Constant cst); - - /** {@inheritDoc} */ - @Override - protected final void prepare0() { - DexFile file = getFile(); - - orderItems(); - - for (Item one : items()) { - one.addContents(file); - } - } - - /** {@inheritDoc} */ - @Override - protected final void writeTo0(AnnotatedOutput out) { - DexFile file = getFile(); - int alignment = getAlignment(); - - for (Item one : items()) { - one.writeTo(file, out); - out.alignTo(alignment); - } - } - - /** {@inheritDoc} */ - @Override - public final int getAbsoluteItemOffset(Item item) { - /* - * Since all items must be the same size, we can use the size - * of the one we're given to calculate its offset. - */ - IndexedItem ii = (IndexedItem) item; - int relativeOffset = ii.getIndex() * ii.writeSize(); - - return getAbsoluteOffset(relativeOffset); - } - - /** - * Alters or picks the order for items in this instance if desired, - * so that subsequent calls to {@link #items} will yield a - * so-ordered collection. If the items in this instance are indexed, - * then this method should also assign indices. - */ - protected abstract void orderItems(); -} diff --git a/dx/src/com/android/dx/dex/file/UniformListItem.java b/dx/src/com/android/dx/dex/file/UniformListItem.java deleted file mode 100644 index 3af39428a..000000000 --- a/dx/src/com/android/dx/dex/file/UniformListItem.java +++ /dev/null @@ -1,216 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.dx.dex.file; - -import com.android.dx.util.AnnotatedOutput; -import com.android.dx.util.Hex; - -import java.util.HashMap; -import java.util.List; - -/** - * Class that represents a contiguous list of uniform items. Each - * item in the list, in particular, must have the same write size and - * alignment. - * - * <p>This class inherits its alignment from its items, bumped up to - * <code>4</code> if the items have a looser alignment requirement. If - * it is more than <code>4</code>, then there will be a gap after the - * output list size (which is four bytes) and before the first item.</p> - * - * @param <T> type of element contained in an instance - */ -public final class UniformListItem<T extends OffsettedItem> - extends OffsettedItem { - /** the size of the list header */ - private static final int HEADER_SIZE = 4; - - /** non-null; the item type */ - private final ItemType itemType; - - /** non-null; the contents */ - private final List<T> items; - - /** - * Constructs an instance. It is illegal to modify the given list once - * it is used to construct an instance of this class. - * - * @param itemType non-null; the type of the item - * @param items non-null and non-empty; list of items to represent - */ - public UniformListItem(ItemType itemType, List<T> items) { - super(getAlignment(items), writeSize(items)); - - if (itemType == null) { - throw new NullPointerException("itemType == null"); - } - - this.items = items; - this.itemType = itemType; - } - - /** - * Helper for {@link #UniformListItem}, which returns the alignment - * requirement implied by the given list. See the header comment for - * more details. - * - * @param items non-null; list of items being represented - * @return >= 4; the alignment requirement - */ - private static int getAlignment(List<? extends OffsettedItem> items) { - try { - // Since they all must have the same alignment, any one will do. - return Math.max(HEADER_SIZE, items.get(0).getAlignment()); - } catch (IndexOutOfBoundsException ex) { - // Translate the exception. - throw new IllegalArgumentException("items.size() == 0"); - } catch (NullPointerException ex) { - // Translate the exception. - throw new NullPointerException("items == null"); - } - } - - /** - * Calculates the write size for the given list. - * - * @param items non-null; the list in question - * @return >= 0; the write size - */ - private static int writeSize(List<? extends OffsettedItem> items) { - /* - * This class assumes all included items are the same size, - * an assumption which is verified in place0(). - */ - OffsettedItem first = items.get(0); - return (items.size() * first.writeSize()) + getAlignment(items); - } - - /** {@inheritDoc} */ - @Override - public ItemType itemType() { - return itemType; - } - - /** {@inheritDoc} */ - @Override - public String toString() { - StringBuffer sb = new StringBuffer(100); - - sb.append(getClass().getName()); - sb.append(items); - - return sb.toString(); - } - - /** {@inheritDoc} */ - @Override - public void addContents(DexFile file) { - for (OffsettedItem i : items) { - i.addContents(file); - } - } - - /** {@inheritDoc} */ - @Override - public final String toHuman() { - StringBuffer sb = new StringBuffer(100); - boolean first = true; - - sb.append("{"); - - for (OffsettedItem i : items) { - if (first) { - first = false; - } else { - sb.append(", "); - } - sb.append(i.toHuman()); - } - - sb.append("}"); - return sb.toString(); - } - - /** - * Gets the underlying list of items. - * - * @return non-null; the list - */ - public final List<T> getItems() { - return items; - } - - /** {@inheritDoc} */ - @Override - protected void place0(Section addedTo, int offset) { - offset += headerSize(); - - boolean first = true; - int theSize = -1; - int theAlignment = -1; - - for (OffsettedItem i : items) { - int size = i.writeSize(); - if (first) { - theSize = size; - theAlignment = i.getAlignment(); - first = false; - } else { - if (size != theSize) { - throw new UnsupportedOperationException( - "item size mismatch"); - } - if (i.getAlignment() != theAlignment) { - throw new UnsupportedOperationException( - "item alignment mismatch"); - } - } - - offset = i.place(addedTo, offset) + size; - } - } - - /** {@inheritDoc} */ - @Override - protected void writeTo0(DexFile file, AnnotatedOutput out) { - int size = items.size(); - - if (out.annotates()) { - out.annotate(0, offsetString() + " " + typeName()); - out.annotate(4, " size: " + Hex.u4(size)); - } - - out.writeInt(size); - - for (OffsettedItem i : items) { - i.writeTo(file, out); - } - } - - /** - * Get the size of the header of this list. - * - * @return >= 0; the header size - */ - private int headerSize() { - /* - * Because of how this instance was set up, this is the same - * as the alignment. - */ - return getAlignment(); - } -} diff --git a/dx/src/com/android/dx/dex/file/ValueEncoder.java b/dx/src/com/android/dx/dex/file/ValueEncoder.java deleted file mode 100644 index 02a34194f..000000000 --- a/dx/src/com/android/dx/dex/file/ValueEncoder.java +++ /dev/null @@ -1,532 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.dx.dex.file; - -import com.android.dx.rop.annotation.Annotation; -import com.android.dx.rop.annotation.NameValuePair; -import com.android.dx.rop.cst.Constant; -import com.android.dx.rop.cst.CstAnnotation; -import com.android.dx.rop.cst.CstArray; -import com.android.dx.rop.cst.CstBoolean; -import com.android.dx.rop.cst.CstByte; -import com.android.dx.rop.cst.CstChar; -import com.android.dx.rop.cst.CstDouble; -import com.android.dx.rop.cst.CstEnumRef; -import com.android.dx.rop.cst.CstFieldRef; -import com.android.dx.rop.cst.CstFloat; -import com.android.dx.rop.cst.CstInteger; -import com.android.dx.rop.cst.CstKnownNull; -import com.android.dx.rop.cst.CstLiteralBits; -import com.android.dx.rop.cst.CstLong; -import com.android.dx.rop.cst.CstMethodRef; -import com.android.dx.rop.cst.CstShort; -import com.android.dx.rop.cst.CstString; -import com.android.dx.rop.cst.CstType; -import com.android.dx.rop.cst.CstUtf8; -import com.android.dx.util.AnnotatedOutput; -import com.android.dx.util.Hex; - -import java.util.Collection; - -/** - * Handler for writing out <code>encoded_values</code> and parts - * thereof. - */ -public final class ValueEncoder { - /** annotation value type constant: <code>byte</code> */ - private static final int VALUE_BYTE = 0x00; - - /** annotation value type constant: <code>short</code> */ - private static final int VALUE_SHORT = 0x02; - - /** annotation value type constant: <code>char</code> */ - private static final int VALUE_CHAR = 0x03; - - /** annotation value type constant: <code>int</code> */ - private static final int VALUE_INT = 0x04; - - /** annotation value type constant: <code>long</code> */ - private static final int VALUE_LONG = 0x06; - - /** annotation value type constant: <code>float</code> */ - private static final int VALUE_FLOAT = 0x10; - - /** annotation value type constant: <code>double</code> */ - private static final int VALUE_DOUBLE = 0x11; - - /** annotation value type constant: <code>string</code> */ - private static final int VALUE_STRING = 0x17; - - /** annotation value type constant: <code>type</code> */ - private static final int VALUE_TYPE = 0x18; - - /** annotation value type constant: <code>field</code> */ - private static final int VALUE_FIELD = 0x19; - - /** annotation value type constant: <code>method</code> */ - private static final int VALUE_METHOD = 0x1a; - - /** annotation value type constant: <code>enum</code> */ - private static final int VALUE_ENUM = 0x1b; - - /** annotation value type constant: <code>array</code> */ - private static final int VALUE_ARRAY = 0x1c; - - /** annotation value type constant: <code>annotation</code> */ - private static final int VALUE_ANNOTATION = 0x1d; - - /** annotation value type constant: <code>null</code> */ - private static final int VALUE_NULL = 0x1e; - - /** annotation value type constant: <code>boolean</code> */ - private static final int VALUE_BOOLEAN = 0x1f; - - /** non-null; file being written */ - private final DexFile file; - - /** non-null; output stream to write to */ - private final AnnotatedOutput out; - - /** - * Construct an instance. - * - * @param file non-null; file being written - * @param out non-null; output stream to write to - */ - public ValueEncoder(DexFile file, AnnotatedOutput out) { - if (file == null) { - throw new NullPointerException("file == null"); - } - - if (out == null) { - throw new NullPointerException("out == null"); - } - - this.file = file; - this.out = out; - } - - /** - * Writes out the encoded form of the given constant. - * - * @param cst non-null; the constant to write - */ - public void writeConstant(Constant cst) { - int type = constantToValueType(cst); - int arg; - - switch (type) { - case VALUE_BYTE: - case VALUE_SHORT: - case VALUE_INT: - case VALUE_LONG: { - long value = ((CstLiteralBits) cst).getLongBits(); - writeSignedIntegralValue(type, value); - break; - } - case VALUE_CHAR: { - long value = ((CstLiteralBits) cst).getLongBits(); - writeUnsignedIntegralValue(type, value); - break; - } - case VALUE_FLOAT: { - // Shift value left 32 so that right-zero-extension works. - long value = ((CstFloat) cst).getLongBits() << 32; - writeRightZeroExtendedValue(type, value); - break; - } - case VALUE_DOUBLE: { - long value = ((CstDouble) cst).getLongBits(); - writeRightZeroExtendedValue(type, value); - break; - } - case VALUE_STRING: { - int index = file.getStringIds().indexOf((CstString) cst); - writeUnsignedIntegralValue(type, (long) index); - break; - } - case VALUE_TYPE: { - int index = file.getTypeIds().indexOf((CstType) cst); - writeUnsignedIntegralValue(type, (long) index); - break; - } - case VALUE_FIELD: { - int index = file.getFieldIds().indexOf((CstFieldRef) cst); - writeUnsignedIntegralValue(type, (long) index); - break; - } - case VALUE_METHOD: { - int index = file.getMethodIds().indexOf((CstMethodRef) cst); - writeUnsignedIntegralValue(type, (long) index); - break; - } - case VALUE_ENUM: { - CstFieldRef fieldRef = ((CstEnumRef) cst).getFieldRef(); - int index = file.getFieldIds().indexOf(fieldRef); - writeUnsignedIntegralValue(type, (long) index); - break; - } - case VALUE_ARRAY: { - out.writeByte(type); - writeArray((CstArray) cst, false); - break; - } - case VALUE_ANNOTATION: { - out.writeByte(type); - writeAnnotation(((CstAnnotation) cst).getAnnotation(), - false); - break; - } - case VALUE_NULL: { - out.writeByte(type); - break; - } - case VALUE_BOOLEAN: { - int value = ((CstBoolean) cst).getIntBits(); - out.writeByte(type | (value << 5)); - break; - } - default: { - throw new RuntimeException("Shouldn't happen"); - } - } - } - - /** - * Gets the value type for the given constant. - * - * @param cst non-null; the constant - * @return the value type; one of the <code>VALUE_*</code> constants - * defined by this class - */ - private static int constantToValueType(Constant cst) { - /* - * TODO: Constant should probable have an associated enum, so this - * can be a switch(). - */ - if (cst instanceof CstByte) { - return VALUE_BYTE; - } else if (cst instanceof CstShort) { - return VALUE_SHORT; - } else if (cst instanceof CstChar) { - return VALUE_CHAR; - } else if (cst instanceof CstInteger) { - return VALUE_INT; - } else if (cst instanceof CstLong) { - return VALUE_LONG; - } else if (cst instanceof CstFloat) { - return VALUE_FLOAT; - } else if (cst instanceof CstDouble) { - return VALUE_DOUBLE; - } else if (cst instanceof CstString) { - return VALUE_STRING; - } else if (cst instanceof CstType) { - return VALUE_TYPE; - } else if (cst instanceof CstFieldRef) { - return VALUE_FIELD; - } else if (cst instanceof CstMethodRef) { - return VALUE_METHOD; - } else if (cst instanceof CstEnumRef) { - return VALUE_ENUM; - } else if (cst instanceof CstArray) { - return VALUE_ARRAY; - } else if (cst instanceof CstAnnotation) { - return VALUE_ANNOTATION; - } else if (cst instanceof CstKnownNull) { - return VALUE_NULL; - } else if (cst instanceof CstBoolean) { - return VALUE_BOOLEAN; - } else { - throw new RuntimeException("Shouldn't happen"); - } - } - - /** - * Writes out the encoded form of the given array, that is, as - * an <code>encoded_array</code> and not including a - * <code>value_type</code> prefix. If the output stream keeps - * (debugging) annotations and <code>topLevel</code> is - * <code>true</code>, then this method will write (debugging) - * annotations. - * - * @param array non-null; array instance to write - * @param topLevel <code>true</code> iff the given annotation is the - * top-level annotation or <code>false</code> if it is a sub-annotation - * of some other annotation - */ - public void writeArray(CstArray array, boolean topLevel) { - boolean annotates = topLevel && out.annotates(); - CstArray.List list = ((CstArray) array).getList(); - int size = list.size(); - - if (annotates) { - out.annotate(" size: " + Hex.u4(size)); - } - - out.writeUnsignedLeb128(size); - - for (int i = 0; i < size; i++) { - Constant cst = list.get(i); - if (annotates) { - out.annotate(" [" + Integer.toHexString(i) + "] " + - constantToHuman(cst)); - } - writeConstant(cst); - } - - if (annotates) { - out.endAnnotation(); - } - } - - /** - * Writes out the encoded form of the given annotation, that is, - * as an <code>encoded_annotation</code> and not including a - * <code>value_type</code> prefix. If the output stream keeps - * (debugging) annotations and <code>topLevel</code> is - * <code>true</code>, then this method will write (debugging) - * annotations. - * - * @param annotation non-null; annotation instance to write - * @param topLevel <code>true</code> iff the given annotation is the - * top-level annotation or <code>false</code> if it is a sub-annotation - * of some other annotation - */ - public void writeAnnotation(Annotation annotation, boolean topLevel) { - boolean annotates = topLevel && out.annotates(); - StringIdsSection stringIds = file.getStringIds(); - TypeIdsSection typeIds = file.getTypeIds(); - - CstType type = annotation.getType(); - int typeIdx = typeIds.indexOf(type); - - if (annotates) { - out.annotate(" type_idx: " + Hex.u4(typeIdx) + " // " + - type.toHuman()); - } - - out.writeUnsignedLeb128(typeIds.indexOf(annotation.getType())); - - Collection<NameValuePair> pairs = annotation.getNameValuePairs(); - int size = pairs.size(); - - if (annotates) { - out.annotate(" size: " + Hex.u4(size)); - } - - out.writeUnsignedLeb128(size); - - int at = 0; - for (NameValuePair pair : pairs) { - CstUtf8 name = pair.getName(); - int nameIdx = stringIds.indexOf(name); - Constant value = pair.getValue(); - - if (annotates) { - out.annotate(0, " elements[" + at + "]:"); - at++; - out.annotate(" name_idx: " + Hex.u4(nameIdx) + " // " + - name.toHuman()); - } - - out.writeUnsignedLeb128(nameIdx); - - if (annotates) { - out.annotate(" value: " + constantToHuman(value)); - } - - writeConstant(value); - } - - if (annotates) { - out.endAnnotation(); - } - } - - /** - * Gets the colloquial type name and human form of the type of the - * given constant, when used as an encoded value. - * - * @param cst non-null; the constant - * @return non-null; its type name and human form - */ - public static String constantToHuman(Constant cst) { - int type = constantToValueType(cst); - - if (type == VALUE_NULL) { - return "null"; - } - - StringBuilder sb = new StringBuilder(); - - sb.append(cst.typeName()); - sb.append(' '); - sb.append(cst.toHuman()); - - return sb.toString(); - } - - /** - * Helper for {@link #writeConstant}, which writes out the value - * for any signed integral type. - * - * @param type the type constant - * @param value <code>long</code> bits of the value - */ - private void writeSignedIntegralValue(int type, long value) { - /* - * Figure out how many bits are needed to represent the value, - * including a sign bit: The bit count is subtracted from 65 - * and not 64 to account for the sign bit. The xor operation - * has the effect of leaving non-negative values alone and - * unary complementing negative values (so that a leading zero - * count always returns a useful number for our present - * purpose). - */ - int requiredBits = - 65 - Long.numberOfLeadingZeros(value ^ (value >> 63)); - - // Round up the requiredBits to a number of bytes. - int requiredBytes = (requiredBits + 0x07) >> 3; - - /* - * Write the header byte, which includes the type and - * requiredBytes - 1. - */ - out.writeByte(type | ((requiredBytes - 1) << 5)); - - // Write the value, per se. - while (requiredBytes > 0) { - out.writeByte((byte) value); - value >>= 8; - requiredBytes--; - } - } - - /** - * Helper for {@link #writeConstant}, which writes out the value - * for any unsigned integral type. - * - * @param type the type constant - * @param value <code>long</code> bits of the value - */ - private void writeUnsignedIntegralValue(int type, long value) { - // Figure out how many bits are needed to represent the value. - int requiredBits = 64 - Long.numberOfLeadingZeros(value); - if (requiredBits == 0) { - requiredBits = 1; - } - - // Round up the requiredBits to a number of bytes. - int requiredBytes = (requiredBits + 0x07) >> 3; - - /* - * Write the header byte, which includes the type and - * requiredBytes - 1. - */ - out.writeByte(type | ((requiredBytes - 1) << 5)); - - // Write the value, per se. - while (requiredBytes > 0) { - out.writeByte((byte) value); - value >>= 8; - requiredBytes--; - } - } - - /** - * Helper for {@link #writeConstant}, which writes out a - * right-zero-extended value. - * - * @param type the type constant - * @param value <code>long</code> bits of the value - */ - private void writeRightZeroExtendedValue(int type, long value) { - // Figure out how many bits are needed to represent the value. - int requiredBits = 64 - Long.numberOfTrailingZeros(value); - if (requiredBits == 0) { - requiredBits = 1; - } - - // Round up the requiredBits to a number of bytes. - int requiredBytes = (requiredBits + 0x07) >> 3; - - // Scootch the first bits to be written down to the low-order bits. - value >>= 64 - (requiredBytes * 8); - - /* - * Write the header byte, which includes the type and - * requiredBytes - 1. - */ - out.writeByte(type | ((requiredBytes - 1) << 5)); - - // Write the value, per se. - while (requiredBytes > 0) { - out.writeByte((byte) value); - value >>= 8; - requiredBytes--; - } - } - - - /** - * Helper for <code>addContents()</code> methods, which adds - * contents for a particular {@link Annotation}, calling itself - * recursively should it encounter a nested annotation. - * - * @param file non-null; the file to add to - * @param annotation non-null; the annotation to add contents for - */ - public static void addContents(DexFile file, Annotation annotation) { - TypeIdsSection typeIds = file.getTypeIds(); - StringIdsSection stringIds = file.getStringIds(); - - typeIds.intern(annotation.getType()); - - for (NameValuePair pair : annotation.getNameValuePairs()) { - stringIds.intern(pair.getName()); - addContents(file, pair.getValue()); - } - } - - /** - * Helper for <code>addContents()</code> methods, which adds - * contents for a particular constant, calling itself recursively - * should it encounter a {@link CstArray} and calling {@link - * #addContents(DexFile,Annotation)} recursively should it - * encounter a {@link CstAnnotation}. - * - * @param file non-null; the file to add to - * @param cst non-null; the constant to add contents for - */ - public static void addContents(DexFile file, Constant cst) { - TypeIdsSection typeIds = file.getTypeIds(); - StringIdsSection stringIds = file.getStringIds(); - - if (cst instanceof CstAnnotation) { - addContents(file, ((CstAnnotation) cst).getAnnotation()); - } else if (cst instanceof CstArray) { - CstArray.List list = ((CstArray) cst).getList(); - int size = list.size(); - for (int i = 0; i < size; i++) { - addContents(file, list.get(i)); - } - } else { - file.internIfAppropriate(cst); - } - } -} |