summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--dx/src/com/android/dx/command/dexer/Main.java36
-rw-r--r--dx/src/com/android/dx/dex/DexOptions.java25
-rw-r--r--dx/src/com/android/dx/dex/cf/CfTranslator.java60
-rw-r--r--dx/src/com/android/dx/dex/code/Dops.java5
-rw-r--r--dx/src/com/android/dx/dex/code/OutputCollector.java7
-rw-r--r--dx/src/com/android/dx/dex/code/OutputFinisher.java10
-rw-r--r--dx/src/com/android/dx/dex/code/RopTranslator.java18
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 =