Implement support for new structures in DexWriter

This commit is contained in:
Ben Gruver 2018-02-02 13:06:52 -08:00
parent cc34359691
commit 5c5e4ae279
20 changed files with 1046 additions and 39 deletions

View File

@ -35,10 +35,7 @@ public class VersionMap {
public static final int NO_VERSION = -1;
public static int mapArtVersionToApi(int artVersion) {
// NOTE: Art version 87 and api level 26 do not correspond to any
// particular android release and represent the current (as of
// October 2016) state of aosp/master.
if (artVersion >= 87) {
if (artVersion >= 124) {
return 26;
}
if (artVersion >= 79) {
@ -70,13 +67,15 @@ public class VersionMap {
case 24:
case 25:
return 79;
case 26:
return 124;
}
// NOTE: Art version 87 and api level 26 do not correspond to any
// NOTE: Art version 143 and api level 27 do not correspond to any
// particular android release and represent the current (as of
// October 2016) state of aosp/master.
if (api > 25) {
return 87;
// May 2018) state of aosp/master.
if (api > 26) {
return 143;
}
return NO_VERSION;
}

View File

@ -43,7 +43,7 @@ public class HeaderItem {
public static final int ITEM_SIZE = 0x70;
private static final byte[] MAGIC_VALUE = new byte[] { 0x64, 0x65, 0x78, 0x0a, 0x00, 0x00, 0x00, 0x00 };
private static final int[] SUPPORTED_DEX_VERSIONS = new int[] { 35, 37 };
private static final int[] SUPPORTED_DEX_VERSIONS = new int[] { 35, 37, 38 };
public static final int LITTLE_ENDIAN_TAG = 0x12345678;
public static final int BIG_ENDIAN_TAG = 0x78563412;
@ -232,9 +232,11 @@ public class HeaderItem {
if (api < 24) {
// Prior to Android N we only support dex version 035.
return getMagicForDexVersion(35);
} else {
} if (api < 26) {
// On android N and later we support dex version 037.
return getMagicForDexVersion(37);
} else {
return getMagicForDexVersion(38);
}
}

View File

@ -51,6 +51,8 @@ public abstract class DexBackedReference {
return new DexBackedFieldReference(dexFile, referenceIndex);
case ReferenceType.METHOD_PROTO:
return new DexBackedMethodProtoReference(dexFile, referenceIndex);
case ReferenceType.CALL_SITE:
return new DexBackedCallSiteReference(dexFile, referenceIndex);
default:
throw new ExceptionWithContext("Invalid reference type: %d", referenceType);
}

View File

@ -0,0 +1,39 @@
/*
* 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 org.jf.dexlib2.iface.reference.CallSiteReference;
public interface CallSiteSection<CallSiteKey extends CallSiteReference, EncodedArrayKey>
extends IndexSection<CallSiteKey> {
EncodedArrayKey getEncodedCallSite(CallSiteKey callSiteReference);
}

View File

@ -35,10 +35,8 @@ import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Ordering;
import org.jf.dexlib2.AccessFlags;
import org.jf.dexlib2.Opcode;
import org.jf.dexlib2.Opcodes;
import org.jf.dexlib2.ReferenceType;
import com.google.common.primitives.Ints;
import org.jf.dexlib2.*;
import org.jf.dexlib2.base.BaseAnnotation;
import org.jf.dexlib2.base.BaseAnnotationElement;
import org.jf.dexlib2.builder.MutableMethodImplementation;
@ -84,6 +82,8 @@ public abstract class DexWriter<
TypeRef extends TypeReference, ProtoRefKey extends MethodProtoReference,
FieldRefKey extends FieldReference, MethodRefKey extends MethodReference,
ClassKey extends Comparable<? super ClassKey>,
CallSiteKey extends CallSiteReference,
MethodHandleKey extends MethodHandleReference,
AnnotationKey extends Annotation, AnnotationSetKey,
TypeListKey,
FieldKey, MethodKey,
@ -97,6 +97,8 @@ public abstract class DexWriter<
MethodSectionType extends MethodSection<StringKey, TypeKey, ProtoRefKey, MethodRefKey, MethodKey>,
ClassSectionType extends ClassSection<StringKey, TypeKey, TypeListKey, ClassKey, FieldKey, MethodKey,
AnnotationSetKey, EncodedArrayKey>,
CallSiteSectionType extends CallSiteSection<CallSiteKey, EncodedArrayKey>,
MethodHandleSectionType extends MethodHandleSection<MethodHandleKey, FieldRefKey, MethodRefKey>,
TypeListSectionType extends TypeListSection<TypeKey, TypeListKey>,
AnnotationSectionType extends AnnotationSection<StringKey, TypeKey, AnnotationKey, AnnotationElement,
EncodedValue>,
@ -113,6 +115,8 @@ public abstract class DexWriter<
protected int fieldSectionOffset = NO_OFFSET;
protected int methodSectionOffset = NO_OFFSET;
protected int classIndexSectionOffset = NO_OFFSET;
protected int callSiteSectionOffset = NO_OFFSET;
protected int methodHandleSectionOffset = NO_OFFSET;
protected int stringDataSectionOffset = NO_OFFSET;
protected int classDataSectionOffset = NO_OFFSET;
@ -138,6 +142,8 @@ public abstract class DexWriter<
public final FieldSectionType fieldSection;
public final MethodSectionType methodSection;
public final ClassSectionType classSection;
public final CallSiteSectionType callSiteSection;
public final MethodHandleSectionType methodHandleSection;
public final TypeListSectionType typeListSection;
public final AnnotationSectionType annotationSection;
@ -154,6 +160,8 @@ public abstract class DexWriter<
this.fieldSection = sectionProvider.getFieldSection();
this.methodSection = sectionProvider.getMethodSection();
this.classSection = sectionProvider.getClassSection();
this.callSiteSection = sectionProvider.getCallSiteSection();
this.methodHandleSection = sectionProvider.getMethodHandleSection();
this.typeListSection = sectionProvider.getTypeListSection();
this.annotationSection = sectionProvider.getAnnotationSection();
this.annotationSetSection = sectionProvider.getAnnotationSetSection();
@ -165,6 +173,16 @@ public abstract class DexWriter<
protected abstract void writeEncodedValue(@Nonnull InternalEncodedValueWriter writer,
@Nonnull EncodedValue encodedValue) throws IOException;
private Comparator<Map.Entry<? extends CallSiteKey, Integer>> callSiteComparator =
new Comparator<Entry<? extends CallSiteKey, Integer>>() {
@Override
public int compare(Entry<? extends CallSiteKey, Integer> o1, Entry<? extends CallSiteKey, Integer> o2) {
int offset1 = encodedArraySection.getItemOffset(callSiteSection.getEncodedCallSite(o1.getKey()));
int offset2 = encodedArraySection.getItemOffset(callSiteSection.getEncodedCallSite(o2.getKey()));
return Ints.compare(offset1, offset2);
}
};
private static Comparator<Map.Entry> toStringKeyComparator =
new Comparator<Map.Entry>() {
@Override public int compare(Entry o1, Entry o2) {
@ -181,9 +199,10 @@ public abstract class DexWriter<
}
protected class InternalEncodedValueWriter extends EncodedValueWriter<StringKey, TypeKey, FieldRefKey, MethodRefKey,
AnnotationElement, EncodedValue> {
AnnotationElement, ProtoRefKey, MethodHandleKey, EncodedValue> {
private InternalEncodedValueWriter(@Nonnull DexDataWriter writer) {
super(writer, stringSection, typeSection, fieldSection, methodSection, annotationSection);
super(writer, stringSection, typeSection, fieldSection, methodSection, protoSection, methodHandleSection,
annotationSection);
}
@Override protected void writeEncodedValue(@Nonnull EncodedValue encodedValue) throws IOException {
@ -198,7 +217,9 @@ public abstract class DexWriter<
protoSection.getItemCount() * ProtoIdItem.ITEM_SIZE +
fieldSection.getItemCount() * FieldIdItem.ITEM_SIZE +
methodSection.getItemCount() * MethodIdItem.ITEM_SIZE +
classSection.getItemCount() * ClassDefItem.ITEM_SIZE;
classSection.getItemCount() * ClassDefItem.ITEM_SIZE +
callSiteSection.getItemCount() * CallSiteIdItem.ITEM_SIZE +
methodHandleSection.getItemCount() * MethodHandleItem.ITEM_SIZE;
}
@Nonnull
@ -262,14 +283,36 @@ public abstract class DexWriter<
writeProtos(indexWriter);
writeFields(indexWriter);
writeMethods(indexWriter);
// encoded arrays depend on method handles..
DexDataWriter methodHandleWriter = outputAt(dest, indexWriter.getPosition() +
classSection.getItemCount() * ClassDefItem.ITEM_SIZE +
callSiteSection.getItemCount() * CallSiteIdItem.ITEM_SIZE);
try {
writeMethodHandles(methodHandleWriter);
} finally {
methodHandleWriter.close();
}
// call sites depend on encoded arrays..
writeEncodedArrays(offsetWriter);
// class defs depend on method handles and call sites..
DexDataWriter callSiteWriter = outputAt(dest, indexWriter.getPosition() +
classSection.getItemCount() * ClassDefItem.ITEM_SIZE);
try {
writeCallSites(callSiteWriter);
} finally {
callSiteWriter.close();
}
writeAnnotations(offsetWriter);
writeAnnotationSets(offsetWriter);
writeAnnotationSetRefs(offsetWriter);
writeAnnotationDirectories(offsetWriter);
writeDebugAndCodeItems(offsetWriter, tempFactory.makeDeferredOutputStream());
writeEncodedArrays(offsetWriter);
writeClasses(indexWriter, offsetWriter);
writeMapItem(offsetWriter);
writeHeader(headerWriter, dataSectionOffset, offsetWriter.getPosition());
} finally {
@ -511,6 +554,55 @@ public abstract class DexWriter<
return nextIndex;
}
private void writeCallSites(DexDataWriter writer) throws IOException {
callSiteSectionOffset = writer.getPosition();
List<Map.Entry<? extends CallSiteKey, Integer>> callSiteEntries =
Lists.newArrayList(callSiteSection.getItems());
Collections.sort(callSiteEntries, callSiteComparator);
int index = 0;
for (Map.Entry<? extends CallSiteKey, Integer> callSite: callSiteEntries) {
callSite.setValue(index++);
writer.writeInt(encodedArraySection.getItemOffset(callSiteSection.getEncodedCallSite(callSite.getKey())));
}
}
private void writeMethodHandles(DexDataWriter writer) throws IOException {
methodHandleSectionOffset = writer.getPosition();
int index = 0;
for (Entry<? extends MethodHandleKey, Integer> entry: methodHandleSection.getItems()) {
entry.setValue(index++);
MethodHandleKey methodHandleReference = entry.getKey();
writer.writeUshort(methodHandleReference.getMethodHandleType());
writer.writeUshort(0);
int memberIndex;
switch (methodHandleReference.getMethodHandleType()) {
case MethodHandleType.INSTANCE_GET:
case MethodHandleType.INSTANCE_PUT:
case MethodHandleType.STATIC_GET:
case MethodHandleType.STATIC_PUT:
memberIndex = fieldSection.getItemIndex(
methodHandleSection.getFieldReference(methodHandleReference));
break;
case MethodHandleType.INVOKE_INSTANCE:
case MethodHandleType.INVOKE_STATIC:
memberIndex = methodSection.getItemIndex(
methodHandleSection.getMethodReference(methodHandleReference));
break;
default:
throw new ExceptionWithContext("Invalid method handle type: %d",
methodHandleReference.getMethodHandleType());
}
writer.writeUshort(memberIndex);
writer.writeUshort(0);
}
}
private void writeEncodedFields(@Nonnull DexDataWriter writer, @Nonnull Collection<? extends FieldKey> fields)
throws IOException {
int prevIndex = 0;
@ -1311,6 +1403,8 @@ public abstract class DexWriter<
@Nonnull public abstract FieldSectionType getFieldSection();
@Nonnull public abstract MethodSectionType getMethodSection();
@Nonnull public abstract ClassSectionType getClassSection();
@Nonnull public abstract CallSiteSectionType getCallSiteSection();
@Nonnull public abstract MethodHandleSectionType getMethodHandleSection();
@Nonnull public abstract TypeListSectionType getTypeListSection();
@Nonnull public abstract AnnotationSectionType getAnnotationSection();
@Nonnull public abstract AnnotationSetSectionType getAnnotationSetSection();

View File

@ -35,6 +35,7 @@ import com.google.common.collect.Ordering;
import org.jf.dexlib2.ValueType;
import org.jf.dexlib2.base.BaseAnnotationElement;
import org.jf.dexlib2.iface.reference.FieldReference;
import org.jf.dexlib2.iface.reference.MethodHandleReference;
import org.jf.dexlib2.iface.reference.MethodReference;
import javax.annotation.Nonnull;
@ -43,12 +44,14 @@ import java.util.Collection;
public abstract class EncodedValueWriter<StringKey, TypeKey, FieldRefKey extends FieldReference,
MethodRefKey extends MethodReference, AnnotationElement extends org.jf.dexlib2.iface.AnnotationElement,
EncodedValue> {
ProtoRefKey, MethodHandleKey extends MethodHandleReference, EncodedValue> {
@Nonnull private final DexDataWriter writer;
@Nonnull private final StringSection<StringKey, ?> stringSection;
@Nonnull private final TypeSection<?, TypeKey, ?> typeSection;
@Nonnull private final FieldSection<?, ?, FieldRefKey, ?> fieldSection;
@Nonnull private final MethodSection<?, ?, ?, MethodRefKey, ?> methodSection;
@Nonnull private final ProtoSection<?, ?, ProtoRefKey, ?> protoSection;
@Nonnull private final MethodHandleSection<MethodHandleKey, ?, ?> methodHandleSection;
@Nonnull private final AnnotationSection<StringKey, TypeKey, ?, AnnotationElement, EncodedValue> annotationSection;
public EncodedValueWriter(
@ -57,12 +60,16 @@ public abstract class EncodedValueWriter<StringKey, TypeKey, FieldRefKey extends
@Nonnull TypeSection<?, TypeKey, ?> typeSection,
@Nonnull FieldSection<?, ?, FieldRefKey, ?> fieldSection,
@Nonnull MethodSection<?, ?, ?, MethodRefKey, ?> methodSection,
ProtoSection<?, ?, ProtoRefKey, ?> protoSection,
MethodHandleSection<MethodHandleKey, ?, ?> methodHandleSection,
@Nonnull AnnotationSection<StringKey, TypeKey, ?, AnnotationElement, EncodedValue> annotationSection) {
this.writer = writer;
this.stringSection = stringSection;
this.typeSection = typeSection;
this.fieldSection = fieldSection;
this.methodSection = methodSection;
this.protoSection = protoSection;
this.methodHandleSection = methodHandleSection;
this.annotationSection = annotationSection;
}
@ -146,4 +153,12 @@ public abstract class EncodedValueWriter<StringKey, TypeKey, FieldRefKey extends
public void writeType(@Nonnull TypeKey value) throws IOException {
writer.writeEncodedUint(ValueType.TYPE, typeSection.getItemIndex(value));
}
public void writeMethodType(@Nonnull ProtoRefKey value) throws IOException {
writer.writeEncodedUint(ValueType.METHOD_TYPE, protoSection.getItemIndex(value));
}
public void writeMethodHandle(@Nonnull MethodHandleKey value) throws IOException {
writer.writeEncodedUint(ValueType.METHOD_HANDLE, methodHandleSection.getItemIndex(value));
}
}

View File

@ -40,12 +40,7 @@ import org.jf.dexlib2.iface.instruction.DualReferenceInstruction;
import org.jf.dexlib2.iface.instruction.ReferenceInstruction;
import org.jf.dexlib2.iface.instruction.SwitchElement;
import org.jf.dexlib2.iface.instruction.formats.*;
import org.jf.dexlib2.iface.reference.FieldReference;
import org.jf.dexlib2.iface.reference.MethodProtoReference;
import org.jf.dexlib2.iface.reference.MethodReference;
import org.jf.dexlib2.iface.reference.Reference;
import org.jf.dexlib2.iface.reference.StringReference;
import org.jf.dexlib2.iface.reference.TypeReference;
import org.jf.dexlib2.iface.reference.*;
import org.jf.util.ExceptionWithContext;
import javax.annotation.Nonnull;
@ -55,7 +50,7 @@ import java.util.List;
public class InstructionWriter<StringRef extends StringReference, TypeRef extends TypeReference,
FieldRefKey extends FieldReference, MethodRefKey extends MethodReference,
ProtoRefKey extends MethodProtoReference> {
ProtoRefKey extends MethodProtoReference, CallSiteKey extends CallSiteReference> {
@Nonnull private final Opcodes opcodes;
@Nonnull private final DexDataWriter writer;
@Nonnull private final StringSection<?, StringRef> stringSection;
@ -63,10 +58,12 @@ public class InstructionWriter<StringRef extends StringReference, TypeRef extend
@Nonnull private final FieldSection<?, ?, FieldRefKey, ?> fieldSection;
@Nonnull private final MethodSection<?, ?, ?, MethodRefKey, ?> methodSection;
@Nonnull private final ProtoSection<?, ?, ProtoRefKey, ?> protoSection;
@Nonnull private final CallSiteSection<CallSiteKey, ?> callSiteSection;
@Nonnull static <StringRef extends StringReference, TypeRef extends TypeReference, FieldRefKey extends FieldReference,
MethodRefKey extends MethodReference, ProtoRefKey extends MethodProtoReference>
InstructionWriter<StringRef, TypeRef, FieldRefKey, MethodRefKey, ProtoRefKey>
@Nonnull static <StringRef extends StringReference, TypeRef extends TypeReference,
FieldRefKey extends FieldReference, MethodRefKey extends MethodReference,
ProtoRefKey extends MethodProtoReference, CallSiteKey extends CallSiteReference>
InstructionWriter<StringRef, TypeRef, FieldRefKey, MethodRefKey, ProtoRefKey, CallSiteKey>
makeInstructionWriter(
@Nonnull Opcodes opcodes,
@Nonnull DexDataWriter writer,
@ -74,9 +71,10 @@ public class InstructionWriter<StringRef extends StringReference, TypeRef extend
@Nonnull TypeSection<?, ?, TypeRef> typeSection,
@Nonnull FieldSection<?, ?, FieldRefKey, ?> fieldSection,
@Nonnull MethodSection<?, ?, ?, MethodRefKey, ?> methodSection,
@Nonnull ProtoSection<?, ?, ProtoRefKey, ?> protoSection) {
return new InstructionWriter<StringRef, TypeRef, FieldRefKey, MethodRefKey, ProtoRefKey>(
opcodes, writer, stringSection, typeSection, fieldSection, methodSection, protoSection);
@Nonnull ProtoSection<?, ?, ProtoRefKey, ?> protoSection,
@Nonnull CallSiteSection<CallSiteKey, ?> callSiteSection) {
return new InstructionWriter<StringRef, TypeRef, FieldRefKey, MethodRefKey, ProtoRefKey, CallSiteKey>(
opcodes, writer, stringSection, typeSection, fieldSection, methodSection, protoSection, callSiteSection);
}
InstructionWriter(@Nonnull Opcodes opcodes,
@ -85,7 +83,8 @@ public class InstructionWriter<StringRef extends StringReference, TypeRef extend
@Nonnull TypeSection<?, ?, TypeRef> typeSection,
@Nonnull FieldSection<?, ?, FieldRefKey, ?> fieldSection,
@Nonnull MethodSection<?, ?, ?, MethodRefKey, ?> methodSection,
@Nonnull ProtoSection<?, ?, ProtoRefKey, ?> protoSection) {
@Nonnull ProtoSection<?, ?, ProtoRefKey, ?> protoSection,
@Nonnull CallSiteSection<CallSiteKey, ?> callSiteSection) {
this.opcodes = opcodes;
this.writer = writer;
this.stringSection = stringSection;
@ -93,6 +92,7 @@ public class InstructionWriter<StringRef extends StringReference, TypeRef extend
this.fieldSection = fieldSection;
this.methodSection = methodSection;
this.protoSection = protoSection;
this.callSiteSection = callSiteSection;
}
private short getOpcodeValue(Opcode opcode) {
@ -551,6 +551,8 @@ public class InstructionWriter<StringRef extends StringReference, TypeRef extend
return typeSection.getItemIndex((TypeRef) reference);
case ReferenceType.METHOD_PROTO:
return protoSection.getItemIndex((ProtoRefKey) reference);
case ReferenceType.CALL_SITE:
return callSiteSection.getItemIndex((CallSiteKey) reference);
default:
throw new ExceptionWithContext("Unknown reference type: %d", referenceType);
}

View File

@ -0,0 +1,42 @@
/*
* 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 org.jf.dexlib2.iface.reference.FieldReference;
import org.jf.dexlib2.iface.reference.MethodHandleReference;
import org.jf.dexlib2.iface.reference.MethodReference;
public interface MethodHandleSection<MethodHandleKey extends MethodHandleReference, FieldRefKey extends FieldReference,
MethodRefKey extends MethodReference> extends IndexSection<MethodHandleKey> {
FieldRefKey getFieldReference(MethodHandleKey methodHandleReference);
MethodRefKey getMethodReference(MethodHandleKey methodHandleReference);
}

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.builder;
import com.google.common.collect.Maps;
import org.jf.dexlib2.iface.reference.CallSiteReference;
import org.jf.dexlib2.writer.CallSiteSection;
import org.jf.dexlib2.writer.builder.BuilderEncodedValues.BuilderArrayEncodedValue;
import org.jf.dexlib2.writer.util.CallSiteUtil;
import javax.annotation.Nonnull;
import java.util.Collection;
import java.util.Map;
import java.util.concurrent.ConcurrentMap;
public class BuilderCallSitePool extends BaseBuilderPool
implements CallSiteSection<BuilderCallSiteReference, BuilderArrayEncodedValue> {
@Nonnull private final ConcurrentMap<CallSiteReference, BuilderCallSiteReference> internedItems =
Maps.newConcurrentMap();
public BuilderCallSitePool(@Nonnull DexBuilder dexBuilder) {
super(dexBuilder);
}
@Nonnull public BuilderCallSiteReference internCallSite(@Nonnull CallSiteReference callSiteReference) {
BuilderCallSiteReference internedCallSite = internedItems.get(callSiteReference);
if (internedCallSite != null) {
return internedCallSite;
}
BuilderArrayEncodedValue encodedCallSite = dexBuilder.encodedArraySection.internArrayEncodedValue(
CallSiteUtil.getEncodedCallSite(callSiteReference));
internedCallSite = new BuilderCallSiteReference(callSiteReference.getName(), encodedCallSite);
BuilderCallSiteReference existing = internedItems.putIfAbsent(internedCallSite, internedCallSite);
return existing == null ? internedCallSite : existing;
}
@Override
public BuilderArrayEncodedValue getEncodedCallSite(BuilderCallSiteReference callSiteReference) {
return callSiteReference.encodedCallSite;
}
@Override
public int getItemIndex(@Nonnull BuilderCallSiteReference builderCallSite) {
return builderCallSite.index;
}
@Nonnull
@Override
public Collection<? extends Map.Entry<? extends BuilderCallSiteReference, Integer>> getItems() {
return new BuilderMapEntryCollection<BuilderCallSiteReference>(internedItems.values()) {
@Override
protected int getValue(@Nonnull BuilderCallSiteReference builderCallSiteReference) {
return builderCallSiteReference.index;
}
@Override
protected int setValue(@Nonnull BuilderCallSiteReference builderCallSiteReference, int value) {
int prev = builderCallSiteReference.index;
builderCallSiteReference.index = value;
return prev;
}
};
}
@Override
public int getItemCount() {
return internedItems.size();
}
}

View File

@ -0,0 +1,88 @@
/*
* 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.ImmutableList;
import org.jf.dexlib2.base.reference.BaseCallSiteReference;
import org.jf.dexlib2.iface.value.StringEncodedValue;
import org.jf.dexlib2.writer.builder.BuilderEncodedValues.BuilderArrayEncodedValue;
import org.jf.dexlib2.writer.builder.BuilderEncodedValues.BuilderEncodedValue;
import org.jf.dexlib2.writer.builder.BuilderEncodedValues.BuilderMethodHandleEncodedValue;
import org.jf.dexlib2.writer.builder.BuilderEncodedValues.BuilderMethodTypeEncodedValue;
import javax.annotation.Nonnull;
import java.util.List;
import static org.jf.dexlib2.writer.DexWriter.NO_INDEX;
public class BuilderCallSiteReference extends BaseCallSiteReference implements BuilderReference {
@Nonnull final String name;
@Nonnull final BuilderArrayEncodedValue encodedCallSite;
int index = NO_INDEX;
public BuilderCallSiteReference(@Nonnull String name,
@Nonnull BuilderArrayEncodedValue encodedCallSite) {
this.name = name;
this.encodedCallSite = encodedCallSite;
}
@Nonnull @Override public String getName() {
return name;
}
@Nonnull @Override public BuilderMethodHandleReference getMethodHandle() {
return ((BuilderMethodHandleEncodedValue) encodedCallSite.elements.get(0)).getValue();
}
@Nonnull @Override public String getMethodName() {
return ((StringEncodedValue) encodedCallSite.elements.get(1)).getValue();
}
@Nonnull @Override public BuilderMethodProtoReference getMethodProto() {
return ((BuilderMethodTypeEncodedValue) encodedCallSite.elements.get(2)).getValue();
}
@Nonnull @Override public List<? extends BuilderEncodedValue> getExtraArguments() {
if (encodedCallSite.elements.size() <= 3) {
return ImmutableList.of();
}
return encodedCallSite.elements.subList(3, encodedCallSite.elements.size());
}
@Override public int getIndex() {
return index;
}
@Override public void setIndex(int index) {
this.index = index;
}
}

View File

@ -241,4 +241,26 @@ public abstract class BuilderEncodedValues {
return typeReference.getType();
}
}
public static class BuilderMethodTypeEncodedValue extends BaseMethodTypeEncodedValue
implements BuilderEncodedValue {
@Nonnull final BuilderMethodProtoReference methodProtoReference;
public BuilderMethodTypeEncodedValue(@Nonnull BuilderMethodProtoReference methodProtoReference) {
this.methodProtoReference = methodProtoReference;
}
@Nonnull @Override public BuilderMethodProtoReference getValue() { return methodProtoReference; }
}
public static class BuilderMethodHandleEncodedValue extends BaseMethodHandleEncodedValue
implements BuilderEncodedValue {
@Nonnull final BuilderMethodHandleReference methodHandleReference;
public BuilderMethodHandleEncodedValue(@Nonnull BuilderMethodHandleReference methodHandleReference) {
this.methodHandleReference = methodHandleReference;
}
@Nonnull @Override public BuilderMethodHandleReference getValue() { return methodHandleReference; }
}
}

View File

@ -0,0 +1,124 @@
/*
* 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.MethodHandleType;
import org.jf.dexlib2.iface.reference.FieldReference;
import org.jf.dexlib2.iface.reference.MethodHandleReference;
import org.jf.dexlib2.iface.reference.MethodReference;
import org.jf.dexlib2.writer.MethodHandleSection;
import org.jf.util.ExceptionWithContext;
import javax.annotation.Nonnull;
import java.util.Collection;
import java.util.Map;
import java.util.concurrent.ConcurrentMap;
public class BuilderMethodHandlePool extends BaseBuilderPool
implements MethodHandleSection<BuilderMethodHandleReference, BuilderFieldReference, BuilderMethodReference> {
@Nonnull private final ConcurrentMap<MethodHandleReference, BuilderMethodHandleReference> internedItems =
Maps.newConcurrentMap();
public BuilderMethodHandlePool(@Nonnull DexBuilder dexBuilder) {
super(dexBuilder);
}
public BuilderMethodHandleReference internMethodHandle(MethodHandleReference methodHandleReference) {
BuilderMethodHandleReference internedMethodHandle = internedItems.get(methodHandleReference);
if (internedMethodHandle != null) {
return internedMethodHandle;
}
BuilderReference memberReference;
switch (methodHandleReference.getMethodHandleType()) {
case MethodHandleType.INSTANCE_GET:
case MethodHandleType.INSTANCE_PUT:
case MethodHandleType.STATIC_GET:
case MethodHandleType.STATIC_PUT:
memberReference = dexBuilder.internFieldReference(
(FieldReference) methodHandleReference.getMemberReference());
break;
case MethodHandleType.INVOKE_INSTANCE:
case MethodHandleType.INVOKE_STATIC:
memberReference = dexBuilder.internMethodReference(
(MethodReference) methodHandleReference.getMemberReference());
break;
default:
throw new ExceptionWithContext("Invalid method handle type: %d",
methodHandleReference.getMethodHandleType());
}
internedMethodHandle = new BuilderMethodHandleReference(methodHandleReference.getMethodHandleType(),
memberReference);
BuilderMethodHandleReference prev = internedItems.putIfAbsent(internedMethodHandle, internedMethodHandle);
return prev == null ? internedMethodHandle : prev;
}
@Override
public BuilderFieldReference getFieldReference(BuilderMethodHandleReference methodHandleReference) {
return (BuilderFieldReference) methodHandleReference.getMemberReference();
}
@Override
public BuilderMethodReference getMethodReference(BuilderMethodHandleReference methodHandleReference) {
return (BuilderMethodReference) methodHandleReference.getMemberReference();
}
@Override
public int getItemIndex(@Nonnull BuilderMethodHandleReference builderMethodHandleReference) {
return builderMethodHandleReference.index;
}
@Nonnull
@Override
public Collection<? extends Map.Entry<? extends BuilderMethodHandleReference, Integer>> getItems() {
return new BuilderMapEntryCollection<BuilderMethodHandleReference>(internedItems.values()) {
@Override
protected int getValue(@Nonnull BuilderMethodHandleReference builderMethodHandleReference) {
return builderMethodHandleReference.index;
}
@Override
protected int setValue(@Nonnull BuilderMethodHandleReference builderMethodHandleReference, int value) {
int prev = builderMethodHandleReference.index;
builderMethodHandleReference.index = value;
return prev;
}
};
}
@Override
public int getItemCount() {
return internedItems.size();
}
}

View File

@ -0,0 +1,65 @@
/*
* 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 org.jf.dexlib2.base.reference.BaseMethodHandleReference;
import javax.annotation.Nonnull;
import static org.jf.dexlib2.writer.DexWriter.NO_INDEX;
public class BuilderMethodHandleReference extends BaseMethodHandleReference implements BuilderReference {
final int methodHandleType;
@Nonnull final BuilderReference memberReference;
int index = NO_INDEX;
public BuilderMethodHandleReference(int methodHandleType, @Nonnull BuilderReference memberReference) {
this.methodHandleType = methodHandleType;
this.memberReference = memberReference;
}
@Override public int getMethodHandleType() {
return methodHandleType;
}
@Nonnull @Override public BuilderReference getMemberReference() {
return memberReference;
}
@Override public int getIndex() {
return index;
}
@Override public void setIndex(int index) {
this.index = index;
}
}

View File

@ -56,10 +56,11 @@ import java.util.Set;
public class DexBuilder extends DexWriter<BuilderStringReference, BuilderStringReference, BuilderTypeReference,
BuilderTypeReference, BuilderMethodProtoReference, BuilderFieldReference, BuilderMethodReference,
BuilderClassDef, BuilderAnnotation, BuilderAnnotationSet, BuilderTypeList, BuilderField, BuilderMethod,
BuilderArrayEncodedValue, BuilderEncodedValue, BuilderAnnotationElement, BuilderStringPool, BuilderTypePool,
BuilderProtoPool, BuilderFieldPool, BuilderMethodPool, BuilderClassPool, BuilderTypeListPool,
BuilderAnnotationPool, BuilderAnnotationSetPool, BuilderEncodedArrayPool> {
BuilderClassDef, BuilderCallSiteReference, BuilderMethodHandleReference, BuilderAnnotation, BuilderAnnotationSet, BuilderTypeList,
BuilderField, BuilderMethod, BuilderArrayEncodedValue, BuilderEncodedValue, BuilderAnnotationElement,
BuilderStringPool, BuilderTypePool, BuilderProtoPool, BuilderFieldPool, BuilderMethodPool, BuilderClassPool,
BuilderCallSitePool, BuilderMethodHandlePool, BuilderTypeListPool, BuilderAnnotationPool,
BuilderAnnotationSetPool, BuilderEncodedArrayPool> {
public DexBuilder(@Nonnull Opcodes opcodes) {
super(opcodes);
@ -145,6 +146,14 @@ public class DexBuilder extends DexWriter<BuilderStringReference, BuilderStringR
internedStaticInitializers));
}
public BuilderCallSiteReference internCallSite(@Nonnull CallSiteReference callSiteReference) {
return callSiteSection.internCallSite(callSiteReference);
}
public BuilderMethodHandleReference internMethodHandle(@Nonnull MethodHandleReference methodHandleReference) {
return methodHandleSection.internMethodHandle(methodHandleReference);
}
@Nonnull public BuilderStringReference internStringReference(@Nonnull String string) {
return stringSection.internString(string);
}
@ -195,6 +204,12 @@ public class DexBuilder extends DexWriter<BuilderStringReference, BuilderStringR
if (reference instanceof MethodProtoReference) {
return internMethodProtoReference((MethodProtoReference) reference);
}
if (reference instanceof CallSiteReference) {
return internCallSite((CallSiteReference) reference);
}
if (reference instanceof MethodHandleReference) {
return internMethodHandle((MethodHandleReference) reference);
}
throw new IllegalArgumentException("Could not determine type of reference");
}
@ -271,6 +286,12 @@ public class DexBuilder extends DexWriter<BuilderStringReference, BuilderStringR
case ValueType.TYPE:
writer.writeType(((BuilderTypeEncodedValue)encodedValue).typeReference);
break;
case ValueType.METHOD_TYPE:
writer.writeMethodType(((BuilderMethodTypeEncodedValue) encodedValue).methodProtoReference);
break;
case ValueType.METHOD_HANDLE:
writer.writeMethodHandle(((BuilderMethodHandleEncodedValue) encodedValue).methodHandleReference);
break;
default:
throw new ExceptionWithContext("Unrecognized value type: %d", encodedValue.getValueType());
}
@ -335,6 +356,10 @@ public class DexBuilder extends DexWriter<BuilderStringReference, BuilderStringR
return internStringEncodedValue((StringEncodedValue)encodedValue);
case ValueType.TYPE:
return internTypeEncodedValue((TypeEncodedValue)encodedValue);
case ValueType.METHOD_TYPE:
return internMethodTypeEncodedValue((MethodTypeEncodedValue) encodedValue);
case ValueType.METHOD_HANDLE:
return internMethodHandleEncodedValue((MethodHandleEncodedValue) encodedValue);
default:
throw new ExceptionWithContext("Unexpected encoded value type: %d", encodedValue.getValueType());
}
@ -377,6 +402,16 @@ public class DexBuilder extends DexWriter<BuilderStringReference, BuilderStringR
return new BuilderTypeEncodedValue(typeSection.internType(type.getValue()));
}
@Nonnull private BuilderMethodTypeEncodedValue internMethodTypeEncodedValue(
@Nonnull MethodTypeEncodedValue methodType) {
return new BuilderMethodTypeEncodedValue(protoSection.internMethodProto(methodType.getValue()));
}
@Nonnull private BuilderMethodHandleEncodedValue internMethodHandleEncodedValue(
@Nonnull MethodHandleEncodedValue methodHandle) {
return new BuilderMethodHandleEncodedValue(methodHandleSection.internMethodHandle(methodHandle.getValue()));
}
protected class DexBuilderSectionProvider extends SectionProvider {
@Nonnull @Override public BuilderStringPool getStringSection() {
return new BuilderStringPool();
@ -402,6 +437,14 @@ public class DexBuilder extends DexWriter<BuilderStringReference, BuilderStringR
return new BuilderClassPool(DexBuilder.this);
}
@Nonnull @Override public BuilderCallSitePool getCallSiteSection() {
return new BuilderCallSitePool(DexBuilder.this);
}
@Nonnull @Override public BuilderMethodHandlePool getMethodHandleSection() {
return new BuilderMethodHandlePool(DexBuilder.this);
}
@Nonnull @Override public BuilderTypeListPool getTypeListSection() {
return new BuilderTypeListPool(DexBuilder.this);
}

View File

@ -0,0 +1,59 @@
/*
* 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.reference.CallSiteReference;
import org.jf.dexlib2.iface.value.ArrayEncodedValue;
import org.jf.dexlib2.writer.CallSiteSection;
import org.jf.dexlib2.writer.util.CallSiteUtil;
import javax.annotation.Nonnull;
public class CallSitePool extends BaseIndexPool<CallSiteReference>
implements CallSiteSection<CallSiteReference, ArrayEncodedValue> {
public CallSitePool(@Nonnull DexPool dexPool) {
super(dexPool);
}
public void intern(CallSiteReference callSiteReference) {
Integer prev = internedItems.put(callSiteReference, 0);
if (prev == null) {
dexPool.encodedArraySection.intern(getEncodedCallSite(callSiteReference));
}
}
@Override
public ArrayEncodedValue getEncodedCallSite(CallSiteReference callSiteReference) {
return CallSiteUtil.getEncodedCallSite(callSiteReference);
}
}

View File

@ -146,6 +146,9 @@ public class ClassPool extends BasePool<String, PoolClassDef> implements ClassSe
case ReferenceType.METHOD:
dexPool.methodSection.intern((MethodReference)reference);
break;
case ReferenceType.CALL_SITE:
dexPool.callSiteSection.intern((CallSiteReference) reference);
break;
default:
throw new ExceptionWithContext("Unrecognized reference type: %d",
instruction.getOpcode().referenceType);

View File

@ -52,10 +52,10 @@ import java.util.Set;
public class DexPool extends DexWriter<CharSequence, StringReference, CharSequence, TypeReference,
MethodProtoReference, FieldReference, MethodReference, PoolClassDef,
Annotation, Set<? extends Annotation>,
CallSiteReference, MethodHandleReference, Annotation, Set<? extends Annotation>,
TypeListPool.Key<? extends Collection<? extends CharSequence>>, Field, PoolMethod,
ArrayEncodedValue, EncodedValue, AnnotationElement, StringPool, TypePool, ProtoPool, FieldPool, MethodPool,
ClassPool, TypeListPool, AnnotationPool, AnnotationSetPool, EncodedArrayPool> {
ClassPool, CallSitePool, MethodHandlePool, TypeListPool, AnnotationPool, AnnotationSetPool, EncodedArrayPool> {
private final Markable[] sections = new Markable[] {
stringSection, typeSection, protoSection, fieldSection, methodSection, classSection, typeListSection,
@ -170,6 +170,12 @@ public class DexPool extends DexWriter<CharSequence, StringReference, CharSequen
case ValueType.TYPE:
writer.writeType(((TypeEncodedValue)encodedValue).getValue());
break;
case ValueType.METHOD_TYPE:
writer.writeMethodType(((MethodTypeEncodedValue) encodedValue).getValue());
break;
case ValueType.METHOD_HANDLE:
writer.writeMethodHandle(((MethodHandleEncodedValue) encodedValue).getValue());
break;
default:
throw new ExceptionWithContext("Unrecognized value type: %d", encodedValue.getValueType());
}
@ -205,6 +211,12 @@ public class DexPool extends DexWriter<CharSequence, StringReference, CharSequen
case ValueType.METHOD:
methodSection.intern(((MethodEncodedValue)encodedValue).getValue());
break;
case ValueType.METHOD_HANDLE:
methodHandleSection.intern(((MethodHandleEncodedValue)encodedValue).getValue());
break;
case ValueType.METHOD_TYPE:
protoSection.intern(((MethodTypeEncodedValue)encodedValue).getValue());
break;
}
}
@ -233,6 +245,14 @@ public class DexPool extends DexWriter<CharSequence, StringReference, CharSequen
return new ClassPool(DexPool.this);
}
@Nonnull @Override public CallSitePool getCallSiteSection() {
return new CallSitePool(DexPool.this);
}
@Nonnull @Override public MethodHandlePool getMethodHandleSection() {
return new MethodHandlePool(DexPool.this);
}
@Nonnull @Override public TypeListPool getTypeListSection() {
return new TypeListPool(DexPool.this);
}

View File

@ -0,0 +1,79 @@
/*
* 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.MethodHandleType;
import org.jf.dexlib2.iface.reference.FieldReference;
import org.jf.dexlib2.iface.reference.MethodHandleReference;
import org.jf.dexlib2.iface.reference.MethodReference;
import org.jf.dexlib2.writer.MethodHandleSection;
import org.jf.util.ExceptionWithContext;
import javax.annotation.Nonnull;
public class MethodHandlePool extends BaseIndexPool<MethodHandleReference>
implements MethodHandleSection<MethodHandleReference, FieldReference, MethodReference> {
public MethodHandlePool(@Nonnull DexPool dexPool) {
super(dexPool);
}
public void intern(MethodHandleReference methodHandleReference) {
Integer prev = internedItems.put(methodHandleReference, 0);
if (prev == null) {
switch (methodHandleReference.getMethodHandleType()) {
case MethodHandleType.INSTANCE_GET:
case MethodHandleType.INSTANCE_PUT:
case MethodHandleType.STATIC_GET:
case MethodHandleType.STATIC_PUT:
dexPool.fieldSection.intern((FieldReference) methodHandleReference.getMemberReference());
break;
case MethodHandleType.INVOKE_INSTANCE:
case MethodHandleType.INVOKE_STATIC:
dexPool.methodSection.intern((MethodReference) methodHandleReference.getMemberReference());
break;
default:
throw new ExceptionWithContext(
"Invalid method handle type: %d", methodHandleReference.getMethodHandleType());
}
}
}
@Override
public FieldReference getFieldReference(MethodHandleReference methodHandleReference) {
return (FieldReference) methodHandleReference.getMemberReference();
}
@Override
public MethodReference getMethodReference(MethodHandleReference methodHandleReference) {
return (MethodReference) methodHandleReference.getMemberReference();
}
}

View File

@ -0,0 +1,76 @@
/*
* 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.collect.Lists;
import org.jf.dexlib2.base.value.BaseArrayEncodedValue;
import org.jf.dexlib2.base.value.BaseMethodHandleEncodedValue;
import org.jf.dexlib2.base.value.BaseMethodTypeEncodedValue;
import org.jf.dexlib2.iface.reference.CallSiteReference;
import org.jf.dexlib2.iface.reference.MethodHandleReference;
import org.jf.dexlib2.iface.reference.MethodProtoReference;
import org.jf.dexlib2.iface.value.ArrayEncodedValue;
import org.jf.dexlib2.iface.value.EncodedValue;
import org.jf.dexlib2.immutable.value.ImmutableStringEncodedValue;
import javax.annotation.Nonnull;
import java.util.List;
public class CallSiteUtil {
public static ArrayEncodedValue getEncodedCallSite(CallSiteReference callSiteReference) {
return new BaseArrayEncodedValue() {
@Nonnull
@Override
public List<? extends EncodedValue> getValue() {
List<EncodedValue> encodedCallSite = Lists.newArrayList();
encodedCallSite.add(new BaseMethodHandleEncodedValue() {
@Nonnull
@Override
public MethodHandleReference getValue() {
return callSiteReference.getMethodHandle();
}
});
encodedCallSite.add(new ImmutableStringEncodedValue(callSiteReference.getMethodName()));
encodedCallSite.add(new BaseMethodTypeEncodedValue() {
@Nonnull
@Override
public MethodProtoReference getValue() {
return callSiteReference.getMethodProto();
}
});
encodedCallSite.addAll(callSiteReference.getExtraArguments());
return encodedCallSite;
}
};
}
}

View File

@ -0,0 +1,135 @@
/*
* 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 com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterators;
import com.google.common.collect.Lists;
import org.jf.dexlib2.*;
import org.jf.dexlib2.builder.MethodImplementationBuilder;
import org.jf.dexlib2.builder.instruction.BuilderInstruction35c;
import org.jf.dexlib2.iface.ClassDef;
import org.jf.dexlib2.iface.DexFile;
import org.jf.dexlib2.iface.Method;
import org.jf.dexlib2.iface.instruction.Instruction;
import org.jf.dexlib2.iface.instruction.formats.Instruction35c;
import org.jf.dexlib2.iface.reference.CallSiteReference;
import org.jf.dexlib2.immutable.ImmutableClassDef;
import org.jf.dexlib2.immutable.ImmutableDexFile;
import org.jf.dexlib2.immutable.ImmutableMethod;
import org.jf.dexlib2.immutable.ImmutableMethodImplementation;
import org.jf.dexlib2.immutable.instruction.ImmutableInstruction35c;
import org.jf.dexlib2.immutable.reference.ImmutableCallSiteReference;
import org.jf.dexlib2.immutable.reference.ImmutableMethodHandleReference;
import org.jf.dexlib2.immutable.reference.ImmutableMethodProtoReference;
import org.jf.dexlib2.immutable.reference.ImmutableMethodReference;
import org.jf.dexlib2.writer.builder.BuilderCallSiteReference;
import org.jf.dexlib2.writer.builder.BuilderMethod;
import org.jf.dexlib2.writer.builder.DexBuilder;
import org.jf.dexlib2.writer.io.FileDataStore;
import org.junit.Assert;
import org.junit.Test;
import java.io.File;
import java.io.IOException;
public class CallSiteTest {
@Test
public void testPoolCallSite() throws IOException {
ClassDef class1 = new ImmutableClassDef("Lcls1;", AccessFlags.PUBLIC.getValue(), "Ljava/lang/Object;", null, null,
null, null,
Lists.<Method>newArrayList(
new ImmutableMethod("Lcls1", "method1",
ImmutableList.of(), "V", AccessFlags.PUBLIC.getValue(), null,
new ImmutableMethodImplementation(10, ImmutableList.of(
new ImmutableInstruction35c(Opcode.INVOKE_CUSTOM, 0, 0, 0, 0, 0, 0,
new ImmutableCallSiteReference("call_site_1",
new ImmutableMethodHandleReference(MethodHandleType.INVOKE_STATIC,
new ImmutableMethodReference("Lcls1", "loader",
ImmutableList.of("Ljava/lang/invoke/Lookup;",
"Ljava/lang/String;",
"Ljava/lang/invoke/MethodType;"),
"Ljava/lang/invoke/CallSite;")),
"someMethod", new ImmutableMethodProtoReference(ImmutableList.of(), "V"), ImmutableList.of()))
), null, null))));
File tempFile = File.createTempFile("dex", ".dex");
DexFileFactory.writeDexFile(tempFile.getPath(),
new ImmutableDexFile(Opcodes.forArtVersion(111), ImmutableList.of(class1)));
verifyDexFile(DexFileFactory.loadDexFile(tempFile, Opcodes.forArtVersion(111)));
}
@Test
public void testBuilderCallSite() throws IOException {
DexBuilder dexBuilder = new DexBuilder(Opcodes.forArtVersion(111));
BuilderCallSiteReference callSite = dexBuilder.internCallSite(new ImmutableCallSiteReference("call_site_1",
new ImmutableMethodHandleReference(
MethodHandleType.INVOKE_STATIC,
new ImmutableMethodReference("Lcls1", "loader", ImmutableList.of("Ljava/lang/invoke/Lookup;",
"Ljava/lang/String;",
"Ljava/lang/invoke/MethodType;"),
"Ljava/lang/invoke/CallSite;")),
"someMethod",
new ImmutableMethodProtoReference(ImmutableList.of(), "V"), ImmutableList.of()));
MethodImplementationBuilder methodImplementationBuilder = new MethodImplementationBuilder(10);
methodImplementationBuilder.addInstruction(new BuilderInstruction35c(Opcode.INVOKE_CUSTOM, 0, 0, 0, 0, 0, 0,
callSite));
BuilderMethod method = dexBuilder.internMethod("Lcls1", "method1", null, "V", 0, ImmutableSet.of(),
methodImplementationBuilder.getMethodImplementation());
dexBuilder.internClassDef("Lcls1;", AccessFlags.PUBLIC.getValue(), "Ljava/lang/Object;", null, null,
ImmutableSet.of(), null,
ImmutableList.of(method));
File tempFile = File.createTempFile("dex", ".dex");
dexBuilder.writeTo(new FileDataStore(tempFile));
verifyDexFile(DexFileFactory.loadDexFile(tempFile, Opcodes.forArtVersion(111)));
}
private void verifyDexFile(DexFile dexFile) {
Assert.assertEquals(1, dexFile.getClasses().size());
ClassDef cls = Lists.newArrayList(dexFile.getClasses()).get(0);
Assert.assertEquals("Lcls1;", cls.getType());
Assert.assertEquals(1, Lists.newArrayList(cls.getMethods()).size());
Method method = Iterators.getNext(cls.getMethods().iterator(), null);
Assert.assertEquals("method1", method.getName());
Assert.assertEquals(1, Lists.newArrayList(method.getImplementation().getInstructions()).size());
Instruction instruction = Lists.newArrayList(method.getImplementation().getInstructions().iterator()).get(0);
Assert.assertEquals(Opcode.INVOKE_CUSTOM, instruction.getOpcode());
Assert.assertTrue(((Instruction35c) instruction).getReference() instanceof CallSiteReference);
}
}