DexMaker.java revision 90699b97998f1582a921202fb909f17f9718d177
1579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson/*
2579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Copyright (C) 2011 The Android Open Source Project
3579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson *
4579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Licensed under the Apache License, Version 2.0 (the "License");
5579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * you may not use this file except in compliance with the License.
6579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * You may obtain a copy of the License at
7579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson *
8579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson *      http://www.apache.org/licenses/LICENSE-2.0
9579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson *
10579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Unless required by applicable law or agreed to in writing, software
11579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * distributed under the License is distributed on an "AS IS" BASIS,
12579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * See the License for the specific language governing permissions and
14579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * limitations under the License.
15579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson */
16579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
17579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonpackage com.google.dexmaker;
18579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
19579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.dex.DexFormat;
20579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.dex.DexOptions;
21579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.dex.code.DalvCode;
22579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.dex.code.PositionList;
23579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.dex.code.RopTranslator;
24579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.dex.file.ClassDefItem;
25579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.dex.file.DexFile;
26579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.dex.file.EncodedField;
27579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.dex.file.EncodedMethod;
28579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.code.AccessFlags;
2990699b97998f1582a921202fb909f17f9718d177Jesse Wilsonimport static com.android.dx.rop.code.AccessFlags.ACC_CONSTRUCTOR;
30579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.code.LocalVariableInfo;
31579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.code.RopMethod;
32579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.cst.CstString;
33579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.cst.CstType;
34579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.type.StdTypeList;
35579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.io.File;
36579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.io.FileOutputStream;
37579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.io.IOException;
38579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.lang.reflect.InvocationTargetException;
3990699b97998f1582a921202fb909f17f9718d177Jesse Wilsonimport static java.lang.reflect.Modifier.PRIVATE;
4090699b97998f1582a921202fb909f17f9718d177Jesse Wilsonimport static java.lang.reflect.Modifier.STATIC;
41579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.util.LinkedHashMap;
42579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.util.Map;
43579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.util.jar.JarEntry;
44579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.util.jar.JarOutputStream;
45579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
46579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson/**
47579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Define types, fields and methods.
48579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson */
49579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonpublic final class DexGenerator {
50579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private final Map<Type<?>, TypeDeclaration> types
51579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            = new LinkedHashMap<Type<?>, TypeDeclaration>();
52579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
53579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private TypeDeclaration getTypeDeclaration(Type<?> type) {
54579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        TypeDeclaration result = types.get(type);
55579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (result == null) {
56579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            result = new TypeDeclaration(type);
57579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            types.put(type, result);
58579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
59579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return result;
60579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
61579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
6290699b97998f1582a921202fb909f17f9718d177Jesse Wilson    // TODO: describe the legal flags without referring to a non-public API AccessFlags
6390699b97998f1582a921202fb909f17f9718d177Jesse Wilson
64579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
65579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param flags any flags masked by {@link com.android.dx.rop.code.AccessFlags#CLASS_FLAGS}.
66579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
67579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void declare(Type<?> type, String sourceFile, int flags,
68579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            Type<?> supertype, Type<?>... interfaces) {
69579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        TypeDeclaration declaration = getTypeDeclaration(type);
70579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (declaration.declared) {
71579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new IllegalStateException("already declared: " + type);
72579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
73579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        declaration.declared = true;
74579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        declaration.flags = flags;
75579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        declaration.supertype = supertype;
76579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        declaration.sourceFile = sourceFile;
77579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        declaration.interfaces = new TypeList(interfaces);
78579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
79579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
80579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
81579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param flags any flags masked by {@link com.android.dx.rop.code.AccessFlags#METHOD_FLAGS}.
82579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
8390699b97998f1582a921202fb909f17f9718d177Jesse Wilson    public Code declareConstructor(MethodId<?, ?> method, int flags) {
8490699b97998f1582a921202fb909f17f9718d177Jesse Wilson        return declare(method, flags | ACC_CONSTRUCTOR);
8590699b97998f1582a921202fb909f17f9718d177Jesse Wilson    }
8690699b97998f1582a921202fb909f17f9718d177Jesse Wilson
8790699b97998f1582a921202fb909f17f9718d177Jesse Wilson    /**
8890699b97998f1582a921202fb909f17f9718d177Jesse Wilson     * @param flags any flags masked by {@link com.android.dx.rop.code.AccessFlags#METHOD_FLAGS}.
8990699b97998f1582a921202fb909f17f9718d177Jesse Wilson     */
90579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public Code declare(MethodId<?, ?> method, int flags) {
91579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        TypeDeclaration typeDeclaration = getTypeDeclaration(method.declaringType);
92579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (typeDeclaration.methods.containsKey(method)) {
93579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new IllegalStateException("already declared: " + method);
94579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
95579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        MethodDeclaration methodDeclaration = new MethodDeclaration(method, flags);
96579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        typeDeclaration.methods.put(method, methodDeclaration);
97579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return methodDeclaration.code;
98579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
99579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
100579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
101579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param flags any flags masked by {@link AccessFlags#FIELD_FLAGS}.
102579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
103579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public void declare(FieldId<?, ?> fieldId, int flags, Object staticValue) {
104579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        TypeDeclaration typeDeclaration = getTypeDeclaration(fieldId.declaringType);
105579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (typeDeclaration.fields.containsKey(fieldId)) {
106579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new IllegalStateException("already declared: " + fieldId);
107579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
108579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        FieldDeclaration fieldDeclaration = new FieldDeclaration(fieldId, flags, staticValue);
109579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        typeDeclaration.fields.put(fieldId, fieldDeclaration);
110579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
111579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
112579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
113579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Returns a .dex formatted file.
114579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
115579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public byte[] generate() {
116579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        DexOptions options = new DexOptions();
117579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        options.targetApiLevel = DexFormat.API_NO_EXTENDED_OPCODES;
118579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        DexFile outputDex = new DexFile(options);
119579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
120579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        for (TypeDeclaration typeDeclaration : types.values()) {
121579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            outputDex.add(typeDeclaration.toClassDefItem());
122579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
123579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
124579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        try {
125579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return outputDex.toDex(null, false);
126579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } catch (IOException e) {
127579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new RuntimeException(e);
128579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
129579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
130579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
131579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
132579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Loads the generated types into the current process.
133579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
134579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * <p>All parameters are optional, you may pass {@code null} and suitable
135579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * defaults will be used.
136579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
137579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * <p>If you opt to provide your own output directories, take care to
138579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * ensure that they are not world-readable, otherwise a malicious app will
139579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * be able to inject code to run.  A suitable parameter for these output
140579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * directories would be something like this:
141579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * {@code getApplicationContext().getDir("dx", Context.MODE_PRIVATE); }
142579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
143579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param parent the parent ClassLoader to be used when loading
144579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *     our generated types
145579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param dexOutputDir the destination directory wherein we will write
146579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *     emitted .dex files before they end up in the cache directory
147579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param dexOptCacheDir where optimized .dex files are to be written
148579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
149579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public ClassLoader load(ClassLoader parent, File dexOutputDir, File dexOptCacheDir)
150579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throws IOException {
151579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        byte[] dex = generate();
152579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
153579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /*
154579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * This implementation currently dumps the dex to the filesystem. It
155579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * jars the emitted .dex for the benefit of Gingerbread and earlier
156579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * devices, which can't load .dex files directly.
157579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *
158579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * TODO: load the dex from memory where supported.
159579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
160579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        File result = File.createTempFile("Generated", ".jar", dexOutputDir);
161579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        result.deleteOnExit();
162579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        JarOutputStream jarOut = new JarOutputStream(new FileOutputStream(result));
163579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        jarOut.putNextEntry(new JarEntry(DexFormat.DEX_IN_JAR_NAME));
164579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        jarOut.write(dex);
165579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        jarOut.closeEntry();
166579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        jarOut.close();
167579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        try {
168579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return (ClassLoader) Class.forName("dalvik.system.DexClassLoader")
169579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    .getConstructor(String.class, String.class, String.class, ClassLoader.class)
170579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    .newInstance(result.getPath(), dexOptCacheDir.getAbsolutePath(), null, parent);
171579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } catch (ClassNotFoundException e) {
172579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new UnsupportedOperationException("load() requires a Dalvik VM", e);
173579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } catch (InvocationTargetException e) {
174579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new RuntimeException(e.getCause());
175579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } catch (InstantiationException e) {
176579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new AssertionError();
177579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } catch (NoSuchMethodException e) {
178579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new AssertionError();
179579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } catch (IllegalAccessException e) {
180579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new AssertionError();
181579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
182579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
183579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
184579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private static class TypeDeclaration {
185579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        private final Type<?> type;
186579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
187579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /** declared state */
188579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        private boolean declared;
189579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        private int flags;
190579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        private Type<?> supertype;
191579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        private String sourceFile;
192579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        private TypeList interfaces;
193579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
194579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        private final Map<FieldId, FieldDeclaration> fields
195579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                = new LinkedHashMap<FieldId, FieldDeclaration>();
196579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        private final Map<MethodId, MethodDeclaration> methods
197579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                = new LinkedHashMap<MethodId, MethodDeclaration>();
198579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
199579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        TypeDeclaration(Type<?> type) {
200579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            this.type = type;
201579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
202579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
203579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        ClassDefItem toClassDefItem() {
204579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if (!declared) {
205579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                throw new IllegalStateException("Undeclared type " + type + " declares members: "
206579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                        + fields.keySet() + " " + methods.keySet());
207579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
208579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
209579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            DexOptions dexOptions = new DexOptions();
210579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            dexOptions.targetApiLevel = DexFormat.API_NO_EXTENDED_OPCODES;
211579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
212579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            CstType thisType = type.constant;
213579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
214579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            ClassDefItem out = new ClassDefItem(thisType, flags, supertype.constant,
215579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    interfaces.ropTypes, new CstString(sourceFile));
216579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
217579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            for (MethodDeclaration method : methods.values()) {
218579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                EncodedMethod encoded = method.toEncodedMethod(dexOptions);
219579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                if (method.isDirect()) {
220579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    out.addDirectMethod(encoded);
221579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                } else {
222579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    out.addVirtualMethod(encoded);
223579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                }
224579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
225579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            for (FieldDeclaration field : fields.values()) {
226579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                EncodedField encoded = field.toEncodedField();
227579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                if (field.isStatic()) {
228579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    out.addStaticField(encoded, Constants.getConstant(field.staticValue));
229579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                } else {
230579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    out.addInstanceField(encoded);
231579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                }
232579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
233579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
234579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return out;
235579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
236579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
237579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
238579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    static class FieldDeclaration {
239579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        final FieldId<?, ?> fieldId;
240579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        private final int accessFlags;
241579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        private final Object staticValue;
242579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
243579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        FieldDeclaration(FieldId<?, ?> fieldId, int accessFlags, Object staticValue) {
24490699b97998f1582a921202fb909f17f9718d177Jesse Wilson            if ((accessFlags & STATIC) == 0 && staticValue != null) {
245579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                throw new IllegalArgumentException("instance fields may not have a value");
246579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
247579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            this.fieldId = fieldId;
248579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            this.accessFlags = accessFlags;
249579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            this.staticValue = staticValue;
250579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
251579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
252579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        EncodedField toEncodedField() {
253579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return new EncodedField(fieldId.constant, accessFlags);
254579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
255579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
256579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public boolean isStatic() {
25790699b97998f1582a921202fb909f17f9718d177Jesse Wilson            return (accessFlags & STATIC) != 0;
258579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
259579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
260579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
261579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    static class MethodDeclaration {
262579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        final MethodId<?, ?> method;
263579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        private final int flags;
264579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        private final Code code;
265579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
266579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public MethodDeclaration(MethodId<?, ?> method, int flags) {
267579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            this.method = method;
268579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            this.flags = flags;
269579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            this.code = new Code(this);
270579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
271579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
272579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        boolean isStatic() {
27390699b97998f1582a921202fb909f17f9718d177Jesse Wilson            return (flags & STATIC) != 0;
274579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
275579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
276579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        boolean isDirect() {
27790699b97998f1582a921202fb909f17f9718d177Jesse Wilson            return (flags & (STATIC | PRIVATE | ACC_CONSTRUCTOR)) != 0;
278579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
279579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
280579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        EncodedMethod toEncodedMethod(DexOptions dexOptions) {
281579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            RopMethod ropMethod = new RopMethod(code.toBasicBlocks(), 0);
282579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            LocalVariableInfo locals = null;
283579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            DalvCode dalvCode = RopTranslator.translate(
284579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    ropMethod, PositionList.NONE, locals, code.paramSize(), dexOptions);
285579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return new EncodedMethod(method.constant, flags, dalvCode, StdTypeList.EMPTY);
286579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
287579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
288579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson}
289