Browse Source

fixed JASSIST-207

tags/rel_3_19_0_ga
chibash 10 years ago
parent
commit
e5492bf606

+ 1
- 1
Readme.html View File

@@ -283,7 +283,7 @@ see javassist.Dump.

<p>-version 3.19
<ul>
<li>JIRA JASSIST-206.
<li>JIRA JASSIST-158, 206.
</ul>
</p>


+ 9
- 4
src/main/javassist/bytecode/stackmap/BasicBlock.java View File

@@ -97,6 +97,10 @@ public class BasicBlock {
sbuf.append("}");
}

/**
* A Mark indicates the position of a branch instruction
* or a branch target.
*/
static class Mark implements Comparable {
int position;
BasicBlock block;
@@ -349,10 +353,11 @@ public class BasicBlock {
}
else {
// the previous mark already has exits.
int prevPos = prev.position;
if (prevPos + prev.length < m.position) {
prev = makeBlock(prevPos + prev.length);
prev.length = m.position - prevPos;
if (prev.position + prev.length < m.position) {
// dead code is found.
prev = makeBlock(prev.position + prev.length);
blocks.add(prev);
prev.length = m.position - prev.position;
// the incoming flow from dead code is not counted
// bb.incoming++;
prev.exit = makeArray(bb);

+ 41
- 28
src/main/javassist/bytecode/stackmap/MapMaker.java View File

@@ -307,34 +307,63 @@ public class MapMaker extends Tracer {
// Phase 1.5

/*
* Javac may generate an exception handler that catches only an exception
* Javac may generate an exception handler that catches only the exception
* thrown within the handler itself. It is dead code.
* See javassist.JvstTest4.testJIRA195().
*/

private void findDeadCatchers(byte[] code, TypedBlock[] blocks) throws BadBytecode {
int len = blocks.length;
for (int i = 0; i < len; i++) {
TypedBlock block = blocks[i];
if (block.localsTypes == null) { // if block is dead code
if (!block.alreadySet()) {
fixDeadcode(code, block);
BasicBlock.Catch handler = block.toCatch;
while (handler != null)
if (handler.body == block) {
BasicBlock.Catch handler2
= new BasicBlock.Catch(block, handler.typeIndex, null);
traceException(code, handler2);
break;
if (handler != null) {
TypedBlock tb = (TypedBlock)handler.body;
if (!tb.alreadySet()) {
// tb is a handler that catches only the exceptions
// thrown from dead code.
recordStackMap(tb, handler.typeIndex);
fixDeadcode(code, tb);
tb.incoming = 1;
}
else
handler = handler.next;
}
}
}
}

private void fixDeadcode(byte[] code, TypedBlock block) throws BadBytecode {
int pos = block.position;
int len = block.length - 3;
if (len < 0) {
// if the dead-code length is shorter than 3 bytes.
if (len == -1)
code[pos] = Bytecode.NOP;

code[pos + block.length - 1] = (byte)Bytecode.ATHROW;
block.incoming = 1;
recordStackMap(block, 0);
return;
}

// if block.incomping > 0, all the incoming edges are from
// other dead code blocks. So set block.incoming to 0.
block.incoming = 0;

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 2

/*
* This method first finds strongly connected components (SCCs)
* on a graph made by TypeData by Tarjan's algorithm.
* in a TypeData graph by Tarjan's algorithm.
* SCCs are TypeData nodes sharing the same type.
* Since SCCs are found in the topologically sorted order,
* their types are also fixed when they are found.
@@ -345,9 +374,7 @@ public class MapMaker extends Tracer {
int index = 0;
for (int i = 0; i < len; i++) {
TypedBlock block = blocks[i];
if (block.localsTypes == null) // if block is dead code
fixDeadcode(code, block);
else {
if (block.alreadySet()) { // if block is not dead code
int n = block.localsTypes.length;
for (int j = 0; j < n; j++)
index = block.localsTypes[j].dfs(preOrder, index, classPool);
@@ -359,20 +386,6 @@ public class MapMaker extends Tracer {
}
}

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) {

+ 1
- 1
src/main/javassist/bytecode/stackmap/Tracer.java View File

@@ -81,7 +81,7 @@ public abstract class Tracer implements TypeTag {
return doOpcode148_201(pos, code, op);
}
catch (ArrayIndexOutOfBoundsException e) {
throw new BadBytecode("inconsistent stack height " + e.getMessage());
throw new BadBytecode("inconsistent stack height " + e.getMessage(), e);
}
}


+ 16
- 0
src/test/Test.java View File

@@ -0,0 +1,16 @@
import javassist.*;

public class Test {
public static void main(String[] args) throws Exception {
ClassPool cp = ClassPool.getDefault();
// ClassPool cp = new ClassPool();
cp.insertClassPath("./target/test-classes");
CtClass cc = cp.get("test4.JIRA207");
// cc.getClassFile().setMajorVersion(javassist.bytecode.ClassFile.JAVA_4);
CtMethod cm = cc.getDeclaredMethod("foo");
cm.insertBefore("throw new Exception();");
CtMethod cm2 = cc.getDeclaredMethod("run2");
cm2.insertBefore("throw new Exception();");
cc.writeFile();
}
}

+ 16
- 0
src/test/javassist/JvstTest4.java View File

@@ -903,4 +903,20 @@ public class JvstTest4 extends JvstTestRoot {
Object obj = make(cc.getName());
assertEquals(15, invoke(obj, "run"));
}

public void testJIRA207() throws Exception {
CtClass cc = sloader.get("test4.JIRA207");
CtMethod cm = cc.getDeclaredMethod("foo");
cm.insertBefore("throw new Exception();");

CtMethod cm2 = cc.getDeclaredMethod("run2");
cm2.insertBefore("throw new Exception();");
cc.writeFile();
Object obj = make(cc.getName());
try {
invoke(obj, "run2");
fail("run2");
}
catch (Exception e) {}
}
}

+ 9
- 11
src/test/javassist/bytecode/StackMapTest.java View File

@@ -680,18 +680,16 @@ public class StackMapTest extends TestCase {

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;
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) {}
// this will make a 1-byte dead code.
f.replace("{ $_ = $proceed($$); return $_;}");
}
});
cc.writeFile();
}

public static class C6 {

+ 51
- 0
src/test/test4/JIRA207.java View File

@@ -0,0 +1,51 @@
package test4;

public class JIRA207 {
public int run() {
int i = 3;
return foo(i);
}

public int foo(int i) {
int k = i + 3;
if (k > 0)
return k * k;
else
return k;
}

public int run2() {
int i = 0;
int p = i;
int q = p;
int r = q;
for (int k = 1; k < 3; ++k)
p += k;

for (int k = 3; k > 0; --k)
try {
foo(k);
p++;
}
finally {
p++;
}

try {
foo(p);
}
catch (RuntimeException e) {
if (p > 0)
throw e;
}

switch (p) {
case 1:
p = 100;
break;
default :
++p;
}
return p + r;
}
}

Loading…
Cancel
Save