1f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
2f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Copyright (C) 2007 The Android Open Source Project
3f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
4f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
5f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * you may not use this file except in compliance with the License.
6f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * You may obtain a copy of the License at
7f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
8f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
9f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
10f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
11f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
12f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * See the License for the specific language governing permissions and
14f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * limitations under the License.
15f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
16f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
17f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectpackage com.android.dx.dex.cf;
18f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
19f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.cf.code.ConcreteMethod;
20f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.cf.code.Ropper;
21f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.cf.direct.DirectClassFile;
22f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.cf.direct.StdAttributeFactory;
23f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.cf.iface.Field;
24f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.cf.iface.FieldList;
25f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.cf.iface.Method;
26f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.cf.iface.MethodList;
273dfda9ad1964510e4a7948a240b30cd710e86341Dan Bornsteinimport com.android.dx.dex.DexOptions;
28f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.dex.code.DalvCode;
29f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.dex.code.PositionList;
30f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.dex.code.RopTranslator;
31f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.dex.file.ClassDefItem;
32f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.dex.file.EncodedField;
33f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.dex.file.EncodedMethod;
34f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.annotation.Annotations;
35f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.annotation.AnnotationsList;
36f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.code.AccessFlags;
37f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.code.LocalVariableExtractor;
38f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.code.LocalVariableInfo;
39f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.code.RopMethod;
40f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.code.DexTranslationAdvice;
41f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.code.TranslationAdvice;
42f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.cst.Constant;
43f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.cst.CstBoolean;
44f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.cst.CstByte;
45f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.cst.CstChar;
46f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.cst.CstFieldRef;
47f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.cst.CstInteger;
48f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.cst.CstMethodRef;
49f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.cst.CstShort;
50333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilsonimport com.android.dx.rop.cst.CstString;
51f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.cst.CstType;
52f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.cst.TypedConstant;
53f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.type.Type;
54f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.type.TypeList;
55f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.ssa.Optimizer;
56f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.util.ExceptionWithContext;
57f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
58f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/**
5999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * Static method that turns {@code byte[]}s containing Java
60f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * classfiles into {@link ClassDefItem} instances.
61f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
62f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectpublic class CfTranslator {
6399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    /** set to {@code true} to enable development-time debugging code */
64f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static final boolean DEBUG = false;
65f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
66f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
67f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * This class is uninstantiable.
68f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
69f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private CfTranslator() {
70f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // This space intentionally left blank.
71f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
72f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
73f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
7499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * Takes a {@code byte[]}, interprets it as a Java classfile, and
75f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * translates it into a {@link ClassDefItem}.
76f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
7799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param filePath {@code non-null;} the file path for the class,
78f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * excluding any base directory specification
7999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param bytes {@code non-null;} contents of the file
803dfda9ad1964510e4a7948a240b30cd710e86341Dan Bornstein     * @param cfOptions options for class translation
813dfda9ad1964510e4a7948a240b30cd710e86341Dan Bornstein     * @param dexOptions options for dex output
8299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @return {@code non-null;} the translated class
83f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
84f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public static ClassDefItem translate(String filePath, byte[] bytes,
853dfda9ad1964510e4a7948a240b30cd710e86341Dan Bornstein            CfOptions cfOptions, DexOptions dexOptions) {
86f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        try {
873dfda9ad1964510e4a7948a240b30cd710e86341Dan Bornstein            return translate0(filePath, bytes, cfOptions, dexOptions);
88f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } catch (RuntimeException ex) {
89f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            String msg = "...while processing " + filePath;
90f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throw ExceptionWithContext.withContext(ex, msg);
91f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
92f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
93f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
94f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
95f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Performs the main act of translation. This method is separated
96f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * from {@link #translate} just to keep things a bit simpler in
97f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * terms of exception handling.
98f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
9999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param filePath {@code non-null;} the file path for the class,
100f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * excluding any base directory specification
10199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param bytes {@code non-null;} contents of the file
1023dfda9ad1964510e4a7948a240b30cd710e86341Dan Bornstein     * @param cfOptions options for class translation
1033dfda9ad1964510e4a7948a240b30cd710e86341Dan Bornstein     * @param dexOptions options for dex output
10499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @return {@code non-null;} the translated class
105f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
106f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static ClassDefItem translate0(String filePath, byte[] bytes,
1073dfda9ad1964510e4a7948a240b30cd710e86341Dan Bornstein            CfOptions cfOptions, DexOptions dexOptions) {
108f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        DirectClassFile cf =
1093dfda9ad1964510e4a7948a240b30cd710e86341Dan Bornstein            new DirectClassFile(bytes, filePath, cfOptions.strictNameCheck);
110f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
111f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        cf.setAttributeFactory(StdAttributeFactory.THE_ONE);
112f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        cf.getMagic();
113f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1143dfda9ad1964510e4a7948a240b30cd710e86341Dan Bornstein        OptimizerOptions.loadOptimizeLists(cfOptions.optimizeListFile,
1153dfda9ad1964510e4a7948a240b30cd710e86341Dan Bornstein                cfOptions.dontOptimizeListFile);
116f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
117f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // Build up a class to output.
118f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
119f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        CstType thisClass = cf.getThisClass();
120f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int classAccessFlags = cf.getAccessFlags() & ~AccessFlags.ACC_SUPER;
121333201833d506a3accdeac6ceb7caba8d4b95797Jesse Wilson        CstString sourceFile = (cfOptions.positionInfo == PositionList.NONE) ? null :
122f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            cf.getSourceFile();
123f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        ClassDefItem out =
124f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            new ClassDefItem(thisClass, classAccessFlags,
125f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    cf.getSuperclass(), cf.getInterfaces(), sourceFile);
126f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
127f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        Annotations classAnnotations =
1283dfda9ad1964510e4a7948a240b30cd710e86341Dan Bornstein            AttributeTranslator.getClassAnnotations(cf, cfOptions);
129f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (classAnnotations.size() != 0) {
130f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            out.setClassAnnotations(classAnnotations);
131f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
132de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro
133f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        processFields(cf, out);
1343dfda9ad1964510e4a7948a240b30cd710e86341Dan Bornstein        processMethods(cf, cfOptions, dexOptions, out);
135f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
136f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return out;
137f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
138f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
139f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
140f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Processes the fields of the given class.
141f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
14299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param cf {@code non-null;} class being translated
14399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param out {@code non-null;} output class
144f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
145f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static void processFields(DirectClassFile cf, ClassDefItem out) {
146f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        CstType thisClass = cf.getThisClass();
147f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        FieldList fields = cf.getFields();
148f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int sz = fields.size();
149f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
150f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (int i = 0; i < sz; i++) {
151f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            Field one = fields.get(i);
152f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            try {
153f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                CstFieldRef field = new CstFieldRef(thisClass, one.getNat());
154f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                int accessFlags = one.getAccessFlags();
155f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
156f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                if (AccessFlags.isStatic(accessFlags)) {
157f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    TypedConstant constVal = one.getConstantValue();
158f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    EncodedField fi = new EncodedField(field, accessFlags);
159f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    if (constVal != null) {
160f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        constVal = coerceConstant(constVal, field.getType());
161f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    }
162f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    out.addStaticField(fi, constVal);
163f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                } else {
164f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    EncodedField fi = new EncodedField(field, accessFlags);
165f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    out.addInstanceField(fi);
166f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
167f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
168de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro                Annotations annotations =
169f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    AttributeTranslator.getAnnotations(one.getAttributes());
170f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                if (annotations.size() != 0) {
171f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    out.addFieldAnnotations(field, annotations);
172f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
173f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            } catch (RuntimeException ex) {
174f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                String msg = "...while processing " + one.getName().toHuman() +
175f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    " " + one.getDescriptor().toHuman();
176f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                throw ExceptionWithContext.withContext(ex, msg);
177f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
178f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
179f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
180f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
181f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
182f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Helper for {@link #processFields}, which translates constants into
183f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * more specific types if necessary.
184de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro     *
18599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param constant {@code non-null;} the constant in question
18699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param type {@code non-null;} the desired type
187f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
188f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static TypedConstant coerceConstant(TypedConstant constant,
189f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            Type type) {
190f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        Type constantType = constant.getType();
191f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
192f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (constantType.equals(type)) {
193f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return constant;
194f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
195f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
196f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        switch (type.getBasicType()) {
197f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            case Type.BT_BOOLEAN: {
198f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                return CstBoolean.make(((CstInteger) constant).getValue());
199f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
200f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            case Type.BT_BYTE: {
201f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                return CstByte.make(((CstInteger) constant).getValue());
202f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
203f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            case Type.BT_CHAR: {
204f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                return CstChar.make(((CstInteger) constant).getValue());
205f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
206f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            case Type.BT_SHORT: {
207f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                return CstShort.make(((CstInteger) constant).getValue());
208f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
209f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            default: {
210f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                throw new UnsupportedOperationException("can't coerce " +
211f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        constant + " to " + type);
212f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
213f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
214f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
215f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
216f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
217f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Processes the methods of the given class.
218f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
21999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param cf {@code non-null;} class being translated
2203dfda9ad1964510e4a7948a240b30cd710e86341Dan Bornstein     * @param cfOptions {@code non-null;} options for class translation
2213dfda9ad1964510e4a7948a240b30cd710e86341Dan Bornstein     * @param dexOptions {@code non-null;} options for dex output
22299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param out {@code non-null;} output class
223f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
2243dfda9ad1964510e4a7948a240b30cd710e86341Dan Bornstein    private static void processMethods(DirectClassFile cf, CfOptions cfOptions,
2253dfda9ad1964510e4a7948a240b30cd710e86341Dan Bornstein            DexOptions dexOptions, ClassDefItem out) {
226f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        CstType thisClass = cf.getThisClass();
227f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        MethodList methods = cf.getMethods();
228f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int sz = methods.size();
229f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
230f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (int i = 0; i < sz; i++) {
231f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            Method one = methods.get(i);
232f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            try {
233f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                CstMethodRef meth = new CstMethodRef(thisClass, one.getNat());
234f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                int accessFlags = one.getAccessFlags();
235f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                boolean isStatic = AccessFlags.isStatic(accessFlags);
236f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                boolean isPrivate = AccessFlags.isPrivate(accessFlags);
237f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                boolean isNative = AccessFlags.isNative(accessFlags);
238f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                boolean isAbstract = AccessFlags.isAbstract(accessFlags);
239f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                boolean isConstructor = meth.isInstanceInit() ||
240f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    meth.isClassInit();
241f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                DalvCode code;
242f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
243f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                if (isNative || isAbstract) {
244f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    // There's no code for native or abstract methods.
245f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    code = null;
246f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                } else {
247f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    ConcreteMethod concrete =
248f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        new ConcreteMethod(one, cf,
2493dfda9ad1964510e4a7948a240b30cd710e86341Dan Bornstein                                (cfOptions.positionInfo != PositionList.NONE),
2503dfda9ad1964510e4a7948a240b30cd710e86341Dan Bornstein                                cfOptions.localInfo);
251f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
252f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    TranslationAdvice advice;
253f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
254f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    advice = DexTranslationAdvice.THE_ONE;
255f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
256f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    RopMethod rmeth = Ropper.convert(concrete, advice);
257f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    RopMethod nonOptRmeth = null;
258f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    int paramSize;
259f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
260f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    paramSize = meth.getParameterWordCount(isStatic);
261de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro
262de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro                    String canonicalName
263f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                            = thisClass.getClassType().getDescriptor()
264f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                + "." + one.getName().getString();
265f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2663dfda9ad1964510e4a7948a240b30cd710e86341Dan Bornstein                    if (cfOptions.optimize &&
267f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                            OptimizerOptions.shouldOptimize(canonicalName)) {
268f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        if (DEBUG) {
269f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                            System.err.println("Optimizing " + canonicalName);
270f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        }
271f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
272f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        nonOptRmeth = rmeth;
273f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        rmeth = Optimizer.optimize(rmeth,
2743dfda9ad1964510e4a7948a240b30cd710e86341Dan Bornstein                                paramSize, isStatic, cfOptions.localInfo, advice);
275f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
276f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        if (DEBUG) {
277f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                            OptimizerOptions.compareOptimizerStep(nonOptRmeth,
2783dfda9ad1964510e4a7948a240b30cd710e86341Dan Bornstein                                    paramSize, isStatic, cfOptions, advice, rmeth);
279f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        }
280f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2813dfda9ad1964510e4a7948a240b30cd710e86341Dan Bornstein                        if (cfOptions.statistics) {
282f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                            CodeStatistics.updateRopStatistics(
283f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                    nonOptRmeth, rmeth);
284f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        }
285f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    }
286f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
287f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    LocalVariableInfo locals = null;
288f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2893dfda9ad1964510e4a7948a240b30cd710e86341Dan Bornstein                    if (cfOptions.localInfo) {
290f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        locals = LocalVariableExtractor.extract(rmeth);
291f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    }
292f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2933dfda9ad1964510e4a7948a240b30cd710e86341Dan Bornstein                    code = RopTranslator.translate(rmeth, cfOptions.positionInfo,
2943dfda9ad1964510e4a7948a240b30cd710e86341Dan Bornstein                            locals, paramSize, dexOptions);
295f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2963dfda9ad1964510e4a7948a240b30cd710e86341Dan Bornstein                    if (cfOptions.statistics && nonOptRmeth != null) {
2973dfda9ad1964510e4a7948a240b30cd710e86341Dan Bornstein                        updateDexStatistics(cfOptions, dexOptions, rmeth, nonOptRmeth, locals,
298f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                paramSize, concrete.getCode().size());
299f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    }
300f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
301f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
302f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                // Preserve the synchronized flag as its "declared" variant...
303f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                if (AccessFlags.isSynchronized(accessFlags)) {
304f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    accessFlags |= AccessFlags.ACC_DECLARED_SYNCHRONIZED;
305f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
306f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    /*
307f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                     * ...but only native methods are actually allowed to be
308f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                     * synchronized.
309f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                     */
310f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    if (!isNative) {
311f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        accessFlags &= ~AccessFlags.ACC_SYNCHRONIZED;
312f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    }
313f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
314de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro
315f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                if (isConstructor) {
316f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    accessFlags |= AccessFlags.ACC_CONSTRUCTOR;
317f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
318f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
319f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                TypeList exceptions = AttributeTranslator.getExceptions(one);
320f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                EncodedMethod mi =
321f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    new EncodedMethod(meth, accessFlags, code, exceptions);
322f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
323f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                if (meth.isInstanceInit() || meth.isClassInit() ||
324f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    isStatic || isPrivate) {
325f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    out.addDirectMethod(mi);
326f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                } else {
327f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    out.addVirtualMethod(mi);
328f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
329f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
330de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro                Annotations annotations =
331f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    AttributeTranslator.getMethodAnnotations(one);
332f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                if (annotations.size() != 0) {
333f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    out.addMethodAnnotations(meth, annotations);
334f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
335f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
336de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro                AnnotationsList list =
337f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    AttributeTranslator.getParameterAnnotations(one);
338f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                if (list.size() != 0) {
339f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    out.addParameterAnnotations(meth, list);
340f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
341f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            } catch (RuntimeException ex) {
342f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                String msg = "...while processing " + one.getName().toHuman() +
343f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    " " + one.getDescriptor().toHuman();
344f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                throw ExceptionWithContext.withContext(ex, msg);
345f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
346f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
347f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
348f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
349f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
350f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Helper that updates the dex statistics.
351f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
3523dfda9ad1964510e4a7948a240b30cd710e86341Dan Bornstein    private static void updateDexStatistics(CfOptions cfOptions, DexOptions dexOptions,
353f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            RopMethod optRmeth, RopMethod nonOptRmeth,
354f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            LocalVariableInfo locals, int paramSize, int originalByteCount) {
355f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /*
356f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Run rop->dex again on optimized vs. non-optimized method to
357f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * collect statistics. We have to totally convert both ways,
358f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * since converting the "real" method getting added to the
359f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * file would corrupt it (by messing with its constant pool
360f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * indices).
361f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
362f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
363f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        DalvCode optCode = RopTranslator.translate(optRmeth,
3643dfda9ad1964510e4a7948a240b30cd710e86341Dan Bornstein                cfOptions.positionInfo, locals, paramSize, dexOptions);
365f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        DalvCode nonOptCode = RopTranslator.translate(nonOptRmeth,
3663dfda9ad1964510e4a7948a240b30cd710e86341Dan Bornstein                cfOptions.positionInfo, locals, paramSize, dexOptions);
367f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
368f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /*
369f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Fake out the indices, so code.getInsns() can work well enough
370f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * for the current purpose.
371f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
372f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
373de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro        DalvCode.AssignIndicesCallback callback =
374f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            new DalvCode.AssignIndicesCallback() {
375f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                public int getIndex(Constant cst) {
376f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    // Everything is at index 0!
377f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    return 0;
378f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
379f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            };
380f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
381f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        optCode.assignIndices(callback);
382f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        nonOptCode.assignIndices(callback);
383f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
384f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        CodeStatistics.updateDexStatistics(nonOptCode, optCode);
385f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        CodeStatistics.updateOriginalByteCount(originalByteCount);
386f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
387f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
388