From: chiba Date: Tue, 27 Jul 2004 09:45:50 +0000 (+0000) Subject: fixed Bugs item #997458: addCatch("return;", ...) on CtConstructor causes VerifyError X-Git-Tag: rel_3_17_1_ga~495 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=af2793e73182bb4f61084d97a62852c6c155dac2;p=javassist.git fixed Bugs item #997458: addCatch("return;", ...) on CtConstructor causes VerifyError implemented CtBehavior#addLocalVariable() git-svn-id: http://anonsvn.jboss.org/repos/javassist/trunk@118 30ef5769-5b8d-40dd-aea6-55b5d6557bb3 --- diff --git a/src/main/javassist/CtBehavior.java b/src/main/javassist/CtBehavior.java index 01f907cf..0ed161de 100644 --- a/src/main/javassist/CtBehavior.java +++ b/src/main/javassist/CtBehavior.java @@ -299,6 +299,40 @@ public abstract class CtBehavior extends CtMember { } } + /** + * Declares a new local variable. The scope of this variable is the + * whole method body. The initial value of that variable is not set. + * The declared variable can be accessed in the code snippet inserted + * by insertBefore(), insertAfter(), etc. + * + * @param name the name of the variable + * @param type the type of the variable + * @see #insertBefore(String) + * @see #insertAfter(String) + */ + public void addLocalVariable(String name, CtClass type) + throws CannotCompileException + { + declaringClass.checkModify(); + ConstPool cp = methodInfo.getConstPool(); + CodeAttribute ca = methodInfo.getCodeAttribute(); + if (ca == null) + throw new CannotCompileException("no method body"); + + LocalVariableAttribute va = (LocalVariableAttribute)ca.getAttribute( + LocalVariableAttribute.tag); + if (va == null) { + va = new LocalVariableAttribute(cp); + ca.getAttributes().add(va); + } + + int maxLocals = ca.getMaxLocals(); + String desc = Descriptor.of(type); + va.addEntry(0, ca.getCodeLength(), + cp.addUtf8Info(name), cp.addUtf8Info(desc), maxLocals); + ca.setMaxLocals(maxLocals + Descriptor.dataSize(desc)); + } + /** * Modifies the method/constructor body. * @@ -357,6 +391,7 @@ public abstract class CtBehavior extends CtMember { int nvars = jv.recordParams(getParameterTypes(), Modifier.isStatic(getModifiers())); jv.recordParamNames(ca, nvars); + jv.recordLocalVariables(ca, 0); jv.compileStmnt(src); Bytecode b = jv.getBytecode(); int stack = b.getMaxStack(); @@ -426,6 +461,7 @@ public abstract class CtBehavior extends CtMember { jv.recordParamNames(ca, nvars); CtClass rtype = getReturnType0(); int varNo = jv.recordReturnType(rtype, true); + jv.recordLocalVariables(ca, 0); int handlerLen = insertAfterHandler(asFinally, b, rtype, varNo); @@ -675,7 +711,7 @@ public abstract class CtBehavior extends CtMember { int len = iterator.getCodeLength(); int pos = iterator.append(b.get()); - ca.getExceptionTable().add(0, len, len, + ca.getExceptionTable().add(getStartPosOfBody(ca), len, len, cp.addClassInfo(exceptionType)); iterator.append(b.getExceptionTable(), pos); } @@ -687,6 +723,12 @@ public abstract class CtBehavior extends CtMember { } } + /* CtConstructor overrides this method. + */ + int getStartPosOfBody(CodeAttribute ca) throws CannotCompileException { + return 0; + } + /** * Inserts bytecode at the specified line in the body. * It is equivalent to: diff --git a/src/main/javassist/CtConstructor.java b/src/main/javassist/CtConstructor.java index e294ca51..72dcee11 100644 --- a/src/main/javassist/CtConstructor.java +++ b/src/main/javassist/CtConstructor.java @@ -284,4 +284,18 @@ public final class CtConstructor extends CtBehavior { throw new CannotCompileException(e); } } + + /* This method is called by addCatch() in CtBehavior. + * super() and this() must not be in a try statement. + */ + int getStartPosOfBody(CodeAttribute ca) throws CannotCompileException { + CodeIterator ci = ca.iterator(); + try { + ci.skipConstructor(); + return ci.next(); + } + catch (BadBytecode e) { + throw new CannotCompileException(e); + } + } } diff --git a/src/main/javassist/bytecode/LocalVariableAttribute.java b/src/main/javassist/bytecode/LocalVariableAttribute.java index a88dfac7..ab66f676 100644 --- a/src/main/javassist/bytecode/LocalVariableAttribute.java +++ b/src/main/javassist/bytecode/LocalVariableAttribute.java @@ -34,6 +34,14 @@ public class LocalVariableAttribute extends AttributeInfo { */ public static final String typeTag = "LocalVariableTypeTable"; + /** + * Constructs an empty LocalVariableTable. + */ + public LocalVariableAttribute(ConstPool cp) { + super(cp, tag, new byte[2]); + ByteArray.write16bit(0, info, 0); + } + LocalVariableAttribute(ConstPool cp, int n, DataInputStream in) throws IOException { @@ -44,6 +52,31 @@ public class LocalVariableAttribute extends AttributeInfo { super(cp, tag, i); } + /** + * Appends a new entry to local_variable_table. + * + * @param startPc start_pc + * @param length length + * @param nameIndex name_index + * @param descriptorIndex descriptor_index + * @param index index + */ + public void addEntry(int startPc, int length, int nameIndex, + int descriptorIndex, int index) { + int size = info.length; + byte[] newInfo = new byte[size + 10]; + ByteArray.write16bit(tableLength() + 1, newInfo, 0); + for (int i = 2; i < size; ++i) + newInfo[i] = info[i]; + + ByteArray.write16bit(startPc, newInfo, size); + ByteArray.write16bit(length, newInfo, size + 2); + ByteArray.write16bit(nameIndex, newInfo, size + 4); + ByteArray.write16bit(descriptorIndex, newInfo, size + 6); + ByteArray.write16bit(index, newInfo, size + 8); + info = newInfo; + } + /** * Returns local_variable_table_length. * This represents the number of entries in the table. @@ -83,7 +116,10 @@ public class LocalVariableAttribute extends AttributeInfo { int pos = i * 10 + 2; int pc = ByteArray.readU16bit(info, pos); int len = ByteArray.readU16bit(info, pos + 2); - if (pc > where || (exclusive && pc == where)) + + /* if pc == 0, then the local variable is a method parameter. + */ + if (pc > where || (exclusive && pc == where && pc != 0)) ByteArray.write16bit(pc + gapLength, info, pos); else if (pc + len > where) ByteArray.write16bit(len + gapLength, info, pos + 2);