}
}
+ /**
+ * 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 <code>insertBefore()</code>, <code>insertAfter()</code>, 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.
*
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();
jv.recordParamNames(ca, nvars);
CtClass rtype = getReturnType0();
int varNo = jv.recordReturnType(rtype, true);
+ jv.recordLocalVariables(ca, 0);
int handlerLen = insertAfterHandler(asFinally, b, rtype, varNo);
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);
}
}
}
+ /* 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:
*/
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
{
super(cp, tag, i);
}
+ /**
+ * Appends a new entry to <code>local_variable_table</code>.
+ *
+ * @param startPc <code>start_pc</code>
+ * @param length <code>length</code>
+ * @param nameIndex <code>name_index</code>
+ * @param descriptorIndex <code>descriptor_index</code>
+ * @param index <code>index</code>
+ */
+ 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 <code>local_variable_table_length</code>.
* This represents the number of entries in the table.
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);