summaryrefslogtreecommitdiffstats
path: root/dx
diff options
context:
space:
mode:
authorDan Bornstein <danfuzz@android.com>2011-03-16 16:32:31 -0700
committerDan Bornstein <danfuzz@android.com>2011-03-16 16:32:31 -0700
commit3dfda9ad1964510e4a7948a240b30cd710e86341 (patch)
tree961e10d71cfec326a600f52a20357847c2450496 /dx
parent1b4822ecb93021e6273c92093f78dcb6ccc0cf91 (diff)
downloadandroid_dalvik-3dfda9ad1964510e4a7948a240b30cd710e86341.tar.gz
android_dalvik-3dfda9ad1964510e4a7948a240b30cd710e86341.tar.bz2
android_dalvik-3dfda9ad1964510e4a7948a240b30cd710e86341.zip
Add --target-api=N option to dx.
This change adds the option and plumbs it into where it needs to go, but doesn't add any code to take action on it. That will come in a follow-up. Bug: 4094709 Change-Id: I9c796e176e125b0bcee18af56d9e6da802dfa081
Diffstat (limited to 'dx')
-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 =