diff options
-rw-r--r-- | dx/src/com/android/dx/command/dexer/Main.java | 36 | ||||
-rw-r--r-- | dx/src/com/android/dx/dex/DexOptions.java | 25 | ||||
-rw-r--r-- | dx/src/com/android/dx/dex/cf/CfTranslator.java | 60 | ||||
-rw-r--r-- | dx/src/com/android/dx/dex/code/Dops.java | 5 | ||||
-rw-r--r-- | dx/src/com/android/dx/dex/code/OutputCollector.java | 7 | ||||
-rw-r--r-- | dx/src/com/android/dx/dex/code/OutputFinisher.java | 10 | ||||
-rw-r--r-- | dx/src/com/android/dx/dex/code/RopTranslator.java | 18 |
7 files changed, 119 insertions, 42 deletions
diff --git a/dx/src/com/android/dx/command/dexer/Main.java b/dx/src/com/android/dx/command/dexer/Main.java index 6e8fa7eed..a2133d525 100644 --- a/dx/src/com/android/dx/command/dexer/Main.java +++ b/dx/src/com/android/dx/command/dexer/Main.java @@ -23,6 +23,7 @@ import com.android.dx.cf.iface.ParseException; import com.android.dx.command.DxConsole; import com.android.dx.command.UsageException; import com.android.dx.dex.DexFormat; +import com.android.dx.dex.DexOptions; import com.android.dx.dex.cf.CfOptions; import com.android.dx.dex.cf.CfTranslator; import com.android.dx.dex.cf.CodeStatistics; @@ -464,7 +465,7 @@ public class Main { try { ClassDefItem clazz = - CfTranslator.translate(name, bytes, args.cfOptions); + CfTranslator.translate(name, bytes, args.cfOptions, args.dexOptions); synchronized (outputDex) { outputDex.add(clazz); } @@ -901,6 +902,9 @@ public class Main { */ public boolean keepClassesInJar = false; + /** what API level to target */ + public int targetApiLevel = Integer.MAX_VALUE; + /** how much source position info to preserve */ public int positionInfo = PositionList.LINES; @@ -910,7 +914,7 @@ public class Main { /** whether to merge with the output dex file if it exists. */ public boolean incremental = false; - /** {@code non-null after {@link #parse};} file name arguments */ + /** {@code non-null} after {@link #parse}; file name arguments */ public String[] fileNames; /** whether to do SSA/register optimization */ @@ -925,9 +929,12 @@ public class Main { /** Whether to print statistics to stdout at end of compile cycle */ public boolean statistics; - /** Options for dex.cf.* */ + /** Options for class file transformation */ public CfOptions cfOptions; + /** Options for dex file output */ + public DexOptions dexOptions; + /** number of threads to run with */ public int numThreads = 1; @@ -997,6 +1004,19 @@ public class Main { } else if (arg.startsWith("--dump-method=")) { methodToDump = arg.substring(arg.indexOf('=') + 1); jarOutput = false; + } else if (arg.startsWith("--target-api=")) { + arg = arg.substring(arg.indexOf('=') + 1); + int value; + try { + value = Integer.parseInt(arg); + } catch (NumberFormatException ex) { + value = -1; + } + if (value < 1) { + System.err.println("improper target-api option: " + arg); + throw new UsageException(); + } + targetApiLevel = value; } else if (arg.startsWith("--positions=")) { String pstr = arg.substring(arg.indexOf('=') + 1).intern(); if (pstr == "none") { @@ -1044,6 +1064,7 @@ public class Main { } makeCfOptions(); + makeDexOptions(); } /** @@ -1061,6 +1082,15 @@ public class Main { cfOptions.statistics = statistics; cfOptions.warn = DxConsole.err; } + + /** + * Copies relevent arguments over into a DexOptions instance. + */ + private void makeDexOptions() { + dexOptions = new DexOptions(); + + dexOptions.enableExtendedOpcodes = targetApiLevel >= 12; + } } /** Runnable helper class to process files in multiple threads */ diff --git a/dx/src/com/android/dx/dex/DexOptions.java b/dx/src/com/android/dx/dex/DexOptions.java new file mode 100644 index 000000000..bd07d6d29 --- /dev/null +++ b/dx/src/com/android/dx/dex/DexOptions.java @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.dx.dex; + +/** + * Container for options used to control details of dex file generation. + */ +public class DexOptions { + /** whether extended opcodes are allowed */ + public boolean enableExtendedOpcodes = true; +} diff --git a/dx/src/com/android/dx/dex/cf/CfTranslator.java b/dx/src/com/android/dx/dex/cf/CfTranslator.java index 1a9aa4717..8bcfa3d89 100644 --- a/dx/src/com/android/dx/dex/cf/CfTranslator.java +++ b/dx/src/com/android/dx/dex/cf/CfTranslator.java @@ -24,6 +24,7 @@ import com.android.dx.cf.iface.Field; import com.android.dx.cf.iface.FieldList; import com.android.dx.cf.iface.Method; import com.android.dx.cf.iface.MethodList; +import com.android.dx.dex.DexOptions; import com.android.dx.dex.code.DalvCode; import com.android.dx.dex.code.PositionList; import com.android.dx.dex.code.RopTranslator; @@ -76,13 +77,14 @@ public class CfTranslator { * @param filePath {@code non-null;} the file path for the class, * excluding any base directory specification * @param bytes {@code non-null;} contents of the file - * @param args command-line arguments + * @param cfOptions options for class translation + * @param dexOptions options for dex output * @return {@code non-null;} the translated class */ public static ClassDefItem translate(String filePath, byte[] bytes, - CfOptions args) { + CfOptions cfOptions, DexOptions dexOptions) { try { - return translate0(filePath, bytes, args); + return translate0(filePath, bytes, cfOptions, dexOptions); } catch (RuntimeException ex) { String msg = "...while processing " + filePath; throw ExceptionWithContext.withContext(ex, msg); @@ -97,38 +99,39 @@ public class CfTranslator { * @param filePath {@code non-null;} the file path for the class, * excluding any base directory specification * @param bytes {@code non-null;} contents of the file - * @param args command-line arguments + * @param cfOptions options for class translation + * @param dexOptions options for dex output * @return {@code non-null;} the translated class */ private static ClassDefItem translate0(String filePath, byte[] bytes, - CfOptions args) { + CfOptions cfOptions, DexOptions dexOptions) { DirectClassFile cf = - new DirectClassFile(bytes, filePath, args.strictNameCheck); + new DirectClassFile(bytes, filePath, cfOptions.strictNameCheck); cf.setAttributeFactory(StdAttributeFactory.THE_ONE); cf.getMagic(); - OptimizerOptions.loadOptimizeLists(args.optimizeListFile, - args.dontOptimizeListFile); + OptimizerOptions.loadOptimizeLists(cfOptions.optimizeListFile, + cfOptions.dontOptimizeListFile); // Build up a class to output. CstType thisClass = cf.getThisClass(); int classAccessFlags = cf.getAccessFlags() & ~AccessFlags.ACC_SUPER; - CstUtf8 sourceFile = (args.positionInfo == PositionList.NONE) ? null : + CstUtf8 sourceFile = (cfOptions.positionInfo == PositionList.NONE) ? null : cf.getSourceFile(); ClassDefItem out = new ClassDefItem(thisClass, classAccessFlags, cf.getSuperclass(), cf.getInterfaces(), sourceFile); Annotations classAnnotations = - AttributeTranslator.getClassAnnotations(cf, args); + AttributeTranslator.getClassAnnotations(cf, cfOptions); if (classAnnotations.size() != 0) { out.setClassAnnotations(classAnnotations); } processFields(cf, out); - processMethods(cf, args, out); + processMethods(cf, cfOptions, dexOptions, out); return out; } @@ -214,11 +217,12 @@ public class CfTranslator { * Processes the methods of the given class. * * @param cf {@code non-null;} class being translated - * @param args {@code non-null;} command-line args + * @param cfOptions {@code non-null;} options for class translation + * @param dexOptions {@code non-null;} options for dex output * @param out {@code non-null;} output class */ - private static void processMethods(DirectClassFile cf, - CfOptions args, ClassDefItem out) { + private static void processMethods(DirectClassFile cf, CfOptions cfOptions, + DexOptions dexOptions, ClassDefItem out) { CstType thisClass = cf.getThisClass(); MethodList methods = cf.getMethods(); int sz = methods.size(); @@ -242,8 +246,8 @@ public class CfTranslator { } else { ConcreteMethod concrete = new ConcreteMethod(one, cf, - (args.positionInfo != PositionList.NONE), - args.localInfo); + (cfOptions.positionInfo != PositionList.NONE), + cfOptions.localInfo); TranslationAdvice advice; @@ -259,7 +263,7 @@ public class CfTranslator { = thisClass.getClassType().getDescriptor() + "." + one.getName().getString(); - if (args.optimize && + if (cfOptions.optimize && OptimizerOptions.shouldOptimize(canonicalName)) { if (DEBUG) { System.err.println("Optimizing " + canonicalName); @@ -267,14 +271,14 @@ public class CfTranslator { nonOptRmeth = rmeth; rmeth = Optimizer.optimize(rmeth, - paramSize, isStatic, args.localInfo, advice); + paramSize, isStatic, cfOptions.localInfo, advice); if (DEBUG) { OptimizerOptions.compareOptimizerStep(nonOptRmeth, - paramSize, isStatic, args, advice, rmeth); + paramSize, isStatic, cfOptions, advice, rmeth); } - if (args.statistics) { + if (cfOptions.statistics) { CodeStatistics.updateRopStatistics( nonOptRmeth, rmeth); } @@ -282,15 +286,15 @@ public class CfTranslator { LocalVariableInfo locals = null; - if (args.localInfo) { + if (cfOptions.localInfo) { locals = LocalVariableExtractor.extract(rmeth); } - code = RopTranslator.translate(rmeth, args.positionInfo, - locals, paramSize); + code = RopTranslator.translate(rmeth, cfOptions.positionInfo, + locals, paramSize, dexOptions); - if (args.statistics && nonOptRmeth != null) { - updateDexStatistics(args, rmeth, nonOptRmeth, locals, + if (cfOptions.statistics && nonOptRmeth != null) { + updateDexStatistics(cfOptions, dexOptions, rmeth, nonOptRmeth, locals, paramSize, concrete.getCode().size()); } } @@ -345,7 +349,7 @@ public class CfTranslator { /** * Helper that updates the dex statistics. */ - private static void updateDexStatistics(CfOptions args, + private static void updateDexStatistics(CfOptions cfOptions, DexOptions dexOptions, RopMethod optRmeth, RopMethod nonOptRmeth, LocalVariableInfo locals, int paramSize, int originalByteCount) { /* @@ -357,9 +361,9 @@ public class CfTranslator { */ DalvCode optCode = RopTranslator.translate(optRmeth, - args.positionInfo, locals, paramSize); + cfOptions.positionInfo, locals, paramSize, dexOptions); DalvCode nonOptCode = RopTranslator.translate(nonOptRmeth, - args.positionInfo, locals, paramSize); + cfOptions.positionInfo, locals, paramSize, dexOptions); /* * Fake out the indices, so code.getInsns() can work well enough diff --git a/dx/src/com/android/dx/dex/code/Dops.java b/dx/src/com/android/dx/dex/code/Dops.java index 667b32663..df8818608 100644 --- a/dx/src/com/android/dx/dex/code/Dops.java +++ b/dx/src/com/android/dx/dex/code/Dops.java @@ -16,6 +16,7 @@ package com.android.dx.dex.code; +import com.android.dx.dex.DexOptions; import com.android.dx.dex.code.form.Form10t; import com.android.dx.dex.code.form.Form10x; import com.android.dx.dex.code.form.Form11n; @@ -1396,11 +1397,13 @@ public final class Dops { * given instance, if any. * * @param opcode {@code non-null;} the opcode + * @param options {@code non-null;} options, used to determine + * which opcodes are potentially off-limits * @return {@code null-ok;} the next opcode in the same family, in the * chain of opcodes to try, or {@code null} if the given opcode is * the last in its chain */ - public static Dop getNextOrNull(Dop opcode) { + public static Dop getNextOrNull(Dop opcode, DexOptions options) { int nextOpcode = opcode.getNextOpcode(); if (nextOpcode == Opcodes.NO_NEXT) { diff --git a/dx/src/com/android/dx/dex/code/OutputCollector.java b/dx/src/com/android/dx/dex/code/OutputCollector.java index d78e5fcab..a5e54a89d 100644 --- a/dx/src/com/android/dx/dex/code/OutputCollector.java +++ b/dx/src/com/android/dx/dex/code/OutputCollector.java @@ -16,6 +16,8 @@ package com.android.dx.dex.code; +import com.android.dx.dex.DexOptions; + import java.util.ArrayList; /** @@ -42,14 +44,15 @@ public final class OutputCollector { /** * Constructs an instance. * + * @param dexOptions {@code non-null;} options for dex output * @param initialCapacity {@code >= 0;} initial capacity of the output list * @param suffixInitialCapacity {@code >= 0;} initial capacity of the output * suffix * @param regCount {@code >= 0;} register count for the method */ - public OutputCollector(int initialCapacity, int suffixInitialCapacity, + public OutputCollector(DexOptions dexOptions, int initialCapacity, int suffixInitialCapacity, int regCount) { - this.finisher = new OutputFinisher(initialCapacity, regCount); + this.finisher = new OutputFinisher(dexOptions, initialCapacity, regCount); this.suffix = new ArrayList<DalvInsn>(suffixInitialCapacity); } diff --git a/dx/src/com/android/dx/dex/code/OutputFinisher.java b/dx/src/com/android/dx/dex/code/OutputFinisher.java index 118d18435..1b13faba1 100644 --- a/dx/src/com/android/dx/dex/code/OutputFinisher.java +++ b/dx/src/com/android/dx/dex/code/OutputFinisher.java @@ -16,6 +16,7 @@ package com.android.dx.dex.code; +import com.android.dx.dex.DexOptions; import com.android.dx.io.Opcodes; import com.android.dx.rop.code.LocalItem; import com.android.dx.rop.code.RegisterSpec; @@ -38,6 +39,9 @@ import java.util.HashSet; * form of a {@link DalvInsnList} instance. */ public final class OutputFinisher { + /** {@code non-null;} options for dex output */ + private final DexOptions dexOptions; + /** * {@code >= 0;} register count for the method, not including any extra * "reserved" registers needed to translate "difficult" instructions @@ -64,11 +68,13 @@ public final class OutputFinisher { /** * Constructs an instance. It initially contains no instructions. * + * @param dexOptions {@code non-null;} options for dex output * @param regCount {@code >= 0;} register count for the method * @param initialCapacity {@code >= 0;} initial capacity of the * instructions list */ - public OutputFinisher(int initialCapacity, int regCount) { + public OutputFinisher(DexOptions dexOptions, int initialCapacity, int regCount) { + this.dexOptions = dexOptions; this.unreservedRegCount = regCount; this.insns = new ArrayList<DalvInsn>(initialCapacity); this.reservedCount = -1; @@ -500,7 +506,7 @@ public final class OutputFinisher { break; } - guess = Dops.getNextOrNull(guess); + guess = Dops.getNextOrNull(guess, dexOptions); } return guess; diff --git a/dx/src/com/android/dx/dex/code/RopTranslator.java b/dx/src/com/android/dx/dex/code/RopTranslator.java index 9899c43bd..3d24c4fc9 100644 --- a/dx/src/com/android/dx/dex/code/RopTranslator.java +++ b/dx/src/com/android/dx/dex/code/RopTranslator.java @@ -16,6 +16,7 @@ package com.android.dx.dex.code; +import com.android.dx.dex.DexOptions; import com.android.dx.io.Opcodes; import com.android.dx.rop.code.BasicBlock; import com.android.dx.rop.code.BasicBlockList; @@ -46,6 +47,9 @@ import java.util.ArrayList; * #translate} method is the thing to call on this class. */ public final class RopTranslator { + /** {@code non-null;} options for dex output */ + private final DexOptions dexOptions; + /** {@code non-null;} method to translate */ private final RopMethod method; @@ -92,13 +96,13 @@ public final class RopTranslator { * @param locals {@code null-ok;} local variable information to use * @param paramSize size, in register units, of all the parameters to * this method + * @param dexOptions {@code non-null;} options for dex output * @return {@code non-null;} the translated version */ public static DalvCode translate(RopMethod method, int positionInfo, - LocalVariableInfo locals, int paramSize) { + LocalVariableInfo locals, int paramSize, DexOptions dexOptions) { RopTranslator translator = - new RopTranslator(method, positionInfo, locals, - paramSize); + new RopTranslator(method, positionInfo, locals, paramSize, dexOptions); return translator.translateAndGetResult(); } @@ -111,9 +115,11 @@ public final class RopTranslator { * @param locals {@code null-ok;} local variable information to use * @param paramSize size, in register units, of all the parameters to * this method + * @param dexOptions {@code non-null;} options for dex output */ - private RopTranslator(RopMethod method, int positionInfo, - LocalVariableInfo locals, int paramSize) { + private RopTranslator(RopMethod method, int positionInfo, LocalVariableInfo locals, + int paramSize, DexOptions dexOptions) { + this.dexOptions = dexOptions; this.method = method; this.positionInfo = positionInfo; this.locals = locals; @@ -150,7 +156,7 @@ public final class RopTranslator { this.regCount = blocks.getRegCount() + (paramsAreInOrder ? 0 : this.paramSize); - this.output = new OutputCollector(maxInsns, bsz * 3, regCount); + this.output = new OutputCollector(dexOptions, maxInsns, bsz * 3, regCount); if (locals != null) { this.translationVisitor = |