Commit d6e00c1e authored by Eric Bruneton's avatar Eric Bruneton

Remove the workaround introduced for synthetic parameters.

A workaround was added in 4accca37 for issue #307392. The root cause of the bug was that, via a ClassReader->ClassWriter transform, the number of parameter annotations was not preserved (the number read in ClassReader was ignored, and it was recomputed from the descriptor in MethodWriter).

The workaround added at this time was fixing that, and it was also attempting to report parameter indices corresponding to the source parameters, assuming that the implicit parameters were at added at the begining. However, synthetic parameters can also be added at the end (see issue #317788), so the second part of the above workaround does not work.

This change removes this workaround, and replaces it with a method to preserve the num_parameters value read in ClassReader (via a sentinel annotation). In other words, this change still fixes the root cause of #307392, but no longer attempts to map bytecode parameter indices to source level parameter indices. We believe there is no universal method for doing that, but users can implement their own method, if desired, on top of the ASM API. Indeed, the JVMS spec states that (https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.18):

BEGIN QUOTE
The i'th entry in the parameter_annotations table may, but is not required to, correspond to the i'th parameter descriptor in the method descriptor (§4.3.3).

For example, a compiler may choose to create entries in the table corresponding only to those parameter descriptors which represent explicitly declared parameters in source code. In the Java programming language, a constructor of an inner class is specified to have an implicitly declared parameter before its explicitly declared parameters (JLS §8.8.1), so the corresponding <init> method in a class file has a parameter descriptor representing the implicitly declared parameter before any parameter descriptors representing explicitly declared parameters. If the first explicitly declared parameter is annotated in source code, then a compiler may create parameter_annotations[0] to store annotations corresponding to the second parameter descriptor.
END QUOTE
parent 19aa8886
......@@ -261,16 +261,16 @@ final class AnnotationWriter extends AnnotationVisitor {
* Puts the given annotation lists into the given byte vector.
*
* @param panns an array of annotation writer lists.
* @param off index of the first annotation to be written.
* @param npanns number of annotations to put, i.e. annotations [0,npanns[ are put.
* @param out where the annotations must be put.
*/
static void put(final AnnotationWriter[] panns, final int off, final ByteVector out) {
int size = 1 + 2 * (panns.length - off);
for (int i = off; i < panns.length; ++i) {
static void put(final AnnotationWriter[] panns, final int npanns, final ByteVector out) {
int size = 1 + 2 * npanns;
for (int i = 0; i < npanns; ++i) {
size += panns[i] == null ? 0 : panns[i].getSize();
}
out.putInt(size).putByte(panns.length - off);
for (int i = off; i < panns.length; ++i) {
out.putInt(size).putByte(npanns);
for (int i = 0; i < npanns; ++i) {
AnnotationWriter aw = panns[i];
AnnotationWriter last = null;
int n = 0;
......
......@@ -1865,25 +1865,20 @@ public class ClassReader {
final MethodVisitor mv, final Context context, int v, final boolean visible) {
int i;
int n = b[v++] & 0xFF;
// workaround for a bug in javac (javac compiler generates a parameter
// annotation array whose size is equal to the number of parameters in
// the Java source file, while it should generate an array whose size is
// equal to the number of parameters in the method descriptor - which
// includes the synthetic parameters added by the compiler). This work-
// around supposes that the synthetic parameters are the first ones.
int synthetics = Type.getArgumentTypes(context.desc).length - n;
AnnotationVisitor av;
for (i = 0; i < synthetics; ++i) {
// virtual annotation to detect synthetic parameters in MethodWriter
av = mv.visitParameterAnnotation(i, "Ljava/lang/Synthetic;", false);
if (av != null) {
av.visitEnd();
}
}
char[] c = context.buffer;
for (; i < n + synthetics; ++i) {
for (i = 0; i < n; ++i) {
int j = readUnsignedShort(v);
v += 2;
// If the last parameter does not have any annotation, add a virtual, sentinel annotation,
// so that we can always recompute n in MethodWriter (from the maximum index of all parameter
// annotations).
if (j == 0 && i == n - 1) {
av = mv.visitParameterAnnotation(i, "Ljava/lang/Synthetic;", false);
if (av != null) {
av.visitEnd();
}
}
for (; j > 0; --j) {
av = mv.visitParameterAnnotation(i, readUTF8(v, c), visible);
v = readAnnotationValues(v + 2, c, true, av);
......
......@@ -177,8 +177,8 @@ class MethodWriter extends MethodVisitor {
/** The runtime invisible parameter annotations of this method. May be <tt>null</tt>. */
private AnnotationWriter[] ipanns;
/** The number of synthetic parameters of this method. */
private int synthetics;
/** The maximum parameter annotation index, plus 1. */
private int npanns;
/** The non standard attributes of the method. */
private Attribute attrs;
......@@ -439,11 +439,10 @@ class MethodWriter extends MethodVisitor {
@Override
public AnnotationVisitor visitParameterAnnotation(
final int parameter, final String desc, final boolean visible) {
npanns = Math.max(npanns, parameter + 1);
ByteVector bv = new ByteVector();
if ("Ljava/lang/Synthetic;".equals(desc)) {
// workaround for a bug in javac with synthetic parameters
// see ClassReader.readParameterAnnotations
synthetics = Math.max(synthetics, parameter + 1);
// discard this virtual, sentinel annotation, only used to be able to compute npanns
return new AnnotationWriter(cw, false, bv, null, 0);
}
// write type, and reserve space for values count
......@@ -2003,15 +2002,15 @@ class MethodWriter extends MethodVisitor {
}
if (panns != null) {
cw.newUTF8("RuntimeVisibleParameterAnnotations");
size += 7 + 2 * (panns.length - synthetics);
for (int i = panns.length - 1; i >= synthetics; --i) {
size += 7 + 2 * npanns;
for (int i = npanns - 1; i >= 0; --i) {
size += panns[i] == null ? 0 : panns[i].getSize();
}
}
if (ipanns != null) {
cw.newUTF8("RuntimeInvisibleParameterAnnotations");
size += 7 + 2 * (ipanns.length - synthetics);
for (int i = ipanns.length - 1; i >= synthetics; --i) {
size += 7 + 2 * npanns;
for (int i = npanns - 1; i >= 0; --i) {
size += ipanns[i] == null ? 0 : ipanns[i].getSize();
}
}
......@@ -2215,11 +2214,11 @@ class MethodWriter extends MethodVisitor {
}
if (panns != null) {
out.putShort(cw.newUTF8("RuntimeVisibleParameterAnnotations"));
AnnotationWriter.put(panns, synthetics, out);
AnnotationWriter.put(panns, npanns, out);
}
if (ipanns != null) {
out.putShort(cw.newUTF8("RuntimeInvisibleParameterAnnotations"));
AnnotationWriter.put(ipanns, synthetics, out);
AnnotationWriter.put(ipanns, npanns, out);
}
if (attrs != null) {
attrs.put(cw, null, 0, -1, -1, out);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment