Create separate section for encoded arrays

This commit is contained in:
Ben Gruver 2018-02-01 13:25:21 -08:00
parent 2d227a7349
commit cc34359691
14 changed files with 405 additions and 164 deletions

View File

@ -45,7 +45,7 @@ import java.util.List;
import java.util.Map;
public interface ClassSection<StringKey extends CharSequence, TypeKey extends CharSequence, TypeListKey, ClassKey,
FieldKey, MethodKey, AnnotationSetKey, EncodedValue> extends IndexSection<ClassKey> {
FieldKey, MethodKey, AnnotationSetKey, EncodedArrayKey> extends IndexSection<ClassKey> {
@Nonnull Collection<? extends ClassKey> getSortedClasses();
@Nullable Map.Entry<? extends ClassKey, Integer> getClassEntryByType(@Nullable TypeKey key);
@ -55,7 +55,7 @@ public interface ClassSection<StringKey extends CharSequence, TypeKey extends Ch
@Nullable TypeKey getSuperclass(@Nonnull ClassKey key);
@Nullable TypeListKey getInterfaces(@Nonnull ClassKey key);
@Nullable StringKey getSourceFile(@Nonnull ClassKey key);
@Nullable Collection<? extends EncodedValue> getStaticInitializers(@Nonnull ClassKey key);
@Nullable EncodedArrayKey getStaticInitializers(@Nonnull ClassKey key);
@Nonnull Collection<? extends FieldKey> getSortedStaticFields(@Nonnull ClassKey key);
@Nonnull Collection<? extends FieldKey> getSortedInstanceFields(@Nonnull ClassKey key);
@ -81,9 +81,6 @@ public interface ClassSection<StringKey extends CharSequence, TypeKey extends Ch
@Nullable TypeKey getExceptionType(@Nonnull ExceptionHandler handler);
@Nonnull MutableMethodImplementation makeMutableMethodImplementation(@Nonnull MethodKey key);
void setEncodedArrayOffset(@Nonnull ClassKey key, int offset);
int getEncodedArrayOffset(@Nonnull ClassKey key);
void setAnnotationDirectoryOffset(@Nonnull ClassKey key, int offset);
int getAnnotationDirectoryOffset(@Nonnull ClassKey key);

View File

@ -63,7 +63,6 @@ import org.jf.dexlib2.writer.io.DeferredOutputStreamFactory;
import org.jf.dexlib2.writer.io.DexDataStore;
import org.jf.dexlib2.writer.io.MemoryDeferredOutputStream;
import org.jf.dexlib2.writer.util.TryListBuilder;
import org.jf.util.CollectionUtils;
import org.jf.util.ExceptionWithContext;
import javax.annotation.Nonnull;
@ -88,6 +87,7 @@ public abstract class DexWriter<
AnnotationKey extends Annotation, AnnotationSetKey,
TypeListKey,
FieldKey, MethodKey,
EncodedArrayKey,
EncodedValue,
AnnotationElement extends org.jf.dexlib2.iface.AnnotationElement,
StringSectionType extends StringSection<StringKey, StringRef>,
@ -96,11 +96,12 @@ public abstract class DexWriter<
FieldSectionType extends FieldSection<StringKey, TypeKey, FieldRefKey, FieldKey>,
MethodSectionType extends MethodSection<StringKey, TypeKey, ProtoRefKey, MethodRefKey, MethodKey>,
ClassSectionType extends ClassSection<StringKey, TypeKey, TypeListKey, ClassKey, FieldKey, MethodKey,
AnnotationSetKey, EncodedValue>,
AnnotationSetKey, EncodedArrayKey>,
TypeListSectionType extends TypeListSection<TypeKey, TypeListKey>,
AnnotationSectionType extends AnnotationSection<StringKey, TypeKey, AnnotationKey, AnnotationElement,
EncodedValue>,
AnnotationSetSectionType extends AnnotationSetSection<AnnotationKey, AnnotationSetKey>> {
AnnotationSetSectionType extends AnnotationSetSection<AnnotationKey, AnnotationSetKey>,
EncodedArraySectionType extends EncodedArraySection<EncodedArrayKey, EncodedValue>> {
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<EncodedValue> {
@Nonnull Collection<? extends EncodedValue> 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<EncodedArrayKey<EncodedValue>, Integer> internedItems = Maps.newHashMap();
EncodedArrayKey<EncodedValue> key = new EncodedArrayKey<EncodedValue>();
for (ClassKey classKey: classSection.getSortedClasses()) {
Collection <? extends EncodedValue> 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<EncodedValue>();
numEncodedArrayItems++;
writer.writeUleb128(elements.size());
for (EncodedValue value: elements) {
writeEncodedValue(encodedValueWriter, value);
}
}
for (Map.Entry<? extends EncodedArrayKey, Integer> entry: encodedArraySection.getItems()) {
entry.setValue(writer.getPosition());
List<? extends EncodedValue> 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();
}
}

View File

@ -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<EncodedArrayKey, EncodedValue> extends OffsetSection<EncodedArrayKey> {
List<? extends EncodedValue> getEncodedValueList(EncodedArrayKey encodedArrayKey);
}

View File

@ -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<BuilderField> instanceFields;
@Nonnull final SortedSet<BuilderMethod> directMethods;
@Nonnull final SortedSet<BuilderMethod> 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<? extends BuilderField> fields,
@Nullable Iterable<? extends BuilderMethod> methods) {
if (fields == null) {
fields = ImmutableList.of();
}
@Nullable SortedSet<BuilderField> staticFields,
@Nullable SortedSet<BuilderField> instanceFields,
@Nullable Iterable<? extends BuilderMethod> 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(); }

View File

@ -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<BuilderStringReference,
BuilderTypeReference, BuilderTypeList, BuilderClassDef, BuilderField, BuilderMethod, BuilderAnnotationSet,
BuilderEncodedValue> {
BuilderArrayEncodedValue> {
@Nonnull private final ConcurrentMap<String, BuilderClassDef> internedItems =
Maps.newConcurrentMap();
@ -153,24 +156,8 @@ public class BuilderClassPool extends BaseBuilderPool implements ClassSection<Bu
};
@Nullable @Override
public Collection<? extends BuilderEncodedValue> getStaticInitializers(@Nonnull BuilderClassDef classDef) {
final SortedSet<BuilderField> sortedStaticFields = classDef.getStaticFields();
final int lastIndex = CollectionUtils.lastIndexOf(sortedStaticFields, HAS_INITIALIZER);
if (lastIndex > -1) {
return new AbstractCollection<BuilderEncodedValue>() {
@Nonnull @Override public Iterator<BuilderEncodedValue> 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<Bu
return new MutableMethodImplementation(impl);
}
@Override public void setEncodedArrayOffset(@Nonnull BuilderClassDef builderClassDef, int offset) {
builderClassDef.encodedArrayOffset = offset;
}
@Override public int getEncodedArrayOffset(@Nonnull BuilderClassDef builderClassDef) {
return builderClassDef.encodedArrayOffset;
}
@Override public void setAnnotationDirectoryOffset(@Nonnull BuilderClassDef builderClassDef, int offset) {
builderClassDef.annotationDirectoryOffset = offset;
}

View File

@ -0,0 +1,94 @@
/*
* 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.builder;
import com.google.common.collect.Maps;
import org.jf.dexlib2.iface.value.ArrayEncodedValue;
import org.jf.dexlib2.writer.EncodedArraySection;
import org.jf.dexlib2.writer.builder.BuilderEncodedValues.BuilderArrayEncodedValue;
import org.jf.dexlib2.writer.builder.BuilderEncodedValues.BuilderEncodedValue;
import javax.annotation.Nonnull;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentMap;
public class BuilderEncodedArrayPool extends BaseBuilderPool implements
EncodedArraySection<BuilderArrayEncodedValue, BuilderEncodedValue> {
@Nonnull private final ConcurrentMap<ArrayEncodedValue, BuilderArrayEncodedValue> 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<? extends Map.Entry<? extends BuilderArrayEncodedValue, Integer>> getItems() {
return new BuilderMapEntryCollection<BuilderArrayEncodedValue>(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<? extends BuilderEncodedValue> getEncodedValueList(BuilderArrayEncodedValue builderArrayEncodedValue) {
return builderArrayEncodedValue.elements;
}
}

View File

@ -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<? extends BuilderEncodedValue> elements;
int offset = DexWriter.NO_OFFSET;
BuilderArrayEncodedValue(@Nonnull List<? extends BuilderEncodedValue> elements) {
this.elements = elements;

View File

@ -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<BuilderStringReference, BuilderStringReference, BuilderTypeReference,
BuilderTypeReference, BuilderMethodProtoReference, BuilderFieldReference, BuilderMethodReference,
BuilderClassDef, BuilderAnnotation, BuilderAnnotationSet, BuilderTypeList, BuilderField, BuilderMethod,
BuilderEncodedValue, BuilderAnnotationElement, BuilderStringPool, BuilderTypePool, BuilderProtoPool,
BuilderFieldPool, BuilderMethodPool, BuilderClassPool, BuilderTypeListPool, BuilderAnnotationPool,
BuilderAnnotationSetPool> {
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<BuilderStringReference, BuilderStringR
}
}
ImmutableSortedSet<BuilderField> staticFields = null;
ImmutableSortedSet<BuilderField> 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<BuilderStringReference, BuilderStringR
return internEncodedValue(encodedValue);
}
@Nonnull private BuilderEncodedValue internEncodedValue(@Nonnull EncodedValue encodedValue) {
@Nonnull BuilderEncodedValue internEncodedValue(@Nonnull EncodedValue encodedValue) {
switch (encodedValue.getValueType()) {
case ValueType.ANNOTATION:
return internAnnotationEncodedValue((AnnotationEncodedValue)encodedValue);
@ -400,5 +413,9 @@ public class DexBuilder extends DexWriter<BuilderStringReference, BuilderStringR
@Nonnull @Override public BuilderAnnotationSetPool getAnnotationSetSection() {
return new BuilderAnnotationSetPool(DexBuilder.this);
}
@Nonnull @Override public BuilderEncodedArrayPool getEncodedArraySection() {
return new BuilderEncodedArrayPool(DexBuilder.this);
}
}
}

View File

@ -33,7 +33,10 @@ package org.jf.dexlib2.writer.pool;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.*;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.collect.Ordering;
import org.jf.dexlib2.DebugItemType;
import org.jf.dexlib2.ReferenceType;
import org.jf.dexlib2.builder.MutableMethodImplementation;
@ -42,14 +45,13 @@ import org.jf.dexlib2.iface.debug.*;
import org.jf.dexlib2.iface.instruction.Instruction;
import org.jf.dexlib2.iface.instruction.ReferenceInstruction;
import org.jf.dexlib2.iface.reference.*;
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.dexlib2.util.ReferenceUtil;
import org.jf.dexlib2.writer.ClassSection;
import org.jf.dexlib2.writer.DebugWriter;
import org.jf.dexlib2.writer.util.StaticInitializerUtil;
import org.jf.util.AbstractForwardSequentialList;
import org.jf.util.CollectionUtils;
import org.jf.util.ExceptionWithContext;
import javax.annotation.Nonnull;
@ -60,7 +62,7 @@ import java.util.Map.Entry;
public class ClassPool extends BasePool<String, PoolClassDef> implements ClassSection<CharSequence, CharSequence,
TypeListPool.Key<? extends Collection<? extends CharSequence>>, PoolClassDef, Field, PoolMethod,
Set<? extends Annotation>, EncodedValue> {
Set<? extends Annotation>, ArrayEncodedValue> {
public ClassPool(@Nonnull DexPool dexPool) {
super(dexPool);
@ -94,6 +96,11 @@ public class ClassPool extends BasePool<String, PoolClassDef> implements ClassSe
}
dexPool.annotationSetSection.intern(field.getAnnotations());
ArrayEncodedValue staticInitializers = getStaticInitializers(poolClassDef);
if (staticInitializers != null) {
dexPool.encodedArraySection.intern(staticInitializers);
}
}
HashSet<String> methods = new HashSet<String>();
@ -240,44 +247,9 @@ public class ClassPool extends BasePool<String, PoolClassDef> implements ClassSe
return classDef.getSourceFile();
}
private static final Predicate<Field> HAS_INITIALIZER = new Predicate<Field>() {
@Override
public boolean apply(Field input) {
EncodedValue encodedValue = input.getInitialValue();
return encodedValue != null && !EncodedValueUtils.isDefaultValue(encodedValue);
}
};
private static final Function<Field, EncodedValue> GET_INITIAL_VALUE = new Function<Field, EncodedValue>() {
@Override
public EncodedValue apply(Field input) {
EncodedValue initialValue = input.getInitialValue();
if (initialValue == null) {
return ImmutableEncodedValueFactory.defaultValueForType(input.getType());
}
return initialValue;
}
};
@Nullable @Override public Collection<? extends EncodedValue> getStaticInitializers(
@Nullable @Override public ArrayEncodedValue getStaticInitializers(
@Nonnull PoolClassDef classDef) {
final SortedSet<Field> sortedStaticFields = classDef.getStaticFields();
final int lastIndex = CollectionUtils.lastIndexOf(sortedStaticFields, HAS_INITIALIZER);
if (lastIndex > -1) {
return new AbstractCollection<EncodedValue>() {
@Nonnull @Override public Iterator<EncodedValue> 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<? extends Field> getSortedStaticFields(@Nonnull PoolClassDef classDef) {
@ -421,14 +393,6 @@ public class ClassPool extends BasePool<String, PoolClassDef> 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;
}

View File

@ -54,8 +54,8 @@ public class DexPool extends DexWriter<CharSequence, StringReference, CharSequen
MethodProtoReference, FieldReference, MethodReference, PoolClassDef,
Annotation, Set<? extends Annotation>,
TypeListPool.Key<? extends Collection<? extends CharSequence>>, 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<CharSequence, StringReference, CharSequen
@Nonnull @Override public AnnotationSetPool getAnnotationSetSection() {
return new AnnotationSetPool(DexPool.this);
}
@Nonnull @Override public EncodedArrayPool getEncodedArraySection() {
return new EncodedArrayPool(DexPool.this);
}
}
}

View File

@ -0,0 +1,61 @@
/*
* 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.pool;
import org.jf.dexlib2.iface.value.ArrayEncodedValue;
import org.jf.dexlib2.iface.value.EncodedValue;
import org.jf.dexlib2.writer.EncodedArraySection;
import javax.annotation.Nonnull;
import java.util.List;
public class EncodedArrayPool extends BaseOffsetPool<ArrayEncodedValue>
implements EncodedArraySection<ArrayEncodedValue, EncodedValue> {
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<? extends EncodedValue> getEncodedValueList(ArrayEncodedValue arrayEncodedValue) {
return arrayEncodedValue.getValue();
}
}

View File

@ -50,7 +50,6 @@ class PoolClassDef extends BaseTypeReference implements ClassDef {
@Nonnull final ImmutableSortedSet<PoolMethod> virtualMethods;
int classDefIndex = DexPool.NO_INDEX;
int encodedArrayOffset = DexPool.NO_OFFSET;
int annotationDirectoryOffset = DexPool.NO_OFFSET;
PoolClassDef(@Nonnull ClassDef classDef) {

View File

@ -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<? extends Field> sortedStaticFields) {
final int lastIndex = CollectionUtils.lastIndexOf(sortedStaticFields, HAS_INITIALIZER);
if (lastIndex > -1) {
return new BaseArrayEncodedValue() {
@Nonnull
@Override
public List<? extends EncodedValue> getValue() {
return new AbstractForwardSequentialList<EncodedValue>() {
@Nonnull @Override public Iterator<EncodedValue> 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<Field> HAS_INITIALIZER = new Predicate<Field>() {
@Override
public boolean apply(Field input) {
EncodedValue encodedValue = input.getInitialValue();
return encodedValue != null && !EncodedValueUtils.isDefaultValue(encodedValue);
}
};
private static final Function<Field, EncodedValue> GET_INITIAL_VALUE = new Function<Field, EncodedValue>() {
@Override
public EncodedValue apply(Field input) {
EncodedValue initialValue = input.getInitialValue();
if (initialValue == null) {
return ImmutableEncodedValueFactory.defaultValueForType(input.getType());
}
return initialValue;
}
};
}

View File

@ -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;