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.AnnotatedOutput;
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.*;
@ -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 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 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,
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 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 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
* <code>DexFile</code>
*/
public static ClassDefItem getInternedClassDefItem(DexFile dexFile, TypeIdItem classType, int accessFlags,
TypeIdItem superType, TypeListItem implementedInterfaces, StringIdItem sourceFile,
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,
sourceFile, annotations, classData, staticFieldInitializers);
sourceFile, annotations, classData, encodedArrayItem);
return dexFile.ClassDefsSection.intern(classDefItem);
}
@ -286,6 +305,81 @@ public class ClassDefItem extends Item<ClassDefItem> {
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;
}
}