return null;
MapMaker mm = new MapMaker(classes, minfo, ca);
- mm.make(blocks, ca.getCode());
+ try {
+ mm.make(blocks, ca.getCode());
+ }
+ catch (BadBytecode bb) {
+ throw new BadBytecode(minfo, bb);
+ }
+
return mm.toStackMap(blocks);
}
return null;
MapMaker mm = new MapMaker(classes, minfo, ca);
- mm.make(blocks, ca.getCode());
+ try {
+ mm.make(blocks, ca.getCode());
+ }
+ catch (BadBytecode bb) {
+ throw new BadBytecode(minfo, bb);
+ }
return mm.toStackMap2(minfo.getConstPool(), blocks);
}
{
make(code, blocks[0]);
try {
- fixTypes(blocks);
+ fixTypes(code, blocks);
} catch (NotFoundException e) {
throw new BadBytecode("failed to resolve types", e);
}
* Since SCCs are found in the topologically sorted order,
* their types are also fixed when they are found.
*/
- private void fixTypes(TypedBlock[] blocks) throws NotFoundException {
+ private void fixTypes(byte[] code, TypedBlock[] blocks) throws NotFoundException, BadBytecode {
ArrayList preOrder = new ArrayList();
int len = blocks.length;
int index = 0;
for (int i = 0; i < len; i++) {
TypedBlock block = blocks[i];
- int n = block.localsTypes.length;
- for (int j = 0; j < n; j++)
- index = block.localsTypes[j].dfs(preOrder, index, classPool);
+ if (block.localsTypes == null) // if block is dead code
+ fixDeadcode(code, block);
+ else {
+ int n = block.localsTypes.length;
+ for (int j = 0; j < n; j++)
+ index = block.localsTypes[j].dfs(preOrder, index, classPool);
- n = block.stackTop;
- for (int j = 0; j < n; j++)
- index = block.stackTypes[j].dfs(preOrder, index, classPool);
+ n = block.stackTop;
+ for (int j = 0; j < n; j++)
+ index = block.stackTypes[j].dfs(preOrder, index, classPool);
+ }
}
}
+ private void fixDeadcode(byte[] code, TypedBlock block) throws BadBytecode {
+ int pos = block.position;
+ int len = block.length - 3;
+ if (len < 0)
+ throw new BadBytecode("dead code detected at " + pos
+ + ". No stackmap table generated.");
+
+ for (int k = 0; k < len; k++)
+ code[pos + k] = Bytecode.NOP;
+
+ code[pos + len] = (byte)Bytecode.GOTO;
+ ByteArray.write16bit(-len, code, pos + len + 1);
+ }
+
// Phase 3
public StackMapTable toStackMap(TypedBlock[] blocks) {
offsetDelta = bb.length - 1;
prev = bb;
}
+ else if (bb.incoming == 0) {
+ // dead code.
+ writer.sameFrame(offsetDelta);
+ offsetDelta = bb.length - 1;
+ prev = bb;
+ }
else
offsetDelta += bb.length;
}
}
}
+ public void testJIRA175() throws Exception {
+ CtClass cc = loader.get("javassist.bytecode.StackMapTest$C5");
+ cc.getDeclaredMethod("setter").instrument(new javassist.expr.ExprEditor() {
+ @Override
+ public void edit(javassist.expr.FieldAccess f) throws javassist.CannotCompileException {
+ if (!f.where().getMethodInfo().isMethod())
+ return;
+
+ f.replace("{ $_ = $proceed($$); if (false) return $_;}");
+ }
+ });
+ cc.writeFile();
+ Object t1 = make(cc.getName());
+ assertEquals(3, invoke(t1, "test"));
+ }
+
+ public static class C5 {
+ String value;
+ int ivalue;
+ public int test() {
+ setter("foo");
+ return value.length();
+ }
+
+ public void setter(String s) {
+ value = s;
+ ivalue = s.length();
+ }
+ }
+
+ public void testJIRA175b() throws Exception {
+ CtClass cc = loader.get("javassist.bytecode.StackMapTest$C6");
+ try {
+ cc.getDeclaredMethod("setter").instrument(new javassist.expr.ExprEditor() {
+ public void edit(javassist.expr.FieldAccess f) throws javassist.CannotCompileException {
+ if (!f.where().getMethodInfo().isMethod())
+ return;
+
+ f.replace("{ $_ = $proceed($$); return $_;}");
+ }
+ });
+ fail("deadcode detection");
+ }
+ catch (javassist.CannotCompileException e) {}
+ }
+
+ public static class C6 {
+ String value;
+ int ivalue;
+ public int test() {
+ setter("foo");
+ return value.length();
+ }
+
+ public void setter(String s) {
+ value = s;
+ ivalue = s.length();
+ }
+ }
+
public void tstCtClassType() throws Exception {
ClassPool cp = ClassPool.getDefault();
CtClass cc = cp.get("javassist.CtClassType");