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