Bug 444231: Copyinheritance of method with parameter annotations causes
AIOOBE
- fix ByteCodeTransformer
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/bytecode/BytecodeTransformer.java b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/bytecode/BytecodeTransformer.java
index 8bee433..c4e9279 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/bytecode/BytecodeTransformer.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/bytecode/BytecodeTransformer.java
@@ -230,19 +230,32 @@
// keep this offset for updating the stored value after adjustTail():
int copyInhSrcLineOffsetOffset;
// first phase of adjustment (method prefix and attributes except code):
+ ConstantPoolSimpleConverter conv = constantPoolOffsets == null
+ ? ConstantPoolSimpleConverter.create(srcRole, srcMethodBinding, methodCode, classFile)
+ : new ConstantPoolSimpleConverter(srcConstantPool, constantPoolOffsets, offset, methodCode, classFile);
+
+ conv.updateName(codeAttributeOffset-offset);
+
+ byte[][] varDest = new byte[][]{methodCode};
+ boolean isAddingMarkerArg = !TSuperHelper.isTSuper(srcMethodBinding) && dstMethod.isTSuper;
copyInhSrcLineOffsetOffset = copyAdjustStructure(
classFile,
- constantPoolOffsets == null
- ? ConstantPoolSimpleConverter.create(srcRole, srcMethodBinding, methodCode, classFile)
- : new ConstantPoolSimpleConverter(srcConstantPool, constantPoolOffsets, offset, methodCode, classFile),
- srcConstantPool, offset, methodCode,
+ conv,
+ srcConstantPool, offset, varDest,
dstMethod.binding,
- totalLen);
+ totalLen,
+ isAddingMarkerArg);
+ int inc = varDest[0].length - methodCode.length;
+ tailOffset += inc;
+ totalLen += inc;
+ codeAttributeOffset += inc;
+ methodCode = varDest[0];
codeAttributeOffset -= offset; // now relative to methodCode
tailOffset -= offset;
if (copyInhSrcLineOffsetOffset == -1) {
+ // TODO: consider inserting this attribute during copyAdjustStructure()
// CopyInheritanceSrc added when copying a method for the first time
byte[] extraAttr = generateCpInhSrc(dstMethod.model, classFile);
@@ -346,7 +359,7 @@
* @param conv converter for mapping strings to the new constantpool
* @param src bytes to copy from
* @param srcOffset offset into src
- * @param dest bytes to copy into
+ * @param varDest bytes to copy into -- 0-cell array of byte[] to mimic an in-out param
* @param dstMethod
* @param expectedLen number of bytes to be adjusted (for sanity checking only)
* @return if a CopyInheritanceSrc Attribute is already present return the offset where the lineOffset is stored, -1 otherwise
@@ -354,15 +367,18 @@
private int copyAdjustStructure(
ClassFile classFile,
ConstantPoolSimpleConverter conv,
- byte[] src, int srcOffset, byte[] dest,
+ byte[] src, int srcOffset, byte[][] varDest,
MethodBinding dstMethod,
- int expectedLen)
+ int expectedLen,
+ boolean isAddingMarkerArg)
{
+ byte[] dest = varDest[0];
conv.updateName(2); // method name
conv.writeName(4, dstMethod.signature(classFile)); // method signature
int attributesCount = OTByteCodes.getWord(dest, 6);
int offset = METHOD_PREFIX_LEN;
+ int destOff = 0; // additional offset when inserting more bytes into dest
int copyInhSrcLineOffsetOffset = -1;
@@ -381,7 +397,7 @@
int ref = OTByteCodes.getWord(src, srcOffset+offset);
ConstantPoolObject cpo = this._reader.readConstantPoolObject(ref, 2);
cpo = this._mapper.mapConstantPoolObject(cpo);
- this._writer.writeConstantPoolObject(dest, offset, 2, cpo);
+ this._writer.writeConstantPoolObject(dest, offset+destOff, 2, cpo);
offset+=2;
}
}
@@ -416,7 +432,29 @@
int annotCount = OTByteCodes.getWord(src, srcOffset+offset);
offset+=2;
for (int j=0; j<annotCount; j++)
- offset = adjustAnnotation(conv, src, srcOffset, offset);
+ offset = adjustAnnotation(conv, src, srcOffset, offset);
+ } else if (CharOperation.equals(attrName, RuntimeInvisibleParameterAnnotationsName)
+ || CharOperation.equals(attrName, RuntimeVisibleParameterAnnotationsName))
+ {
+ if (isAddingMarkerArg) {
+ OTByteCodes.setInt(dest, offset+destOff-4, attrLen+2); // grow attr by 2
+
+ int paramCount = OTByteCodes.getUnsignedByte(src, srcOffset+offset);
+ dest[offset+destOff] = (byte)(paramCount+1); // grow paramCount by 1
+ offset++;
+
+ for (int p=0; p<paramCount; p++) { // copy-adjust annotations
+ int annotCount = OTByteCodes.getWord(src, srcOffset+offset);
+ offset+=2;
+ for (int j=0; j<annotCount; j++)
+ offset = adjustAnnotation(conv, src, srcOffset, offset+destOff);
+ }
+ dest = OTByteCodes.insertWord(dest, offset+destOff, 0); // add a "0" entry
+ varDest[0] = dest;
+ destOff += 2;
+ } else {
+ offset += attrLen;
+ }
} else {
offset += attrLen;
}
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/bytecode/OTByteCodes.java b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/bytecode/OTByteCodes.java
index 106b53c..75f3533 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/bytecode/OTByteCodes.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/objectteams/otdt/internal/core/compiler/bytecode/OTByteCodes.java
@@ -217,6 +217,15 @@
code[offset++] = (byte)value;
}
+ public static byte[] insertWord(byte[] code, int idx, int value) {
+ byte[] result = new byte[code.length+2];
+ System.arraycopy(code, 0, result, 0, idx);
+ result[idx] = (byte)(value >> 8);
+ result[idx+1] = (byte)value;
+ System.arraycopy(code, idx, result, idx+2, code.length-idx);
+ return result;
+ }
+
/**
* Reference in big endian order.
**/
diff --git a/testplugins/org.eclipse.objectteams.otdt.tests/otjld/org/eclipse/objectteams/otdt/tests/otjld/other/OTNullAnnotationTest.java b/testplugins/org.eclipse.objectteams.otdt.tests/otjld/org/eclipse/objectteams/otdt/tests/otjld/other/OTNullAnnotationTest.java
index 8430dcb..ff86047 100644
--- a/testplugins/org.eclipse.objectteams.otdt.tests/otjld/org/eclipse/objectteams/otdt/tests/otjld/other/OTNullAnnotationTest.java
+++ b/testplugins/org.eclipse.objectteams.otdt.tests/otjld/org/eclipse/objectteams/otdt/tests/otjld/other/OTNullAnnotationTest.java
@@ -17,6 +17,9 @@
import junit.framework.Test;
+import java.util.Map;
+
+import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.eclipse.objectteams.otdt.tests.otjld.AbstractOTJLDNullAnnotationTest;
@@ -72,7 +75,9 @@
public void testBug444231() {
if (this.complianceLevel >= ClassFileConstants.JDK1_8) return; // not ready for type annotations, yet
- runNegativeTestWithLibs(
+ Map<String,String> options = getCompilerOptions();
+ options.put(JavaCore.COMPILER_PB_FATAL_OPTIONAL_ERROR, JavaCore.DISABLED);
+ runConformTestWithLibs(
new String[] {
"b/Base444231.java",
"package b;\n" +
@@ -89,6 +94,16 @@
"p/Team444231Sub.java",
"package p;\n" +
"public team class Team444231Sub extends Team444231Super {\n" +
+ "}\n"
+ },
+ options,
+ "");
+ runNegativeTestWithLibs(
+ new String[] {
+ "p/Team444231SubSub.java",
+ "package p;\n" +
+ "import p.Team444231Sub;\n" +
+ "public team class Team444231SubSub extends Team444231Sub {\n" +
" void test() {\n" +
" String val = null;\n" +
" new R(val);\n" +