--- a/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java Fri Oct 16 12:56:50 2009 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java Mon Oct 19 13:38:09 2009 -0700
@@ -29,6 +29,7 @@
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.CharBuffer;
+import java.util.Arrays;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Map;
@@ -191,6 +192,16 @@
*/
boolean debugJSR308;
+ /** A table to hold the constant pool indices for method parameter
+ * names, as given in LocalVariableTable attributes.
+ */
+ int[] parameterNameIndices;
+
+ /**
+ * Whether or not any parameter names have been found.
+ */
+ boolean haveParameterNameIndices;
+
/** Get the ClassReader instance for this invocation. */
public static ClassReader instance(Context context) {
ClassReader instance = context.get(classReaderKey);
@@ -922,32 +933,33 @@
void read(Symbol sym, int attrLen) {
int newbp = bp + attrLen;
if (saveParameterNames) {
- // pick up parameter names from the variable table
- List<Name> parameterNames = List.nil();
- int firstParam = ((sym.flags() & STATIC) == 0) ? 1 : 0;
- int endParam = firstParam + Code.width(sym.type.getParameterTypes());
+ // Pick up parameter names from the variable table.
+ // Parameter names are not explicitly identified as such,
+ // but all parameter name entries in the LocalVariableTable
+ // have a start_pc of 0. Therefore, we record the name
+ // indicies of all slots with a start_pc of zero in the
+ // parameterNameIndicies array.
+ // Note that this implicitly honors the JVMS spec that
+ // there may be more than one LocalVariableTable, and that
+ // there is no specified ordering for the entries.
int numEntries = nextChar();
- for (int i=0; i<numEntries; i++) {
+ for (int i = 0; i < numEntries; i++) {
int start_pc = nextChar();
int length = nextChar();
int nameIndex = nextChar();
int sigIndex = nextChar();
int register = nextChar();
- if (start_pc == 0 &&
- firstParam <= register &&
- register < endParam) {
- int index = firstParam;
- for (Type t : sym.type.getParameterTypes()) {
- if (index == register) {
- parameterNames = parameterNames.prepend(readName(nameIndex));
- break;
- }
- index += Code.width(t);
+ if (start_pc == 0) {
+ // ensure array large enough
+ if (register >= parameterNameIndices.length) {
+ int newSize = Math.max(register, parameterNameIndices.length + 8);
+ parameterNameIndices =
+ Arrays.copyOf(parameterNameIndices, newSize);
}
+ parameterNameIndices[register] = nameIndex;
+ haveParameterNameIndices = true;
}
}
- parameterNames = parameterNames.reverse();
- ((MethodSymbol)sym).savedParameterNames = parameterNames;
}
bp = newbp;
}
@@ -1839,6 +1851,8 @@
syms.methodClass);
}
MethodSymbol m = new MethodSymbol(flags, name, type, currentOwner);
+ if (saveParameterNames)
+ initParameterNames(m);
Symbol prevOwner = currentOwner;
currentOwner = m;
try {
@@ -1846,9 +1860,90 @@
} finally {
currentOwner = prevOwner;
}
+ if (saveParameterNames)
+ setParameterNames(m, type);
return m;
}
+ /**
+ * Init the parameter names array.
+ * Parameter names are currently inferred from the names in the
+ * LocalVariableTable attributes of a Code attribute.
+ * (Note: this means parameter names are currently not available for
+ * methods without a Code attribute.)
+ * This method initializes an array in which to store the name indexes
+ * of parameter names found in LocalVariableTable attributes. It is
+ * slightly supersized to allow for additional slots with a start_pc of 0.
+ */
+ void initParameterNames(MethodSymbol sym) {
+ // make allowance for synthetic parameters.
+ final int excessSlots = 4;
+ int expectedParameterSlots =
+ Code.width(sym.type.getParameterTypes()) + excessSlots;
+ if (parameterNameIndices == null
+ || parameterNameIndices.length < expectedParameterSlots) {
+ parameterNameIndices = new int[expectedParameterSlots];
+ } else
+ Arrays.fill(parameterNameIndices, 0);
+ haveParameterNameIndices = false;
+ }
+
+ /**
+ * Set the parameter names for a symbol from the name index in the
+ * parameterNameIndicies array. The type of the symbol may have changed
+ * while reading the method attributes (see the Signature attribute).
+ * This may be because of generic information or because anonymous
+ * synthetic parameters were added. The original type (as read from
+ * the method descriptor) is used to help guess the existence of
+ * anonymous synthetic parameters.
+ * On completion, sym.savedParameter names will either be null (if
+ * no parameter names were found in the class file) or will be set to a
+ * list of names, one per entry in sym.type.getParameterTypes, with
+ * any missing names represented by the empty name.
+ */
+ void setParameterNames(MethodSymbol sym, Type jvmType) {
+ // if no names were found in the class file, there's nothing more to do
+ if (!haveParameterNameIndices)
+ return;
+
+ int firstParam = ((sym.flags() & STATIC) == 0) ? 1 : 0;
+ // the code in readMethod may have skipped the first parameter when
+ // setting up the MethodType. If so, we make a corresponding allowance
+ // here for the position of the first parameter. Note that this
+ // assumes the skipped parameter has a width of 1 -- i.e. it is not
+ // a double width type (long or double.)
+ if (sym.name == names.init && currentOwner.hasOuterInstance()) {
+ // Sometimes anonymous classes don't have an outer
+ // instance, however, there is no reliable way to tell so
+ // we never strip this$n
+ if (!currentOwner.name.isEmpty())
+ firstParam += 1;
+ }
+
+ if (sym.type != jvmType) {
+ // reading the method attributes has caused the symbol's type to
+ // be changed. (i.e. the Signature attribute.) This may happen if
+ // there are hidden (synthetic) parameters in the descriptor, but
+ // not in the Signature. The position of these hidden parameters
+ // is unspecified; for now, assume they are at the beginning, and
+ // so skip over them. The primary case for this is two hidden
+ // parameters passed into Enum constructors.
+ int skip = Code.width(jvmType.getParameterTypes())
+ - Code.width(sym.type.getParameterTypes());
+ firstParam += skip;
+ }
+ List<Name> paramNames = List.nil();
+ int index = firstParam;
+ for (Type t: sym.type.getParameterTypes()) {
+ int nameIdx = (index < parameterNameIndices.length
+ ? parameterNameIndices[index] : 0);
+ Name name = nameIdx == 0 ? names.empty : readName(nameIdx);
+ paramNames = paramNames.prepend(name);
+ index += Code.width(t);
+ }
+ sym.savedParameterNames = paramNames.reverse();
+ }
+
/** Skip a field or method
*/
void skipMember() {