diff --git a/dexlib2/src/main/java/org/jf/dexlib2/writer/ClassSection.java b/dexlib2/src/main/java/org/jf/dexlib2/writer/ClassSection.java index d28dd444..b272bd60 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/writer/ClassSection.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/writer/ClassSection.java @@ -45,7 +45,7 @@ import java.util.List; import java.util.Map; public interface ClassSection extends IndexSection { + FieldKey, MethodKey, AnnotationSetKey, EncodedArrayKey> extends IndexSection { @Nonnull Collection getSortedClasses(); @Nullable Map.Entry getClassEntryByType(@Nullable TypeKey key); @@ -55,7 +55,7 @@ public interface ClassSection getStaticInitializers(@Nonnull ClassKey key); + @Nullable EncodedArrayKey getStaticInitializers(@Nonnull ClassKey key); @Nonnull Collection getSortedStaticFields(@Nonnull ClassKey key); @Nonnull Collection getSortedInstanceFields(@Nonnull ClassKey key); @@ -81,9 +81,6 @@ public interface ClassSection, @@ -96,11 +96,12 @@ public abstract class DexWriter< FieldSectionType extends FieldSection, MethodSectionType extends MethodSection, ClassSectionType extends ClassSection, + AnnotationSetKey, EncodedArrayKey>, TypeListSectionType extends TypeListSection, AnnotationSectionType extends AnnotationSection, - AnnotationSetSectionType extends AnnotationSetSection> { + AnnotationSetSectionType extends AnnotationSetSection, + EncodedArraySectionType extends EncodedArraySection> { public static final int NO_INDEX = -1; public static final int NO_OFFSET = 0; @@ -125,7 +126,6 @@ public abstract class DexWriter< protected int codeSectionOffset = NO_OFFSET; protected int mapSectionOffset = NO_OFFSET; - protected int numEncodedArrayItems = 0; protected int numAnnotationSetRefItems = 0; protected int numAnnotationDirectoryItems = 0; protected int numDebugInfoItems = 0; @@ -138,10 +138,11 @@ public abstract class DexWriter< public final FieldSectionType fieldSection; public final MethodSectionType methodSection; public final ClassSectionType classSection; - + public final TypeListSectionType typeListSection; public final AnnotationSectionType annotationSection; public final AnnotationSetSectionType annotationSetSection; + public final EncodedArraySectionType encodedArraySection; protected DexWriter(Opcodes opcodes) { this.opcodes = opcodes; @@ -156,6 +157,7 @@ public abstract class DexWriter< this.typeListSection = sectionProvider.getTypeListSection(); this.annotationSection = sectionProvider.getAnnotationSection(); this.annotationSetSection = sectionProvider.getAnnotationSetSection(); + this.encodedArraySection = sectionProvider.getEncodedArraySection(); } @Nonnull protected abstract SectionProvider getSectionProvider(); @@ -266,6 +268,7 @@ public abstract class DexWriter< writeAnnotationSetRefs(offsetWriter); writeAnnotationDirectories(offsetWriter); writeDebugAndCodeItems(offsetWriter, tempFactory.makeDeferredOutputStream()); + writeEncodedArrays(offsetWriter); writeClasses(indexWriter, offsetWriter); writeMapItem(offsetWriter); writeHeader(headerWriter, dataSectionOffset, offsetWriter.getPosition()); @@ -480,10 +483,15 @@ public abstract class DexWriter< if (classHasData) { indexWriter.writeInt(offsetWriter.getPosition()); } else { - indexWriter.writeInt(0); + indexWriter.writeInt(NO_OFFSET); } - indexWriter.writeInt(classSection.getEncodedArrayOffset(key)); + EncodedArrayKey staticInitializers = classSection.getStaticInitializers(key); + if (staticInitializers != null) { + indexWriter.writeInt(encodedArraySection.getItemOffset(staticInitializers)); + } else { + indexWriter.writeInt(NO_OFFSET); + } // now write the class_data_item if (classHasData) { @@ -541,55 +549,16 @@ public abstract class DexWriter< } } - private static class EncodedArrayKey { - @Nonnull Collection elements; - - public EncodedArrayKey() { - } - - @Override public int hashCode() { - return CollectionUtils.listHashCode(elements); - } - - @Override public boolean equals(Object o) { - if (o instanceof EncodedArrayKey) { - EncodedArrayKey other = (EncodedArrayKey)o; - if (elements.size() != other.elements.size()) { - return false; - } - return Iterables.elementsEqual(elements, other.elements); - } - return false; - } - } - private void writeEncodedArrays(@Nonnull DexDataWriter writer) throws IOException { InternalEncodedValueWriter encodedValueWriter = new InternalEncodedValueWriter(writer); encodedArraySectionOffset = writer.getPosition(); - HashMap, Integer> internedItems = Maps.newHashMap(); - EncodedArrayKey key = new EncodedArrayKey(); - - for (ClassKey classKey: classSection.getSortedClasses()) { - Collection elements = classSection.getStaticInitializers(classKey); - if (elements != null && elements.size() > 0) { - key.elements = elements; - Integer prev = internedItems.get(key); - if (prev != null) { - classSection.setEncodedArrayOffset(classKey, prev); - } else { - int offset = writer.getPosition(); - internedItems.put(key, offset); - classSection.setEncodedArrayOffset(classKey, offset); - key = new EncodedArrayKey(); - - numEncodedArrayItems++; - - writer.writeUleb128(elements.size()); - for (EncodedValue value: elements) { - writeEncodedValue(encodedValueWriter, value); - } - } + for (Map.Entry entry: encodedArraySection.getItems()) { + entry.setValue(writer.getPosition()); + List encodedArray = encodedArraySection.getEncodedValueList(entry.getKey()); + writer.writeUleb128(encodedArray.size()); + for (EncodedValue value: encodedArray) { + writeEncodedValue(encodedValueWriter, value); } } } @@ -975,7 +944,7 @@ public abstract class DexWriter< InstructionWriter instructionWriter = InstructionWriter.makeInstructionWriter(opcodes, writer, stringSection, typeSection, fieldSection, - methodSection, protoSection); + methodSection, protoSection, callSiteSection); writer.writeInt(codeUnitCount); int codeOffset = 0; @@ -1196,10 +1165,16 @@ public abstract class DexWriter< if (methodSection.getItems().size() > 0) { numItems++; } + if (callSiteSection.getItems().size() > 0) { + numItems++; + } + if (methodHandleSection.getItems().size() > 0) { + numItems++; + } if (typeListSection.getItems().size() > 0) { numItems++; } - if (numEncodedArrayItems > 0) { + if (encodedArraySection.getItems().size() > 0) { numItems++; } if (annotationSection.getItems().size() > 0) { @@ -1247,14 +1222,19 @@ public abstract class DexWriter< writeMapItem(writer, ItemType.FIELD_ID_ITEM, fieldSection.getItems().size(), fieldSectionOffset); writeMapItem(writer, ItemType.METHOD_ID_ITEM, methodSection.getItems().size(), methodSectionOffset); writeMapItem(writer, ItemType.CLASS_DEF_ITEM, classSection.getItems().size(), classIndexSectionOffset); + writeMapItem(writer, ItemType.CALL_SITE_ID_ITEM, callSiteSection.getItems().size(), callSiteSectionOffset); + writeMapItem(writer, ItemType.METHOD_HANDLE_ITEM, methodHandleSection.getItems().size(), + methodHandleSectionOffset); // data section writeMapItem(writer, ItemType.STRING_DATA_ITEM, stringSection.getItems().size(), stringDataSectionOffset); writeMapItem(writer, ItemType.TYPE_LIST, typeListSection.getItems().size(), typeListSectionOffset); - writeMapItem(writer, ItemType.ENCODED_ARRAY_ITEM, numEncodedArrayItems, encodedArraySectionOffset); + writeMapItem(writer, ItemType.ENCODED_ARRAY_ITEM, encodedArraySection.getItems().size(), + encodedArraySectionOffset); writeMapItem(writer, ItemType.ANNOTATION_ITEM, annotationSection.getItems().size(), annotationSectionOffset); writeMapItem(writer, ItemType.ANNOTATION_SET_ITEM, - annotationSetSection.getItems().size() + (shouldCreateEmptyAnnotationSet() ? 1 : 0), annotationSetSectionOffset); + annotationSetSection.getItems().size() + (shouldCreateEmptyAnnotationSet() ? 1 : 0), + annotationSetSectionOffset); writeMapItem(writer, ItemType.ANNOTATION_SET_REF_LIST, numAnnotationSetRefItems, annotationSetRefSectionOffset); writeMapItem(writer, ItemType.ANNOTATION_DIRECTORY_ITEM, numAnnotationDirectoryItems, annotationDirectorySectionOffset); @@ -1334,5 +1314,6 @@ public abstract class DexWriter< @Nonnull public abstract TypeListSectionType getTypeListSection(); @Nonnull public abstract AnnotationSectionType getAnnotationSection(); @Nonnull public abstract AnnotationSetSectionType getAnnotationSetSection(); + @Nonnull public abstract EncodedArraySectionType getEncodedArraySection(); } } diff --git a/dexlib2/src/main/java/org/jf/dexlib2/writer/EncodedArraySection.java b/dexlib2/src/main/java/org/jf/dexlib2/writer/EncodedArraySection.java new file mode 100644 index 00000000..49a5d159 --- /dev/null +++ b/dexlib2/src/main/java/org/jf/dexlib2/writer/EncodedArraySection.java @@ -0,0 +1,38 @@ +/* + * Copyright 2018, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.jf.dexlib2.writer; + +import java.util.List; + +public interface EncodedArraySection extends OffsetSection { + List getEncodedValueList(EncodedArrayKey encodedArrayKey); +} diff --git a/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/BuilderClassDef.java b/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/BuilderClassDef.java index 9938a6e0..1d852818 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/BuilderClassDef.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/BuilderClassDef.java @@ -35,9 +35,9 @@ import com.google.common.base.Functions; import com.google.common.collect.*; import org.jf.dexlib2.base.reference.BaseTypeReference; import org.jf.dexlib2.iface.ClassDef; -import org.jf.dexlib2.util.FieldUtil; import org.jf.dexlib2.util.MethodUtil; import org.jf.dexlib2.writer.DexWriter; +import org.jf.dexlib2.writer.builder.BuilderEncodedValues.BuilderArrayEncodedValue; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -54,9 +54,9 @@ public class BuilderClassDef extends BaseTypeReference implements ClassDef { @Nonnull final SortedSet instanceFields; @Nonnull final SortedSet directMethods; @Nonnull final SortedSet virtualMethods; + @Nullable final BuilderArrayEncodedValue staticInitializers; int classDefIndex = DexWriter.NO_INDEX; - int encodedArrayOffset = DexWriter.NO_OFFSET; int annotationDirectoryOffset = DexWriter.NO_OFFSET; BuilderClassDef(@Nonnull BuilderTypeReference type, @@ -65,14 +65,19 @@ public class BuilderClassDef extends BaseTypeReference implements ClassDef { @Nonnull BuilderTypeList interfaces, @Nullable BuilderStringReference sourceFile, @Nonnull BuilderAnnotationSet annotations, - @Nullable Iterable fields, - @Nullable Iterable methods) { - if (fields == null) { - fields = ImmutableList.of(); - } + @Nullable SortedSet staticFields, + @Nullable SortedSet instanceFields, + @Nullable Iterable methods, + @Nullable BuilderArrayEncodedValue staticInitializers) { if (methods == null) { methods = ImmutableList.of(); } + if (staticFields == null) { + staticFields = ImmutableSortedSet.of(); + } + if (instanceFields == null) { + instanceFields = ImmutableSortedSet.of(); + } this.type = type; this.accessFlags = accessFlags; @@ -80,10 +85,11 @@ public class BuilderClassDef extends BaseTypeReference implements ClassDef { this.interfaces = interfaces; this.sourceFile = sourceFile; this.annotations = annotations; - this.staticFields = ImmutableSortedSet.copyOf(Iterables.filter(fields, FieldUtil.FIELD_IS_STATIC)); - this.instanceFields = ImmutableSortedSet.copyOf(Iterables.filter(fields, FieldUtil.FIELD_IS_INSTANCE)); + this.staticFields = staticFields; + this.instanceFields = instanceFields; this.directMethods = ImmutableSortedSet.copyOf(Iterables.filter(methods, MethodUtil.METHOD_IS_DIRECT)); this.virtualMethods = ImmutableSortedSet.copyOf(Iterables.filter(methods, MethodUtil.METHOD_IS_VIRTUAL)); + this.staticInitializers = staticInitializers; } @Nonnull @Override public String getType() { return type.getType(); } diff --git a/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/BuilderClassPool.java b/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/BuilderClassPool.java index 4f67a873..319a2451 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/BuilderClassPool.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/BuilderClassPool.java @@ -48,21 +48,24 @@ import org.jf.dexlib2.iface.value.EncodedValue; import org.jf.dexlib2.util.EncodedValueUtils; import org.jf.dexlib2.writer.ClassSection; import org.jf.dexlib2.writer.DebugWriter; +import org.jf.dexlib2.writer.builder.BuilderEncodedValues.BuilderArrayEncodedValue; import org.jf.dexlib2.writer.builder.BuilderEncodedValues.BuilderEncodedValue; import org.jf.util.AbstractForwardSequentialList; -import org.jf.util.CollectionUtils; import org.jf.util.ExceptionWithContext; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.io.IOException; -import java.util.*; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.Map; import java.util.Map.Entry; import java.util.concurrent.ConcurrentMap; public class BuilderClassPool extends BaseBuilderPool implements ClassSection { + BuilderArrayEncodedValue> { @Nonnull private final ConcurrentMap internedItems = Maps.newConcurrentMap(); @@ -153,24 +156,8 @@ public class BuilderClassPool extends BaseBuilderPool implements ClassSection getStaticInitializers(@Nonnull BuilderClassDef classDef) { - final SortedSet sortedStaticFields = classDef.getStaticFields(); - - final int lastIndex = CollectionUtils.lastIndexOf(sortedStaticFields, HAS_INITIALIZER); - if (lastIndex > -1) { - return new AbstractCollection() { - @Nonnull @Override public Iterator iterator() { - return FluentIterable.from(sortedStaticFields) - .limit(lastIndex+1) - .transform(GET_INITIAL_VALUE).iterator(); - } - - @Override public int size() { - return lastIndex+1; - } - }; - } - return null; + public BuilderArrayEncodedValue getStaticInitializers(@Nonnull BuilderClassDef classDef) { + return classDef.staticInitializers; } @Nonnull @Override @@ -325,14 +312,6 @@ public class BuilderClassPool extends BaseBuilderPool implements ClassSection { + @Nonnull private final ConcurrentMap internedItems = + Maps.newConcurrentMap(); + + public BuilderEncodedArrayPool(@Nonnull DexBuilder dexBuilder) { + super(dexBuilder); + } + + @Nonnull public BuilderArrayEncodedValue internArrayEncodedValue(@Nonnull ArrayEncodedValue arrayEncodedValue) { + BuilderArrayEncodedValue builderArrayEncodedValue = internedItems.get(arrayEncodedValue); + if (builderArrayEncodedValue != null) { + return builderArrayEncodedValue; + } + + builderArrayEncodedValue = (BuilderArrayEncodedValue)dexBuilder.internEncodedValue(arrayEncodedValue); + BuilderArrayEncodedValue previous = internedItems.putIfAbsent( + builderArrayEncodedValue, builderArrayEncodedValue); + return previous == null ? builderArrayEncodedValue : previous; + } + + @Override + public int getItemOffset(@Nonnull BuilderArrayEncodedValue builderArrayEncodedValue) { + return builderArrayEncodedValue.offset; + } + + @Nonnull + @Override + public Collection> getItems() { + return new BuilderMapEntryCollection(internedItems.values()) { + @Override + protected int getValue(@Nonnull BuilderArrayEncodedValue builderArrayEncodedValue) { + return builderArrayEncodedValue.offset; + } + + @Override + protected int setValue(@Nonnull BuilderArrayEncodedValue key, int value) { + int prev = key.offset; + key.offset = value; + return prev; + } + }; + } + + @Override + public List getEncodedValueList(BuilderArrayEncodedValue builderArrayEncodedValue) { + return builderArrayEncodedValue.elements; + } +} diff --git a/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/BuilderEncodedValues.java b/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/BuilderEncodedValues.java index 0f047124..1cee858b 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/BuilderEncodedValues.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/BuilderEncodedValues.java @@ -34,6 +34,7 @@ package org.jf.dexlib2.writer.builder; import org.jf.dexlib2.base.value.*; import org.jf.dexlib2.iface.value.EncodedValue; import org.jf.dexlib2.immutable.value.*; +import org.jf.dexlib2.writer.DexWriter; import org.jf.util.ExceptionWithContext; import javax.annotation.Nonnull; @@ -66,6 +67,7 @@ public abstract class BuilderEncodedValues { public static class BuilderArrayEncodedValue extends BaseArrayEncodedValue implements BuilderEncodedValue { @Nonnull final List elements; + int offset = DexWriter.NO_OFFSET; BuilderArrayEncodedValue(@Nonnull List elements) { this.elements = elements; diff --git a/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/DexBuilder.java b/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/DexBuilder.java index 25938fe0..ec25be1f 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/DexBuilder.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/writer/builder/DexBuilder.java @@ -32,10 +32,7 @@ package org.jf.dexlib2.writer.builder; import com.google.common.base.Function; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Iterators; -import com.google.common.collect.Sets; +import com.google.common.collect.*; import org.jf.dexlib2.Opcodes; import org.jf.dexlib2.ValueType; import org.jf.dexlib2.iface.Annotation; @@ -44,8 +41,10 @@ import org.jf.dexlib2.iface.MethodImplementation; import org.jf.dexlib2.iface.MethodParameter; import org.jf.dexlib2.iface.reference.*; import org.jf.dexlib2.iface.value.*; +import org.jf.dexlib2.util.FieldUtil; import org.jf.dexlib2.writer.DexWriter; import org.jf.dexlib2.writer.builder.BuilderEncodedValues.*; +import org.jf.dexlib2.writer.util.StaticInitializerUtil; import org.jf.util.ExceptionWithContext; import javax.annotation.Nonnull; @@ -58,9 +57,9 @@ import java.util.Set; public class DexBuilder extends DexWriter { + BuilderArrayEncodedValue, BuilderEncodedValue, BuilderAnnotationElement, BuilderStringPool, BuilderTypePool, + BuilderProtoPool, BuilderFieldPool, BuilderMethodPool, BuilderClassPool, BuilderTypeListPool, + BuilderAnnotationPool, BuilderAnnotationSetPool, BuilderEncodedArrayPool> { public DexBuilder(@Nonnull Opcodes opcodes) { super(opcodes); @@ -122,14 +121,28 @@ public class DexBuilder extends DexWriter staticFields = null; + ImmutableSortedSet instanceFields = null; + BuilderArrayEncodedValue internedStaticInitializers = null; + if (fields != null) { + staticFields = ImmutableSortedSet.copyOf(Iterables.filter(fields, FieldUtil.FIELD_IS_STATIC)); + instanceFields = ImmutableSortedSet.copyOf(Iterables.filter(fields, FieldUtil.FIELD_IS_INSTANCE)); + ArrayEncodedValue staticInitializers = StaticInitializerUtil.getStaticInitializers(staticFields); + if (staticInitializers != null) { + internedStaticInitializers = encodedArraySection.internArrayEncodedValue(staticInitializers); + } + } + return classSection.internClass(new BuilderClassDef(typeSection.internType(type), accessFlags, typeSection.internNullableType(superclass), typeListSection.internTypeList(interfaces), stringSection.internNullableString(sourceFile), annotationSetSection.internAnnotationSet(annotations), - fields, - methods)); + staticFields, + instanceFields, + methods, + internedStaticInitializers)); } @Nonnull public BuilderStringReference internStringReference(@Nonnull String string) { @@ -287,7 +300,7 @@ public class DexBuilder extends DexWriter implements ClassSection>, PoolClassDef, Field, PoolMethod, - Set, EncodedValue> { + Set, ArrayEncodedValue> { public ClassPool(@Nonnull DexPool dexPool) { super(dexPool); @@ -94,6 +96,11 @@ public class ClassPool extends BasePool implements ClassSe } dexPool.annotationSetSection.intern(field.getAnnotations()); + + ArrayEncodedValue staticInitializers = getStaticInitializers(poolClassDef); + if (staticInitializers != null) { + dexPool.encodedArraySection.intern(staticInitializers); + } } HashSet methods = new HashSet(); @@ -240,44 +247,9 @@ public class ClassPool extends BasePool implements ClassSe return classDef.getSourceFile(); } - private static final Predicate HAS_INITIALIZER = new Predicate() { - @Override - public boolean apply(Field input) { - EncodedValue encodedValue = input.getInitialValue(); - return encodedValue != null && !EncodedValueUtils.isDefaultValue(encodedValue); - } - }; - - private static final Function GET_INITIAL_VALUE = new Function() { - @Override - public EncodedValue apply(Field input) { - EncodedValue initialValue = input.getInitialValue(); - if (initialValue == null) { - return ImmutableEncodedValueFactory.defaultValueForType(input.getType()); - } - return initialValue; - } - }; - - @Nullable @Override public Collection getStaticInitializers( + @Nullable @Override public ArrayEncodedValue getStaticInitializers( @Nonnull PoolClassDef classDef) { - final SortedSet sortedStaticFields = classDef.getStaticFields(); - - final int lastIndex = CollectionUtils.lastIndexOf(sortedStaticFields, HAS_INITIALIZER); - if (lastIndex > -1) { - return new AbstractCollection() { - @Nonnull @Override public Iterator iterator() { - return FluentIterable.from(sortedStaticFields) - .limit(lastIndex+1) - .transform(GET_INITIAL_VALUE).iterator(); - } - - @Override public int size() { - return lastIndex+1; - } - }; - } - return null; + return StaticInitializerUtil.getStaticInitializers(classDef.getStaticFields()); } @Nonnull @Override public Collection getSortedStaticFields(@Nonnull PoolClassDef classDef) { @@ -421,14 +393,6 @@ public class ClassPool extends BasePool implements ClassSe return new MutableMethodImplementation(poolMethod.getImplementation()); } - @Override public void setEncodedArrayOffset(@Nonnull PoolClassDef classDef, int offset) { - classDef.encodedArrayOffset = offset; - } - - @Override public int getEncodedArrayOffset(@Nonnull PoolClassDef classDef) { - return classDef.encodedArrayOffset; - } - @Override public void setAnnotationDirectoryOffset(@Nonnull PoolClassDef classDef, int offset) { classDef.annotationDirectoryOffset = offset; } diff --git a/dexlib2/src/main/java/org/jf/dexlib2/writer/pool/DexPool.java b/dexlib2/src/main/java/org/jf/dexlib2/writer/pool/DexPool.java index 6d662ec3..93561412 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/writer/pool/DexPool.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/writer/pool/DexPool.java @@ -54,8 +54,8 @@ public class DexPool extends DexWriter, TypeListPool.Key>, Field, PoolMethod, - EncodedValue, AnnotationElement, StringPool, TypePool, ProtoPool, FieldPool, MethodPool, ClassPool, - TypeListPool, AnnotationPool, AnnotationSetPool> { + ArrayEncodedValue, EncodedValue, AnnotationElement, StringPool, TypePool, ProtoPool, FieldPool, MethodPool, + ClassPool, TypeListPool, AnnotationPool, AnnotationSetPool, EncodedArrayPool> { private final Markable[] sections = new Markable[] { stringSection, typeSection, protoSection, fieldSection, methodSection, classSection, typeListSection, @@ -244,5 +244,9 @@ public class DexPool extends DexWriter + implements EncodedArraySection { + + public EncodedArrayPool(@Nonnull DexPool dexPool) { + super(dexPool); + } + + public void intern(@Nonnull ArrayEncodedValue arrayEncodedValue) { + Integer prev = internedItems.put(arrayEncodedValue, 0); + if (prev == null) { + for (EncodedValue value: arrayEncodedValue.getValue()) { + dexPool.internEncodedValue(value); + } + } + } + + @Override + public List getEncodedValueList(ArrayEncodedValue arrayEncodedValue) { + return arrayEncodedValue.getValue(); + } +} diff --git a/dexlib2/src/main/java/org/jf/dexlib2/writer/pool/PoolClassDef.java b/dexlib2/src/main/java/org/jf/dexlib2/writer/pool/PoolClassDef.java index 00958fb8..02f22102 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/writer/pool/PoolClassDef.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/writer/pool/PoolClassDef.java @@ -50,7 +50,6 @@ class PoolClassDef extends BaseTypeReference implements ClassDef { @Nonnull final ImmutableSortedSet virtualMethods; int classDefIndex = DexPool.NO_INDEX; - int encodedArrayOffset = DexPool.NO_OFFSET; int annotationDirectoryOffset = DexPool.NO_OFFSET; PoolClassDef(@Nonnull ClassDef classDef) { diff --git a/dexlib2/src/main/java/org/jf/dexlib2/writer/util/StaticInitializerUtil.java b/dexlib2/src/main/java/org/jf/dexlib2/writer/util/StaticInitializerUtil.java new file mode 100644 index 00000000..e292264f --- /dev/null +++ b/dexlib2/src/main/java/org/jf/dexlib2/writer/util/StaticInitializerUtil.java @@ -0,0 +1,98 @@ +/* + * Copyright 2018, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.jf.dexlib2.writer.util; + +import com.google.common.base.Function; +import com.google.common.base.Predicate; +import com.google.common.collect.FluentIterable; +import org.jf.dexlib2.base.value.BaseArrayEncodedValue; +import org.jf.dexlib2.iface.Field; +import org.jf.dexlib2.iface.value.ArrayEncodedValue; +import org.jf.dexlib2.iface.value.EncodedValue; +import org.jf.dexlib2.immutable.value.ImmutableEncodedValueFactory; +import org.jf.dexlib2.util.EncodedValueUtils; +import org.jf.util.AbstractForwardSequentialList; +import org.jf.util.CollectionUtils; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.Iterator; +import java.util.List; +import java.util.SortedSet; + +public class StaticInitializerUtil { + + @Nullable public static ArrayEncodedValue getStaticInitializers( + @Nonnull SortedSet sortedStaticFields) { + final int lastIndex = CollectionUtils.lastIndexOf(sortedStaticFields, HAS_INITIALIZER); + if (lastIndex > -1) { + return new BaseArrayEncodedValue() { + @Nonnull + @Override + public List getValue() { + return new AbstractForwardSequentialList() { + @Nonnull @Override public Iterator iterator() { + return FluentIterable.from(sortedStaticFields) + .limit(lastIndex+1) + .transform(GET_INITIAL_VALUE).iterator(); + } + + @Override public int size() { + return lastIndex+1; + } + }; + } + }; + } + return null; + } + + private static final Predicate HAS_INITIALIZER = new Predicate() { + @Override + public boolean apply(Field input) { + EncodedValue encodedValue = input.getInitialValue(); + return encodedValue != null && !EncodedValueUtils.isDefaultValue(encodedValue); + } + }; + + private static final Function GET_INITIAL_VALUE = new Function() { + @Override + public EncodedValue apply(Field input) { + EncodedValue initialValue = input.getInitialValue(); + if (initialValue == null) { + return ImmutableEncodedValueFactory.defaultValueForType(input.getType()); + } + return initialValue; + } + }; + +} diff --git a/smali/src/test/java/org/jf/smali/ImplicitReferenceTest.java b/smali/src/test/java/org/jf/smali/ImplicitReferenceTest.java index 83046536..becb01cd 100644 --- a/smali/src/test/java/org/jf/smali/ImplicitReferenceTest.java +++ b/smali/src/test/java/org/jf/smali/ImplicitReferenceTest.java @@ -29,7 +29,9 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package org.jf.smali;import com.google.common.collect.Lists; +package org.jf.smali; + +import com.google.common.collect.Lists; import com.google.common.collect.Maps; import junit.framework.Assert; import org.antlr.runtime.RecognitionException; @@ -47,7 +49,6 @@ import org.jf.dexlib2.iface.reference.MethodReference; import org.jf.dexlib2.iface.value.FieldEncodedValue; import org.jf.dexlib2.iface.value.MethodEncodedValue; import org.jf.dexlib2.iface.value.TypeEncodedValue; -import org.jf.smali.SmaliTestUtils; import org.junit.Test; import java.io.IOException;