Merge "Add --tolerant option" into ub-jack
diff --git a/jill/src/com/android/jill/Options.java b/jill/src/com/android/jill/Options.java
index d759d24..420d364 100644
--- a/jill/src/com/android/jill/Options.java
+++ b/jill/src/com/android/jill/Options.java
@@ -51,6 +51,9 @@
@Option(name = "--version", usage = "display version")
protected boolean version;
+ @Option(name = "--tolerant", usage = "be tolerant to malformed input (default: false)")
+ protected boolean tolerant = false;
+
private final ContainerType outputContainer = ContainerType.ZIP;
@Option(name = "--no-debug", usage = "disable debug info emission")
@@ -120,10 +123,19 @@
this.verbose = verbose;
}
+
public boolean isVerbose() {
return verbose;
}
+ public void setTolerant(boolean tolerant) {
+ this.tolerant = tolerant;
+ }
+
+ public boolean isTolerant() {
+ return tolerant;
+ }
+
public boolean isEmitDebugInfo() {
return !disableEmitDebugInfo;
}
diff --git a/jill/src/com/android/jill/frontend/java/MethodBodyWriter.java b/jill/src/com/android/jill/frontend/java/MethodBodyWriter.java
index 63f253d..0788f1d 100644
--- a/jill/src/com/android/jill/frontend/java/MethodBodyWriter.java
+++ b/jill/src/com/android/jill/frontend/java/MethodBodyWriter.java
@@ -56,6 +56,7 @@
import java.io.IOException;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
@@ -198,18 +199,23 @@
this.annotWriter = annotWriter;
this.options = options;
currentClass = cn;
- currentMethod = getMethodWithoutJSR(mn);
-
BasicInterpreter bi = new JillAnalyzer();
analyzer = new Analyzer<BasicValue>(bi);
- try {
- analyzer.analyze(currentClass.name, currentMethod);
- removeDeadCode();
+ if (mn.instructions.size() != 0) {
+ currentMethod = getMethodWithoutJSR(mn);
- analyzer.analyze(currentClass.name, currentMethod);
- } catch (AnalyzerException e) {
- throw new JillException("Variable analyser fails.", e);
+ try {
+ analyzer.analyze(currentClass.name, currentMethod);
+
+ removeDeadCode();
+
+ analyzer.analyze(currentClass.name, currentMethod);
+ } catch (AnalyzerException e) {
+ throw new JillException("Variable analyser fails.", e);
+ }
+ } else {
+ currentMethod = mn;
}
}
@@ -406,86 +412,109 @@
writer.writeOpen();
writer.writeOpenNodeList();
- for (Map.Entry<Variable, Variable> entry : parameter2Var.entrySet()) {
- Variable p = entry.getKey();
- sourceInfoWriter.writeDebugBegin(currentClass, currentLine);
- writer.writeCatchBlockIds(currentCatchList);
- writer.writeKeyword(Token.EXPRESSION_STATEMENT);
- writer.writeOpen();
- sourceInfoWriter.writeDebugBegin(currentClass, currentLine);
- writer.writeKeyword(Token.ASG_OPERATION);
- writer.writeOpen();
- writeLocalRef(entry.getValue());
- if (p.getType() == Type.BOOLEAN_TYPE) {
- writeCastOperation(Token.REINTERPRETCAST_OPERATION, p, Type.INT_TYPE.getDescriptor());
+ if (currentMethod.instructions.size() == 0) {
+ if (options.isTolerant()) {
+ sourceInfoWriter.writeDebugBegin(currentClass, currentLine);
+ writer.writeCatchBlockIds(currentCatchList);
+ writer.writeKeyword(Token.THROW_STATEMENT);
+ writer.writeOpen();
+ writer.writeKeyword(Token.NEW_INSTANCE);
+ writer.writeOpen();
+ // Type of created object
+ writer.writeId("Ljava/lang/AssertionError;");
+ // Empty argument types
+ writer.writeIds(Collections.<String>emptyList());
+ // No arguments
+ writer.writeOpenNodeList();
+ writer.writeCloseNodeList();
+ writer.writeClose();
+ sourceInfoWriter.writeDebugEnd(currentClass, currentLine + 1);
+ writer.writeClose();
} else {
- writeLocalRef(p);
+ throw new JillException("Method should have instructions.");
}
- sourceInfoWriter.writeDebugEnd(currentClass, currentLine + 1);
- writer.writeClose();
- sourceInfoWriter.writeDebugEnd(currentClass, currentLine + 1);
- writer.writeClose();
- }
-
- Frame<BasicValue>[] frames = analyzer.getFrames();
-
- for (int insnIdx = 0; insnIdx < currentMethod.instructions.size(); insnIdx++) {
- currentPc = insnIdx;
- AbstractInsnNode insn = currentMethod.instructions.get(insnIdx);
- Frame<BasicValue> currentFrame = frames[insnIdx];
- // There's no next frame if insn is a return, and the last instruction.
- Frame<BasicValue> nextFrame = (insnIdx < frames.length - 1) ? frames[insnIdx + 1] : null;
-
- if (insn instanceof JumpInsnNode) {
- writeInsn(currentFrame, (JumpInsnNode) insn, insnIdx);
- } else if (insn instanceof LdcInsnNode) {
- assert nextFrame != null;
- writeInsn(nextFrame, (LdcInsnNode) insn);
- } else if (insn instanceof InsnNode) {
- writeInsn(currentFrame, nextFrame, (InsnNode) insn);
- } else if (insn instanceof VarInsnNode) {
- assert nextFrame != null;
- writeInsn(currentFrame, nextFrame, (VarInsnNode) insn);
- } else if (insn instanceof LabelNode) {
- computeCatchList((LabelNode) insn);
- writeCatchBlock((LabelNode) insn, insnIdx, frames);
- writeLabelInsn(insnIdx);
- } else if (insn instanceof FieldInsnNode) {
- assert nextFrame != null;
- writeInsn(currentFrame, nextFrame, (FieldInsnNode) insn);
- } else if (insn instanceof MethodInsnNode) {
- assert nextFrame != null;
- writeInsn(currentFrame, nextFrame, (MethodInsnNode) insn);
- } else if (insn instanceof LineNumberNode) {
- currentLine = ((LineNumberNode) insn).line;
- } else if (insn instanceof FrameNode) {
- // Nothing to do.
- } else if (insn instanceof TypeInsnNode) {
- assert nextFrame != null;
- writeInsn(currentFrame, nextFrame, (TypeInsnNode) insn);
- } else if (insn instanceof TableSwitchInsnNode) {
- assert nextFrame != null;
- writeInsn(currentFrame, nextFrame, (TableSwitchInsnNode) insn, insnIdx);
- } else if (insn instanceof LookupSwitchInsnNode) {
- assert nextFrame != null;
- writeInsn(currentFrame, nextFrame, (LookupSwitchInsnNode) insn, insnIdx);
- } else if (insn instanceof IntInsnNode) {
- assert nextFrame != null;
- writeInsn(currentFrame, nextFrame, (IntInsnNode) insn);
- } else if (insn instanceof IincInsnNode) {
- assert nextFrame != null;
- writeInsn(currentFrame, nextFrame, (IincInsnNode) insn);
- } else if (insn instanceof MultiANewArrayInsnNode) {
- assert nextFrame != null;
- writeInsn(currentFrame, nextFrame, (MultiANewArrayInsnNode) insn);
- } else {
- throw new JillException("Unsupported instruction.");
+ } else {
+ for (Map.Entry<Variable, Variable> entry : parameter2Var.entrySet()) {
+ Variable p = entry.getKey();
+ sourceInfoWriter.writeDebugBegin(currentClass, currentLine);
+ writer.writeCatchBlockIds(currentCatchList);
+ writer.writeKeyword(Token.EXPRESSION_STATEMENT);
+ writer.writeOpen();
+ sourceInfoWriter.writeDebugBegin(currentClass, currentLine);
+ writer.writeKeyword(Token.ASG_OPERATION);
+ writer.writeOpen();
+ writeLocalRef(entry.getValue());
+ if (p.getType() == Type.BOOLEAN_TYPE) {
+ writeCastOperation(Token.REINTERPRETCAST_OPERATION, p, Type.INT_TYPE.getDescriptor());
+ } else {
+ writeLocalRef(p);
+ }
+ sourceInfoWriter.writeDebugEnd(currentClass, currentLine + 1);
+ writer.writeClose();
+ sourceInfoWriter.writeDebugEnd(currentClass, currentLine + 1);
+ writer.writeClose();
}
- }
- // Current solution for comparison requires its result to be consumed by an "if"
- if (!cmpOperands.isEmpty()) {
- throw new AssertionError("A comparison has not been followed by an if");
+ Frame<BasicValue>[] frames = analyzer.getFrames();
+
+ for (int insnIdx = 0; insnIdx < currentMethod.instructions.size(); insnIdx++) {
+ currentPc = insnIdx;
+ AbstractInsnNode insn = currentMethod.instructions.get(insnIdx);
+ Frame<BasicValue> currentFrame = frames[insnIdx];
+ // There's no next frame if insn is a return, and the last instruction.
+ Frame<BasicValue> nextFrame = (insnIdx < frames.length - 1) ? frames[insnIdx + 1] : null;
+
+ if (insn instanceof JumpInsnNode) {
+ writeInsn(currentFrame, (JumpInsnNode) insn, insnIdx);
+ } else if (insn instanceof LdcInsnNode) {
+ assert nextFrame != null;
+ writeInsn(nextFrame, (LdcInsnNode) insn);
+ } else if (insn instanceof InsnNode) {
+ writeInsn(currentFrame, nextFrame, (InsnNode) insn);
+ } else if (insn instanceof VarInsnNode) {
+ assert nextFrame != null;
+ writeInsn(currentFrame, nextFrame, (VarInsnNode) insn);
+ } else if (insn instanceof LabelNode) {
+ computeCatchList((LabelNode) insn);
+ writeCatchBlock((LabelNode) insn, insnIdx, frames);
+ writeLabelInsn(insnIdx);
+ } else if (insn instanceof FieldInsnNode) {
+ assert nextFrame != null;
+ writeInsn(currentFrame, nextFrame, (FieldInsnNode) insn);
+ } else if (insn instanceof MethodInsnNode) {
+ assert nextFrame != null;
+ writeInsn(currentFrame, nextFrame, (MethodInsnNode) insn);
+ } else if (insn instanceof LineNumberNode) {
+ currentLine = ((LineNumberNode) insn).line;
+ } else if (insn instanceof FrameNode) {
+ // Nothing to do.
+ } else if (insn instanceof TypeInsnNode) {
+ assert nextFrame != null;
+ writeInsn(currentFrame, nextFrame, (TypeInsnNode) insn);
+ } else if (insn instanceof TableSwitchInsnNode) {
+ assert nextFrame != null;
+ writeInsn(currentFrame, nextFrame, (TableSwitchInsnNode) insn, insnIdx);
+ } else if (insn instanceof LookupSwitchInsnNode) {
+ assert nextFrame != null;
+ writeInsn(currentFrame, nextFrame, (LookupSwitchInsnNode) insn, insnIdx);
+ } else if (insn instanceof IntInsnNode) {
+ assert nextFrame != null;
+ writeInsn(currentFrame, nextFrame, (IntInsnNode) insn);
+ } else if (insn instanceof IincInsnNode) {
+ assert nextFrame != null;
+ writeInsn(currentFrame, nextFrame, (IincInsnNode) insn);
+ } else if (insn instanceof MultiANewArrayInsnNode) {
+ assert nextFrame != null;
+ writeInsn(currentFrame, nextFrame, (MultiANewArrayInsnNode) insn);
+ } else {
+ throw new JillException("Unsupported instruction.");
+ }
+ }
+
+ // Current solution for comparison requires its result to be consumed by an "if"
+ if (!cmpOperands.isEmpty()) {
+ throw new AssertionError("A comparison has not been followed by an if");
+ }
}
writer.writeCloseNodeList();
@@ -2058,9 +2087,11 @@
private void writeLocals() throws IOException {
writer.writeOpenNodeList();
- Iterator<Variable> varIt = collectLocals();
- while (varIt.hasNext()) {
- writeLocal(varIt.next());
+ if (currentMethod.instructions.size() != 0) {
+ Iterator<Variable> varIt = collectLocals();
+ while (varIt.hasNext()) {
+ writeLocal(varIt.next());
+ }
}
writer.writeCloseNodeList();