aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJesse Wilson <jessewilson@google.com>2012-01-06 14:58:00 -0500
committerJesse Wilson <jessewilson@google.com>2012-01-06 14:58:00 -0500
commit23abc2fe89ec3713645d64bdb74415a9090084f4 (patch)
tree552c4505c4a11bca5ca5b6b621053cb572e6a9b0
parente7afb8c8980d8d87660b0b9135e4947e907b4aba (diff)
downloaddexmaker-23abc2fe89ec3713645d64bdb74415a9090084f4.tar.gz
Use 'new Label()' rather than 'Code.newLabel()' to make it clear that allocating a label is a free operation, not depending on the current state of the Code instance.
-rw-r--r--src/main/java/com/google/dexmaker/Code.java29
-rw-r--r--src/main/java/com/google/dexmaker/DexMaker.java44
-rw-r--r--src/main/java/com/google/dexmaker/FieldId.java2
-rw-r--r--src/main/java/com/google/dexmaker/Label.java4
-rw-r--r--src/main/java/com/google/dexmaker/Local.java2
-rw-r--r--src/main/java/com/google/dexmaker/MethodId.java5
-rw-r--r--src/main/java/com/google/dexmaker/stock/ProxyBuilder.java2
-rw-r--r--src/test/java/com/google/dexmaker/DexMakerTest.java38
-rw-r--r--src/test/java/com/google/dexmaker/examples/FibonacciMaker.java2
9 files changed, 79 insertions, 49 deletions
diff --git a/src/main/java/com/google/dexmaker/Code.java b/src/main/java/com/google/dexmaker/Code.java
index 4ec2782..9afe0af 100644
--- a/src/main/java/com/google/dexmaker/Code.java
+++ b/src/main/java/com/google/dexmaker/Code.java
@@ -84,7 +84,8 @@ public final class Code {
for (TypeId<?> parameter : method.parameters.types) {
parameters.add(Local.get(this, parameter));
}
- this.currentLabel = newLabel();
+ this.currentLabel = new Label();
+ adopt(this.currentLabel);
this.currentLabel.marked = true;
}
@@ -167,19 +168,24 @@ public final class Code {
// labels
/**
- * Creates a new label for use as a branch target. The new label must have
- * code attached to it later by calling {@link #mark(Label)}.
+ * Assigns {@code target} to this code.
*/
- public Label newLabel() {
- Label result = new Label();
- labels.add(result);
- return result;
+ private void adopt(Label target) {
+ if (target.code == this) {
+ return; // already adopted
+ }
+ if (target.code != null) {
+ throw new IllegalArgumentException("Cannot adopt label; it belongs to another Code");
+ }
+ target.code = this;
+ labels.add(target);
}
/**
* Start defining instructions for the named label.
*/
public void mark(Label label) {
+ adopt(label);
if (label.marked) {
throw new IllegalStateException("already marked");
}
@@ -191,6 +197,7 @@ public final class Code {
}
public void jump(Label target) {
+ adopt(target);
addInstruction(new PlainInsn(Rops.GOTO, sourcePosition, null, RegisterSpecList.EMPTY),
target);
}
@@ -199,6 +206,7 @@ public final class Code {
if (catchTypes.contains(throwable)) {
throw new IllegalArgumentException("Already caught: " + throwable);
}
+ adopt(catchClause);
catchTypes.add(throwable);
catches = toTypeList(catchTypes);
catchLabels.add(catchClause);
@@ -288,7 +296,8 @@ public final class Code {
* @param catchLabels an immutable list of catch labels
*/
private void splitCurrentLabel(Label alternateSuccessor, List<Label> catchLabels) {
- Label newLabel = newLabel();
+ Label newLabel = new Label();
+ adopt(newLabel);
currentLabel.primarySuccessor = newLabel;
currentLabel.alternateSuccessor = alternateSuccessor;
currentLabel.catchLabels = catchLabels;
@@ -366,9 +375,7 @@ public final class Code {
* trueLabel}. If it is false, execution continues to the next instruction.
*/
public <T> void compare(Comparison comparison, Label trueLabel, Local<T> a, Local<T> b) {
- if (trueLabel == null) {
- throw new IllegalArgumentException();
- }
+ adopt(trueLabel);
Rop rop = comparison.rop(StdTypeList.make(a.type.ropType, b.type.ropType));
addInstruction(new PlainInsn(rop, sourcePosition, null,
RegisterSpecList.make(a.spec(), b.spec())), trueLabel);
diff --git a/src/main/java/com/google/dexmaker/DexMaker.java b/src/main/java/com/google/dexmaker/DexMaker.java
index 838bb69..d635465 100644
--- a/src/main/java/com/google/dexmaker/DexMaker.java
+++ b/src/main/java/com/google/dexmaker/DexMaker.java
@@ -25,7 +25,6 @@ import com.android.dx.dex.file.ClassDefItem;
import com.android.dx.dex.file.DexFile;
import com.android.dx.dex.file.EncodedField;
import com.android.dx.dex.file.EncodedMethod;
-import com.android.dx.rop.code.AccessFlags;
import static com.android.dx.rop.code.AccessFlags.ACC_CONSTRUCTOR;
import com.android.dx.rop.code.LocalVariableInfo;
import com.android.dx.rop.code.RopMethod;
@@ -36,6 +35,7 @@ import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Modifier;
import static java.lang.reflect.Modifier.PRIVATE;
import static java.lang.reflect.Modifier.STATIC;
import java.util.LinkedHashMap;
@@ -157,7 +157,7 @@ import java.util.jar.JarOutputStream;
*
* code.loadConstant(constant1, 1);
* code.loadConstant(constant2, 2);
- * Label baseCase = code.newLabel();
+ * Label baseCase = new Label();
* code.compare(Comparison.LT, baseCase, i, constant2);
* code.op(BinaryOp.SUBTRACT, a, i, constant1);
* code.op(BinaryOp.SUBTRACT, b, i, constant2);
@@ -201,10 +201,11 @@ public final class DexMaker {
return result;
}
- // TODO: describe the legal flags without referring to a non-public API AccessFlags
-
/**
- * @param flags any flags masked by {@link com.android.dx.rop.code.AccessFlags#CLASS_FLAGS}.
+ * Declares {@code type}.
+ *
+ * @param flags a bitwise combination of {@link Modifier#PUBLIC}, {@link
+ * Modifier#FINAL} and {@link Modifier#ABSTRACT}.
*/
public void declare(TypeId<?> type, String sourceFile, int flags,
TypeId<?> supertype, TypeId<?>... interfaces) {
@@ -220,14 +221,23 @@ public final class DexMaker {
}
/**
- * @param flags any flags masked by {@link com.android.dx.rop.code.AccessFlags#METHOD_FLAGS}.
+ * Declares a constructor. The name of {@code method} must be "<init>",
+ * as it is on all instances returned by {@link TypeId#getConstructor}.
+ *
+ * @param flags a bitwise combination of {@link Modifier#PUBLIC}, {@link
+ * Modifier#PRIVATE}, {@link Modifier#PROTECTED}, {@link Modifier#STATIC},
+ * {@link Modifier#FINAL}, and {@link Modifier#VARARGS}.
*/
public Code declareConstructor(MethodId<?, ?> method, int flags) {
return declare(method, flags | ACC_CONSTRUCTOR);
}
/**
- * @param flags any flags masked by {@link com.android.dx.rop.code.AccessFlags#METHOD_FLAGS}.
+ * Declares a method. The name of {@code method} must not be "<init>".
+ *
+ * @param flags a bitwise combination of {@link Modifier#PUBLIC}, {@link
+ * Modifier#PRIVATE}, {@link Modifier#PROTECTED}, {@link Modifier#STATIC},
+ * {@link Modifier#FINAL}, and {@link Modifier#VARARGS}.
*/
public Code declare(MethodId<?, ?> method, int flags) {
TypeDeclaration typeDeclaration = getTypeDeclaration(method.declaringType);
@@ -240,7 +250,12 @@ public final class DexMaker {
}
/**
- * @param flags any flags masked by {@link AccessFlags#FIELD_FLAGS}.
+ * Declares a field.
+ *
+ * @param flags a bitwise combination of {@link Modifier#PUBLIC}, {@link
+ * Modifier#PRIVATE}, {@link Modifier#PROTECTED}, {@link Modifier#STATIC},
+ * {@link Modifier#FINAL}, {@link Modifier#VOLATILE}, and {@link
+ * Modifier#TRANSIENT}.
*/
public void declare(FieldId<?, ?> fieldId, int flags, Object staticValue) {
TypeDeclaration typeDeclaration = getTypeDeclaration(fieldId.declaringType);
@@ -252,7 +267,7 @@ public final class DexMaker {
}
/**
- * Returns a .dex formatted file.
+ * Generates a dex file and returns its bytes.
*/
public byte[] generate() {
DexOptions options = new DexOptions();
@@ -271,15 +286,14 @@ public final class DexMaker {
}
/**
- * Loads the generated types into the current process.
+ * Generates a dex file and loads its types into the current process.
*
- * <p>All parameters are optional, you may pass {@code null} and suitable
+ * <p>All parameters are optional; you may pass {@code null} and suitable
* defaults will be used.
*
- * <p>If you opt to provide your own output directories, take care to
- * ensure that they are not world-readable, otherwise a malicious app will
- * be able to inject code to run. A suitable parameter for these output
- * directories would be something like this:
+ * <p>If you opt to provide your own {@code dexDir}, take care to ensure
+ * that it is not world-writable, otherwise a malicious app may be able
+ * to inject code into your process. A suitable parameter is:
* {@code getApplicationContext().getDir("dx", Context.MODE_PRIVATE); }
*
* @param parent the parent ClassLoader to be used when loading
diff --git a/src/main/java/com/google/dexmaker/FieldId.java b/src/main/java/com/google/dexmaker/FieldId.java
index 17ebfec..42974e9 100644
--- a/src/main/java/com/google/dexmaker/FieldId.java
+++ b/src/main/java/com/google/dexmaker/FieldId.java
@@ -21,7 +21,7 @@ import com.android.dx.rop.cst.CstNat;
import com.android.dx.rop.cst.CstString;
/**
- * A field.
+ * Identifies a field.
*/
public final class FieldId<D, V> {
final TypeId<D> declaringType;
diff --git a/src/main/java/com/google/dexmaker/Label.java b/src/main/java/com/google/dexmaker/Label.java
index 401e2a0..b37b18c 100644
--- a/src/main/java/com/google/dexmaker/Label.java
+++ b/src/main/java/com/google/dexmaker/Label.java
@@ -31,6 +31,8 @@ public final class Label {
final List<Insn> instructions = new ArrayList<Insn>();
+ Code code;
+
boolean marked = false;
/** an immutable list of labels corresponding to the types in the catch list */
@@ -44,7 +46,7 @@ public final class Label {
int id = -1;
- Label() {}
+ public Label() {}
boolean isEmpty() {
return instructions.isEmpty();
diff --git a/src/main/java/com/google/dexmaker/Local.java b/src/main/java/com/google/dexmaker/Local.java
index a993d5f..c89436d 100644
--- a/src/main/java/com/google/dexmaker/Local.java
+++ b/src/main/java/com/google/dexmaker/Local.java
@@ -19,7 +19,7 @@ package com.google.dexmaker;
import com.android.dx.rop.code.RegisterSpec;
/**
- * A temporary variable that holds a single value.
+ * A temporary variable that holds a single value of a known type.
*/
public final class Local<T> {
private final Code code;
diff --git a/src/main/java/com/google/dexmaker/MethodId.java b/src/main/java/com/google/dexmaker/MethodId.java
index ba67ff5..f437b90 100644
--- a/src/main/java/com/google/dexmaker/MethodId.java
+++ b/src/main/java/com/google/dexmaker/MethodId.java
@@ -23,7 +23,7 @@ import com.android.dx.rop.type.Prototype;
import java.util.List;
/**
- * A method or constructor.
+ * Identifies a method or constructor.
*/
public final class MethodId<D, R> {
final TypeId<D> declaringType;
@@ -55,6 +55,9 @@ public final class MethodId<D, R> {
return returnType;
}
+ /**
+ * Returns the method's name. This is "<init>" if this is a constructor.
+ */
public String getName() {
return name;
}
diff --git a/src/main/java/com/google/dexmaker/stock/ProxyBuilder.java b/src/main/java/com/google/dexmaker/stock/ProxyBuilder.java
index 7888a22..5970d82 100644
--- a/src/main/java/com/google/dexmaker/stock/ProxyBuilder.java
+++ b/src/main/java/com/google/dexmaker/stock/ProxyBuilder.java
@@ -385,7 +385,7 @@ public final class ProxyBuilder<T> {
// if (proxy == null)
code.loadConstant(nullHandler, null);
- Label handlerNullCase = code.newLabel();
+ Label handlerNullCase = new Label();
code.compare(Comparison.EQ, handlerNullCase, nullHandler, localHandler);
// This code is what we execute when we have a valid proxy: delegate to invocation
diff --git a/src/test/java/com/google/dexmaker/DexMakerTest.java b/src/test/java/com/google/dexmaker/DexMakerTest.java
index b9b0ea2..9c347eb 100644
--- a/src/test/java/com/google/dexmaker/DexMakerTest.java
+++ b/src/test/java/com/google/dexmaker/DexMakerTest.java
@@ -493,8 +493,8 @@ public final class DexMakerTest extends TestCase {
Local<Integer> localA = code.getParameter(0, TypeId.INT);
Local<Integer> localB = code.getParameter(1, TypeId.INT);
Local<Boolean> result = code.newLocal(TypeId.get(boolean.class));
- Label afterIf = code.newLabel();
- Label ifBody = code.newLabel();
+ Label afterIf = new Label();
+ Label ifBody = new Label();
code.compare(comparison, ifBody, localA, localB);
code.jump(afterIf);
@@ -1094,9 +1094,9 @@ public final class DexMakerTest extends TestCase {
code.loadConstant(local2, 2);
code.loadConstant(localResult, 1);
code.loadConstant(localI, 0);
- Label loopCondition = code.newLabel();
- Label loopBody = code.newLabel();
- Label afterLoop = code.newLabel();
+ Label loopCondition = new Label();
+ Label loopBody = new Label();
+ Label afterLoop = new Label();
code.mark(loopCondition);
code.compare(Comparison.LT, loopBody, localI, localCount);
code.jump(afterLoop);
@@ -1135,9 +1135,9 @@ public final class DexMakerTest extends TestCase {
Local<Integer> local2 = code.newLocal(TypeId.INT);
code.loadConstant(localResult, 1);
code.loadConstant(local2, 2);
- Label loopCondition = code.newLabel();
- Label loopBody = code.newLabel();
- Label afterLoop = code.newLabel();
+ Label loopCondition = new Label();
+ Label loopBody = new Label();
+ Label afterLoop = new Label();
code.mark(loopCondition);
code.compare(Comparison.LT, loopBody, localResult, localMax);
code.jump(afterLoop);
@@ -1178,9 +1178,9 @@ public final class DexMakerTest extends TestCase {
Local<Integer> localA = code.getParameter(0, TypeId.INT);
Local<Integer> localB = code.getParameter(1, TypeId.INT);
Local<Integer> localC = code.getParameter(2, TypeId.INT);
- Label aLessThanB = code.newLabel();
- Label aLessThanC = code.newLabel();
- Label bLessThanC = code.newLabel();
+ Label aLessThanB = new Label();
+ Label aLessThanC = new Label();
+ Label bLessThanC = new Label();
code.compare(Comparison.LT, aLessThanB, localA, localB);
code.compare(Comparison.LT, bLessThanC, localB, localC);
code.returnValue(localC);
@@ -1224,7 +1224,7 @@ public final class DexMakerTest extends TestCase {
Local<Integer> localX = code.newLocal(TypeId.INT);
Local<Integer> localY = code.newLocal(TypeId.INT);
Local<Integer> localResult = code.newLocal(TypeId.INT);
- Label baseCase = code.newLabel();
+ Label baseCase = new Label();
code.loadConstant(local1, 1);
code.loadConstant(local2, 2);
code.compare(Comparison.LT, baseCase, localA, local2);
@@ -1265,9 +1265,9 @@ public final class DexMakerTest extends TestCase {
Code code = dexMaker.declare(methodId, PUBLIC | STATIC);
Local<Integer> localI = code.getParameter(0, TypeId.INT);
Local<String> result = code.newLocal(TypeId.STRING);
- Label catchIae = code.newLabel();
- Label catchIse = code.newLabel();
- Label catchRe = code.newLabel();
+ Label catchIae = new Label();
+ Label catchIse = new Label();
+ Label catchRe = new Label();
code.addCatchClause(TypeId.get(IllegalArgumentException.class), catchIae);
code.addCatchClause(TypeId.get(IllegalStateException.class), catchIse);
@@ -1343,8 +1343,8 @@ public final class DexMakerTest extends TestCase {
Local<Integer> localB = code.getParameter(1, TypeId.INT);
Local<Integer> localC = code.getParameter(2, TypeId.INT);
Local<String> localResult = code.newLocal(TypeId.STRING);
- Label catchInner = code.newLabel();
- Label catchOuter = code.newLabel();
+ Label catchInner = new Label();
+ Label catchOuter = new Label();
TypeId<IllegalArgumentException> iaeType = TypeId.get(IllegalArgumentException.class);
code.addCatchClause(iaeType, catchOuter);
@@ -1640,6 +1640,10 @@ public final class DexMakerTest extends TestCase {
// TODO: attempt to generate an interface
+ // TODO: declare native method or abstract method
+
+ // TODO: synchronized or declared synchronized?
+
private void addDefaultConstructor() {
Code code = dexMaker.declareConstructor(GENERATED.getConstructor(), PUBLIC);
Local<?> thisRef = code.getThis(GENERATED);
diff --git a/src/test/java/com/google/dexmaker/examples/FibonacciMaker.java b/src/test/java/com/google/dexmaker/examples/FibonacciMaker.java
index 91f743a..5e0461c 100644
--- a/src/test/java/com/google/dexmaker/examples/FibonacciMaker.java
+++ b/src/test/java/com/google/dexmaker/examples/FibonacciMaker.java
@@ -47,7 +47,7 @@ public final class FibonacciMaker {
Local<Integer> result = code.newLocal(TypeId.INT);
code.loadConstant(constant1, 1);
code.loadConstant(constant2, 2);
- Label baseCase = code.newLabel();
+ Label baseCase = new Label();
code.compare(Comparison.LT, baseCase, i, constant2);
code.op(BinaryOp.SUBTRACT, a, i, constant1);
code.op(BinaryOp.SUBTRACT, b, i, constant2);