When making a ClassDefItem from scratch, sort the static field initializers appropriately

git-svn-id: https://smali.googlecode.com/svn/trunk@404 55b6fa8a-2a1e-11de-a435-ffa8d773f76a
This commit is contained in:
JesusFreke@JesusFreke.com
2009-08-23 03:41:27 +00:00
parent f49271eb8f
commit b90597bd9b
2 changed files with 159 additions and 4 deletions

View File

@ -31,6 +31,9 @@ package org.jf.dexlib;
import org.jf.dexlib.Util.Input; import org.jf.dexlib.Util.Input;
import org.jf.dexlib.Util.AnnotatedOutput; import org.jf.dexlib.Util.AnnotatedOutput;
import org.jf.dexlib.Util.AccessFlags; import org.jf.dexlib.Util.AccessFlags;
import org.jf.dexlib.Util.TypeUtils;
import org.jf.dexlib.EncodedValue.EncodedValue;
import org.jf.dexlib.EncodedValue.ArrayEncodedSubValue;
import java.util.*; import java.util.*;
@ -62,7 +65,11 @@ public class ClassDefItem extends Item<ClassDefItem> {
* @param sourceFile The main source file that this class is defined in, or null if not available * @param sourceFile The main source file that this class is defined in, or null if not available
* @param annotations The annotations for this class and its fields, methods and method parameters, or null if none * @param annotations The annotations for this class and its fields, methods and method parameters, or null if none
* @param classData The <code>ClassDataItem</code> containing the method and field definitions for this class * @param classData The <code>ClassDataItem</code> containing the method and field definitions for this class
* @param staticFieldInitializers The initial values for this class's static fields, or null if none * @param staticFieldInitializers The initial values for this class's static fields, or null if none. The initial
* values should be in the same order as the static fields in the <code>ClassDataItem</code>. It can contain
* fewer items than static fields, in which case the remaining static fields will be initialized with a default
* value of null/0. The initial value for any fields that don't specifically have a value can be either the
* type-appropriate null/0 encoded value, or null.
*/ */
private ClassDefItem(DexFile dexFile, TypeIdItem classType, int accessFlags, TypeIdItem superType, private ClassDefItem(DexFile dexFile, TypeIdItem classType, int accessFlags, TypeIdItem superType,
TypeListItem implementedInterfaces, StringIdItem sourceFile, TypeListItem implementedInterfaces, StringIdItem sourceFile,
@ -97,16 +104,28 @@ public class ClassDefItem extends Item<ClassDefItem> {
* @param sourceFile The main source file that this class is defined in, or null if not available * @param sourceFile The main source file that this class is defined in, or null if not available
* @param annotations The annotations for this class and its fields, methods and method parameters, or null if none * @param annotations The annotations for this class and its fields, methods and method parameters, or null if none
* @param classData The <code>ClassDataItem</code> containing the method and field definitions for this class * @param classData The <code>ClassDataItem</code> containing the method and field definitions for this class
* @param staticFieldInitializers The initial values for this class's static fields, or null if none * @param staticFieldInitializers The initial values for this class's static fields, or null if none. The initial
* values should be in the same order as the fields in the <code>staticFields</code. parameter It can contain
* fewer items than static fields, in which case the remaining static fields will be initialized with a default
* value of null/0. The initial value for any fields that don't specifically have a value can be either the
* type-appropriate null/0 encoded value, or null.
* @param staticFields The static fields that correspond to the initial values in
* <code>staticFieldInitializers</code>. The static fields are needed in order to sort the initial values correctly
* @return a <code>ClassDefItem</code> for the given values, and that has been interned into the given * @return a <code>ClassDefItem</code> for the given values, and that has been interned into the given
* <code>DexFile</code> * <code>DexFile</code>
*/ */
public static ClassDefItem getInternedClassDefItem(DexFile dexFile, TypeIdItem classType, int accessFlags, public static ClassDefItem getInternedClassDefItem(DexFile dexFile, TypeIdItem classType, int accessFlags,
TypeIdItem superType, TypeListItem implementedInterfaces, StringIdItem sourceFile, TypeIdItem superType, TypeListItem implementedInterfaces, StringIdItem sourceFile,
AnnotationDirectoryItem annotations, ClassDataItem classData, AnnotationDirectoryItem annotations, ClassDataItem classData,
EncodedArrayItem staticFieldInitializers) { EncodedValue[] staticFieldInitializers, ClassDataItem.EncodedField[] staticFields) {
EncodedArrayItem encodedArrayItem = null;
if(!dexFile.getInplace() && staticFieldInitializers != null) {
encodedArrayItem = makeStaticFieldInitializersItem(dexFile, staticFieldInitializers,
staticFields);
}
ClassDefItem classDefItem = new ClassDefItem(dexFile, classType, accessFlags, superType, implementedInterfaces, ClassDefItem classDefItem = new ClassDefItem(dexFile, classType, accessFlags, superType, implementedInterfaces,
sourceFile, annotations, classData, staticFieldInitializers); sourceFile, annotations, classData, encodedArrayItem);
return dexFile.ClassDefsSection.intern(classDefItem); return dexFile.ClassDefsSection.intern(classDefItem);
} }
@ -286,6 +305,81 @@ public class ClassDefItem extends Item<ClassDefItem> {
unplacedClassDefsByType.remove(classDefItem.classType); unplacedClassDefsByType.remove(classDefItem.classType);
} }
} }
}
/**
* A helper method to sort the static field initializers and populate the default values as needed
* @param dexFile the <code>DexFile</code>
* @param staticFieldInitializers the initial values
* @param fields the fields that correspond to each initial value in <code>staticFieldInitializers</code>
* @return an interned EncodedArrayItem containing the static field initializers
*/
private static EncodedArrayItem makeStaticFieldInitializersItem(DexFile dexFile,
EncodedValue[] staticFieldInitializers,
ClassDataItem.EncodedField[] fields) {
class FieldAndValue {
public final EncodedValue value;
public final ClassDataItem.EncodedField field;
public FieldAndValue(ClassDataItem.EncodedField field, EncodedValue value) {
this.field = field;
this.value = value;
}
}
if (staticFieldInitializers == null || staticFieldInitializers.length == 0) {
return null;
}
int len = fields.length;
FieldAndValue[] fieldAndValues = new FieldAndValue[len];
for (int i=0; i<len; i++) {
EncodedValue encodedValue = null;
if (i < staticFieldInitializers.length) {
encodedValue = staticFieldInitializers[i];
}
ClassDataItem.EncodedField encodedField = fields[i];
fieldAndValues[i] = new FieldAndValue(encodedField, encodedValue);
}
Arrays.sort(fieldAndValues, new Comparator<FieldAndValue>() {
public int compare(FieldAndValue a, FieldAndValue b) {
return a.field.compareTo(b.field);
}
});
int lastIndex = -1;
for (int i=0; i<len; i++) {
FieldAndValue fav = fieldAndValues[i];
if (fav.value != null &&
(fav.value.compareTo(TypeUtils.makeDefaultValueForType(dexFile,
fav.field.field.getFieldType().getTypeDescriptor())) != 0)) {
lastIndex = i;
}
}
//we don't have any non-null/non-default values, so we don't need to create an EncodedArrayItem
if (lastIndex == -1) {
return null;
}
EncodedValue[] values = new EncodedValue[lastIndex+1];
for (int i=0; i<=lastIndex; i++) {
FieldAndValue fav = fieldAndValues[i];
EncodedValue encodedValue = fav.value;
if (encodedValue == null) {
encodedValue = TypeUtils.makeDefaultValueForType(dexFile,
fav.field.field.getFieldType().getTypeDescriptor());
}
values[i] = encodedValue;
}
ArrayEncodedSubValue encodedArrayValue = new ArrayEncodedSubValue(values);
return EncodedArrayItem.getInternedEncodedArrayItem(dexFile, encodedArrayValue);
} }
} }

View File

@ -0,0 +1,61 @@
/*
* [The "BSD licence"]
* Copyright (c) 2009 Ben Gruver
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.dexlib.Util;
import org.jf.dexlib.DexFile;
import org.jf.dexlib.EncodedValue.*;
public class TypeUtils
{
public static EncodedValue makeDefaultValueForType(DexFile dexFile, String type) {
EncodedValue subField;
switch (type.charAt(0)) {
case 'Z':
return BooleanEncodedValue.FalseValue;
case 'B':
return new ByteEncodedValue((byte)0);
case 'S':
return new ShortEncodedValue((short)0);
case 'C':
return new CharEncodedValue((char)0);
case 'I':
return new IntEncodedValue(0);
case 'J':
return new LongEncodedValue(0);
case 'F':
return new FloatEncodedValue(0);
case 'D':
return new DoubleEncodedValue(0);
case 'L':
case '[':
return NullEncodedValue.NullValue;
}
return null;
}
}