Use the static opcode chains in dx.
This removes the need to iterate over all possible opcodes looking for
family/format matches whenever the need arises to rewrite an
instruction with a new opcode. This should speed dx up at least a
little, though I don't know if it will be measurable. It's certainly
cleaner and a bit simpler, though.
Change-Id: I779f19cb1249d30f6886faf76670ae37d5dfc402
diff --git a/dx/src/com/android/dx/dex/code/Dops.java b/dx/src/com/android/dx/dex/code/Dops.java
index 34d356d..417c1f1 100644
--- a/dx/src/com/android/dx/dex/code/Dops.java
+++ b/dx/src/com/android/dx/dex/code/Dops.java
@@ -1410,33 +1410,22 @@
}
/**
- * Gets the {@link Dop} with the given family/format combination, if
- * any.
+ * Gets the next {@link Dop} in the instruction fitting chain after the
+ * given instance, if any.
*
- * @param family {@code DalvOps.MIN_VALUE..DalvOps.MAX_VALUE;} the
- * opcode family
- * @param format {@code non-null;} the opcode's instruction format
- * @return {@code null-ok;} the corresponding opcode, or {@code null} if
- * there is none
+ * @param opcode {@code non-null;} the opcode
+ * @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 getOrNull(int family, InsnFormat format) {
- if (format == null) {
- throw new NullPointerException("format == null");
+ public static Dop getNextOrNull(Dop opcode) {
+ int nextOpcode = opcode.getNextOpcode();
+
+ if (nextOpcode == DalvOps.NO_NEXT) {
+ return null;
}
- int len = DOPS.length;
-
- // TODO: Linear search is bad.
- for (int i = 0; i < len; i++) {
- Dop dop = DOPS[i];
- if ((dop != null) &&
- (dop.getFamily() == family) &&
- (dop.getFormat() == format)) {
- return dop;
- }
- }
-
- return null;
+ return get(nextOpcode);
}
/**
diff --git a/dx/src/com/android/dx/dex/code/OutputFinisher.java b/dx/src/com/android/dx/dex/code/OutputFinisher.java
index 4a51198..9d6fec7 100644
--- a/dx/src/com/android/dx/dex/code/OutputFinisher.java
+++ b/dx/src/com/android/dx/dex/code/OutputFinisher.java
@@ -63,8 +63,8 @@
* Constructs an instance. It initially contains no instructions.
*
* @param regCount {@code >= 0;} register count for the method
- * @param initialCapacity {@code >= 0;} initial capacity of the instructions
- * list
+ * @param initialCapacity {@code >= 0;} initial capacity of the
+ * instructions list
*/
public OutputFinisher(int initialCapacity, int regCount) {
this.unreservedRegCount = regCount;
@@ -255,7 +255,8 @@
* @param which how many instructions back to find the branch;
* {@code 0} is the most recently added instruction,
* {@code 1} is the instruction before that, etc.
- * @param newTarget {@code non-null;} the new target for the reversed branch
+ * @param newTarget {@code non-null;} the new target for the
+ * reversed branch
*/
public void reverseBranch(int which, CodeAddress newTarget) {
int size = insns.size();
@@ -345,9 +346,9 @@
throw new UnsupportedOperationException("already processed");
}
- InsnFormat[] formats = makeFormatsArray();
- reserveRegisters(formats);
- massageInstructions(formats);
+ Dop[] opcodes = makeOpcodesArray();
+ reserveRegisters(opcodes);
+ massageInstructions(opcodes);
assignAddressesAndFixBranches();
return DalvInsnList.makeImmutable(insns,
@@ -356,17 +357,17 @@
/**
* Helper for {@link #finishProcessingAndGetList}, which extracts
- * the format out of each instruction into a separate array, to be
+ * the opcode out of each instruction into a separate array, to be
* further manipulated as things progress.
*
- * @return {@code non-null;} the array of formats
+ * @return {@code non-null;} the array of opcodes
*/
- private InsnFormat[] makeFormatsArray() {
+ private Dop[] makeOpcodesArray() {
int size = insns.size();
- InsnFormat[] result = new InsnFormat[size];
+ Dop[] result = new Dop[size];
for (int i = 0; i < size; i++) {
- result[i] = insns.get(i).getOpcode().getFormat();
+ result[i] = insns.get(i).getOpcode();
}
return result;
@@ -375,13 +376,14 @@
/**
* Helper for {@link #finishProcessingAndGetList}, which figures
* out how many reserved registers are required and then reserving
- * them. It also updates the given {@code formats} array so
+ * them. It also updates the given {@code opcodes} array so
* as to avoid extra work when constructing the massaged
* instruction list.
*
- * @param formats {@code non-null;} array of per-instruction format selections
+ * @param opcodes {@code non-null;} array of per-instruction
+ * opcode selections
*/
- private void reserveRegisters(InsnFormat[] formats) {
+ private void reserveRegisters(Dop[] opcodes) {
int oldReservedCount = (reservedCount < 0) ? 0 : reservedCount;
/*
@@ -389,7 +391,7 @@
* reservation, repeatedly until no new reservations happen.
*/
for (;;) {
- int newReservedCount = calculateReservedCount(formats);
+ int newReservedCount = calculateReservedCount(opcodes);
if (oldReservedCount >= newReservedCount) {
break;
}
@@ -425,13 +427,14 @@
* Helper for {@link #reserveRegisters}, which does one
* pass over the instructions, calculating the number of
* registers that need to be reserved. It also updates the
- * {@code formats} list to help avoid extra work in future
+ * {@code opcodes} list to help avoid extra work in future
* register reservation passes.
*
- * @param formats {@code non-null;} array of per-instruction format selections
+ * @param opcodes {@code non-null;} array of per-instruction
+ * opcode selections
* @return {@code >= 0;} the count of reserved registers
*/
- private int calculateReservedCount(InsnFormat[] formats) {
+ private int calculateReservedCount(Dop[] opcodes) {
int size = insns.size();
/*
@@ -444,14 +447,14 @@
for (int i = 0; i < size; i++) {
DalvInsn insn = insns.get(i);
- InsnFormat originalFormat = formats[i];
- InsnFormat newFormat = findFormatForInsn(insn, originalFormat);
+ Dop originalOpcode = opcodes[i];
+ Dop newOpcode = findOpcodeForInsn(insn, originalOpcode);
- if (originalFormat == newFormat) {
+ if (originalOpcode == newOpcode) {
continue;
}
- if (newFormat == null) {
+ if (newOpcode == null) {
/*
* The instruction will need to be expanded, so reserve
* registers for it.
@@ -462,50 +465,43 @@
}
}
- formats[i] = newFormat;
+ opcodes[i] = newOpcode;
}
return newReservedCount;
}
/**
- * Attempts to fit the given instruction into a format, returning
- * either a format that the instruction fits into or {@code null}
- * to indicate that the instruction will need to be expanded. This
- * fitting process starts with the given format as a first "best
- * guess" and then pessimizes from there if necessary.
+ * Attempts to fit the given instruction into a specific opcode,
+ * returning the opcode whose format that the instruction fits
+ * into or {@code null} to indicate that the instruction will need
+ * to be expanded. This fitting process starts with the given
+ * opcode as a first "best guess" and then pessimizes from there
+ * if necessary.
*
* @param insn {@code non-null;} the instruction in question
- * @param format {@code null-ok;} the current guess as to the best instruction
- * format to use; {@code null} means that no simple format fits
- * @return {@code null-ok;} a possibly-different format, which is either a
- * good fit or {@code null} to indicate that no simple format
- * fits
+ * @param guess {@code null-ok;} the current guess as to the best
+ * opcode; {@code null} means that no simple opcode fits
+ * @return {@code null-ok;} a possibly-different opcode; either a
+ * {@code non-null} good fit or {@code null} to indicate that no
+ * simple opcode fits
*/
- private InsnFormat findFormatForInsn(DalvInsn insn, InsnFormat format) {
- if (format == null) {
- // The instruction is already known not to fit any simple format.
- return format;
- }
+ private Dop findOpcodeForInsn(DalvInsn insn, Dop guess) {
+ /*
+ * Note: The initial guess might be null, meaning that an
+ * earlier call to this method already determined that there
+ * was no possible simple opcode fit.
+ */
- if (format.isCompatible(insn)) {
- // The instruction already fits in the current best-known format.
- return format;
- }
-
- Dop dop = insn.getOpcode();
- int family = dop.getFamily();
-
- for (;;) {
- format = format.nextUp();
- if ((format == null) ||
- (format.isCompatible(insn) &&
- (Dops.getOrNull(family, format) != null))) {
+ while (guess != null) {
+ if (guess.getFormat().isCompatible(insn)) {
break;
}
+
+ guess = Dops.getNextOrNull(guess);
}
- return format;
+ return guess;
}
/**
@@ -527,27 +523,27 @@
* final addresses aren't known at the point that this method is
* called.</p>
*
- * @param formats {@code non-null;} array of per-instruction format selections
+ * @param opcodes {@code non-null;} array of per-instruction
+ * opcode selections
*/
- private void massageInstructions(InsnFormat[] formats) {
+ private void massageInstructions(Dop[] opcodes) {
if (reservedCount == 0) {
/*
* The easy common case: No registers were reserved, so we
- * merely need to replace any instructions whose format changed
- * during the reservation pass, but all instructions will stay
- * at their original indices, and the instruction list doesn't
- * grow.
+ * merely need to replace any instructions whose format
+ * (and hence whose opcode) changed during the reservation
+ * pass, but all instructions will stay at their original
+ * indices, and the instruction list doesn't grow.
*/
int size = insns.size();
for (int i = 0; i < size; i++) {
DalvInsn insn = insns.get(i);
- Dop dop = insn.getOpcode();
- InsnFormat format = formats[i];
+ Dop originalOpcode = insn.getOpcode();
+ Dop currentOpcode = opcodes[i];
- if (format != dop.getFormat()) {
- dop = Dops.getOrNull(dop.getFamily(), format);
- insns.set(i, insn.withOpcode(dop));
+ if (originalOpcode != currentOpcode) {
+ insns.set(i, insn.withOpcode(currentOpcode));
}
}
} else {
@@ -555,7 +551,7 @@
* The difficult uncommon case: Some instructions have to be
* expanded to deal with high registers.
*/
- insns = performExpansion(formats);
+ insns = performExpansion(opcodes);
}
}
@@ -566,22 +562,22 @@
* problems) is expanded into a series of instances that together
* perform the proper function.
*
- * @param formats {@code non-null;} array of per-instruction format selections
+ * @param opcodes {@code non-null;} array of per-instruction
+ * opcode selections
* @return {@code non-null;} the replacement list
*/
- private ArrayList<DalvInsn> performExpansion(InsnFormat[] formats) {
+ private ArrayList<DalvInsn> performExpansion(Dop[] opcodes) {
int size = insns.size();
ArrayList<DalvInsn> result = new ArrayList<DalvInsn>(size * 2);
for (int i = 0; i < size; i++) {
DalvInsn insn = insns.get(i);
- Dop dop = insn.getOpcode();
- InsnFormat originalFormat = dop.getFormat();
- InsnFormat currentFormat = formats[i];
+ Dop originalOpcode = insn.getOpcode();
+ Dop currentOpcode = opcodes[i];
DalvInsn prefix;
DalvInsn suffix;
- if (currentFormat != null) {
+ if (currentOpcode != null) {
// No expansion is necessary.
prefix = null;
suffix = null;
@@ -592,20 +588,19 @@
/*
* Get the initial guess as to the hr version, but then
- * let findFormatForInsn() pick a better format, if any.
+ * let findOpcodeForInsn() pick a better format, if any.
*/
insn = insn.hrVersion();
- originalFormat = insn.getOpcode().getFormat();
- currentFormat = findFormatForInsn(insn, originalFormat);
+ originalOpcode = insn.getOpcode();
+ currentOpcode = findOpcodeForInsn(insn, originalOpcode);
}
if (prefix != null) {
result.add(prefix);
}
- if (currentFormat != originalFormat) {
- dop = Dops.getOrNull(dop.getFamily(), currentFormat);
- insn = insn.withOpcode(dop);
+ if (currentOpcode != originalOpcode) {
+ insn = insn.withOpcode(currentOpcode);
}
result.add(insn);
@@ -669,18 +664,17 @@
continue;
}
- Dop dop = insn.getOpcode();
- InsnFormat format = dop.getFormat();
+ Dop opcode = insn.getOpcode();
TargetInsn target = (TargetInsn) insn;
- if (format.branchFits(target)) {
+ if (opcode.getFormat().branchFits(target)) {
continue;
}
- if (dop.getFamily() == DalvOps.GOTO) {
+ if (opcode.getFamily() == DalvOps.GOTO) {
// It is a goto; widen it if possible.
- InsnFormat newFormat = findFormatForInsn(insn, format);
- if (newFormat == null) {
+ opcode = findOpcodeForInsn(insn, opcode);
+ if (opcode == null) {
/*
* The branch is already maximally large. This should
* only be possible if a method somehow manages to have
@@ -688,9 +682,7 @@
*/
throw new UnsupportedOperationException("method too long");
}
- dop = Dops.getOrNull(dop.getFamily(), newFormat);
- insn = insn.withOpcode(dop);
- insns.set(i, insn);
+ insns.set(i, insn.withOpcode(opcode));
} else {
/*
* It is a conditional: Reverse its sense, and arrange for