FileDocCategorySizeDatePackage
CfTranslator.javaAPI DocAndroid 1.5 API14674Wed May 06 22:41:02 BST 2009com.android.dx.dex.cf

CfTranslator

public class CfTranslator extends Object
Static method that turns byte[]s containing Java classfiles into {@link ClassDefItem} instances.

Fields Summary
private static final boolean
DEBUG
set to true to enable development-time debugging code
Constructors Summary
private CfTranslator()
This class is uninstantiable.


             
      
        // This space intentionally left blank.
    
Methods Summary
private static com.android.dx.rop.cst.TypedConstantcoerceConstant(com.android.dx.rop.cst.TypedConstant constant, com.android.dx.rop.type.Type type)
Helper for {@link #processFields}, which translates constants into more specific types if necessary.

param
constant non-null; the constant in question
param
type non-null; the desired type

        Type constantType = constant.getType();

        if (constantType.equals(type)) {
            return constant;
        }

        switch (type.getBasicType()) {
            case Type.BT_BOOLEAN: {
                return CstBoolean.make(((CstInteger) constant).getValue());
            }
            case Type.BT_BYTE: {
                return CstByte.make(((CstInteger) constant).getValue());
            }
            case Type.BT_CHAR: {
                return CstChar.make(((CstInteger) constant).getValue());
            }
            case Type.BT_SHORT: {
                return CstShort.make(((CstInteger) constant).getValue());
            }
            default: {
                throw new UnsupportedOperationException("can't coerce " +
                        constant + " to " + type);
            }
        }
    
private static voidprocessFields(com.android.dx.cf.direct.DirectClassFile cf, com.android.dx.dex.file.ClassDefItem out)
Processes the fields of the given class.

param
cf non-null; class being translated
param
out non-null; output class

        CstType thisClass = cf.getThisClass();
        FieldList fields = cf.getFields();
        int sz = fields.size();

        for (int i = 0; i < sz; i++) {
            Field one = fields.get(i);
            try {
                CstFieldRef field = new CstFieldRef(thisClass, one.getNat());
                int accessFlags = one.getAccessFlags();

                if (AccessFlags.isStatic(accessFlags)) {
                    TypedConstant constVal = one.getConstantValue();
                    EncodedField fi = new EncodedField(field, accessFlags);
                    if (constVal != null) {
                        constVal = coerceConstant(constVal, field.getType());
                    }
                    out.addStaticField(fi, constVal);
                } else {
                    EncodedField fi = new EncodedField(field, accessFlags);
                    out.addInstanceField(fi);
                }

                Annotations annotations = 
                    AttributeTranslator.getAnnotations(one.getAttributes());
                if (annotations.size() != 0) {
                    out.addFieldAnnotations(field, annotations);
                }
            } catch (RuntimeException ex) {
                String msg = "...while processing " + one.getName().toHuman() +
                    " " + one.getDescriptor().toHuman();
                throw ExceptionWithContext.withContext(ex, msg);
            }
        }
    
private static voidprocessMethods(com.android.dx.cf.direct.DirectClassFile cf, CfOptions args, com.android.dx.dex.file.ClassDefItem out)
Processes the methods of the given class.

param
cf non-null; class being translated
param
args non-null; command-line args
param
out non-null; output class

        CstType thisClass = cf.getThisClass();
        MethodList methods = cf.getMethods();
        int sz = methods.size();

        for (int i = 0; i < sz; i++) {
            Method one = methods.get(i);
            try {
                CstMethodRef meth = new CstMethodRef(thisClass, one.getNat());
                int accessFlags = one.getAccessFlags();
                boolean isStatic = AccessFlags.isStatic(accessFlags);
                boolean isPrivate = AccessFlags.isPrivate(accessFlags);
                boolean isNative = AccessFlags.isNative(accessFlags);
                boolean isAbstract = AccessFlags.isAbstract(accessFlags);
                boolean isConstructor = meth.isInstanceInit() ||
                    meth.isClassInit();
                DalvCode code;

                if (isNative || isAbstract) {
                    // There's no code for native or abstract methods.
                    code = null;
                } else {
                    ConcreteMethod concrete =
                        new ConcreteMethod(one, cf,
                                (args.positionInfo != PositionList.NONE),
                                args.localInfo);

                    TranslationAdvice advice;

                    advice = DexTranslationAdvice.THE_ONE;

                    RopMethod rmeth = Ropper.convert(concrete, advice);
                    RopMethod nonOptRmeth = null;
                    int paramSize;

                    paramSize = meth.getParameterWordCount(isStatic);
    
                    String canonicalName 
                            = thisClass.getClassType().getDescriptor()
                                + "." + one.getName().getString();

                    if (args.optimize &&
                            OptimizerOptions.shouldOptimize(canonicalName)) {
                        if (DEBUG) {
                            System.err.println("Optimizing " + canonicalName);
                        }

                        nonOptRmeth = rmeth;
                        rmeth = Optimizer.optimize(rmeth,
                                paramSize, isStatic, args.localInfo, advice);

                        if (DEBUG) {
                            OptimizerOptions.compareOptimizerStep(nonOptRmeth,
                                    paramSize, isStatic, args, advice, rmeth);
                        }

                        if (args.statistics) {
                            CodeStatistics.updateRopStatistics(
                                    nonOptRmeth, rmeth);
                        }
                    }

                    LocalVariableInfo locals = null;

                    if (args.localInfo) {
                        locals = LocalVariableExtractor.extract(rmeth);
                    }

                    code = RopTranslator.translate(rmeth, args.positionInfo,
                            locals, paramSize);

                    if (args.statistics && nonOptRmeth != null) {
                        updateDexStatistics(args, rmeth, nonOptRmeth, locals,
                                paramSize, concrete.getCode().size());
                    }
                }

                // Preserve the synchronized flag as its "declared" variant...
                if (AccessFlags.isSynchronized(accessFlags)) {
                    accessFlags |= AccessFlags.ACC_DECLARED_SYNCHRONIZED;

                    /*
                     * ...but only native methods are actually allowed to be
                     * synchronized.
                     */
                    if (!isNative) {
                        accessFlags &= ~AccessFlags.ACC_SYNCHRONIZED;
                    }
                }
                
                if (isConstructor) {
                    accessFlags |= AccessFlags.ACC_CONSTRUCTOR;
                }

                TypeList exceptions = AttributeTranslator.getExceptions(one);
                EncodedMethod mi =
                    new EncodedMethod(meth, accessFlags, code, exceptions);

                if (meth.isInstanceInit() || meth.isClassInit() ||
                    isStatic || isPrivate) {
                    out.addDirectMethod(mi);
                } else {
                    out.addVirtualMethod(mi);
                }

                Annotations annotations = 
                    AttributeTranslator.getMethodAnnotations(one);
                if (annotations.size() != 0) {
                    out.addMethodAnnotations(meth, annotations);
                }

                AnnotationsList list = 
                    AttributeTranslator.getParameterAnnotations(one);
                if (list.size() != 0) {
                    out.addParameterAnnotations(meth, list);
                }
            } catch (RuntimeException ex) {
                String msg = "...while processing " + one.getName().toHuman() +
                    " " + one.getDescriptor().toHuman();
                throw ExceptionWithContext.withContext(ex, msg);
            }
        }
    
public static com.android.dx.dex.file.ClassDefItemtranslate(java.lang.String filePath, byte[] bytes, CfOptions args)
Takes a byte[], interprets it as a Java classfile, and translates it into a {@link ClassDefItem}.

param
filePath non-null; the file path for the class, excluding any base directory specification
param
bytes non-null; contents of the file
param
args command-line arguments
return
non-null; the translated class

        try {
            return translate0(filePath, bytes, args);
        } catch (RuntimeException ex) {
            String msg = "...while processing " + filePath;
            throw ExceptionWithContext.withContext(ex, msg);
        }
    
private static com.android.dx.dex.file.ClassDefItemtranslate0(java.lang.String filePath, byte[] bytes, CfOptions args)
Performs the main act of translation. This method is separated from {@link #translate} just to keep things a bit simpler in terms of exception handling.

param
filePath non-null; the file path for the class, excluding any base directory specification
param
bytes non-null; contents of the file
param
args command-line arguments
return
non-null; the translated class

        DirectClassFile cf =
            new DirectClassFile(bytes, filePath, args.strictNameCheck);

        cf.setAttributeFactory(StdAttributeFactory.THE_ONE);
        cf.getMagic();

        OptimizerOptions.loadOptimizeLists(args.optimizeListFile,
                args.dontOptimizeListFile);

        // Build up a class to output.

        CstType thisClass = cf.getThisClass();
        int classAccessFlags = cf.getAccessFlags() & ~AccessFlags.ACC_SUPER;
        CstUtf8 sourceFile = (args.positionInfo == PositionList.NONE) ? null :
            cf.getSourceFile();
        ClassDefItem out =
            new ClassDefItem(thisClass, classAccessFlags,
                    cf.getSuperclass(), cf.getInterfaces(), sourceFile);

        Annotations classAnnotations =
            AttributeTranslator.getClassAnnotations(cf, args);
        if (classAnnotations.size() != 0) {
            out.setClassAnnotations(classAnnotations);
        }
        
        processFields(cf, out);
        processMethods(cf, args, out);

        return out;
    
private static voidupdateDexStatistics(CfOptions args, com.android.dx.rop.code.RopMethod optRmeth, com.android.dx.rop.code.RopMethod nonOptRmeth, com.android.dx.rop.code.LocalVariableInfo locals, int paramSize, int originalByteCount)
Helper that updates the dex statistics.

        /*
         * Run rop->dex again on optimized vs. non-optimized method to
         * collect statistics. We have to totally convert both ways,
         * since converting the "real" method getting added to the
         * file would corrupt it (by messing with its constant pool
         * indices).
         */

        DalvCode optCode = RopTranslator.translate(optRmeth,
                args.positionInfo, locals, paramSize);
        DalvCode nonOptCode = RopTranslator.translate(nonOptRmeth,
                args.positionInfo, locals, paramSize);

        /*
         * Fake out the indices, so code.getInsns() can work well enough
         * for the current purpose.
         */

        DalvCode.AssignIndicesCallback callback = 
            new DalvCode.AssignIndicesCallback() {
                public int getIndex(Constant cst) {
                    // Everything is at index 0!
                    return 0;
                }
            };

        optCode.assignIndices(callback);
        nonOptCode.assignIndices(callback);

        CodeStatistics.updateDexStatistics(nonOptCode, optCode);
        CodeStatistics.updateOriginalByteCount(originalByteCount);