Method from com.sun.tools.javac.jvm.ClassReader Detail: |
long adjustClassFlags(long flags) {
return flags & ~ACC_SUPER; // SUPER and SYNCHRONIZED bits overloaded
}
|
long adjustFieldFlags(long flags) {
return flags;
}
Adjusting flags
*************************************************************** |
long adjustMethodFlags(long flags) {
if ((flags & ACC_BRIDGE) != 0) {
flags &= ~ACC_BRIDGE;
flags |= BRIDGE;
if (!allowGenerics)
flags &= ~SYNTHETIC;
}
if ((flags & ACC_VARARGS) != 0) {
flags &= ~ACC_VARARGS;
flags |= VARARGS;
}
return flags;
}
|
void attachAnnotationDefault(Symbol sym) {
final MethodSymbol meth = (MethodSymbol)sym; // only on methods
final Attribute value = readAttributeValue();
annotate.later(new AnnotationDefaultCompleter(meth, value));
}
Attach the default value for an annotation element. |
void attachAnnotations(Symbol sym) {
int numAttributes = nextChar();
if (numAttributes != 0) {
ListBuffer< CompoundAnnotationProxy > proxies =
new ListBuffer< CompoundAnnotationProxy >();
for (int i = 0; i< numAttributes; i++) {
CompoundAnnotationProxy proxy = readCompoundAnnotation();
if (proxy.type.tsym == syms.proprietaryType.tsym)
sym.flags_field |= PROPRIETARY;
else
proxies.append(proxy);
if (majorVersion >= V51.major &&
proxy.type.tsym == syms.polymorphicSignatureType.tsym) {
sym.flags_field |= POLYMORPHIC_SIGNATURE;
}
}
annotate.later(new AnnotationCompleter(sym, proxies.toList()));
}
}
|
void attachParameterAnnotations(Symbol method) {
final MethodSymbol meth = (MethodSymbol)method;
int numParameters = buf[bp++] & 0xFF;
List< VarSymbol > parameters = meth.params();
int pnum = 0;
while (parameters.tail != null) {
attachAnnotations(parameters.head);
parameters = parameters.tail;
pnum++;
}
if (pnum != numParameters) {
throw badClassFile("bad.runtime.invisible.param.annotations", meth);
}
}
Attach parameter annotations. |
public BadClassFile badClassFile(String key,
Object args) {
return new BadClassFile (
currentOwner.enclClass(),
currentClassFile,
diagFactory.fragment(key, args));
}
|
Type classSigToType() {
if (signature[sigp] != 'L')
throw badClassFile("bad.class.signature",
Convert.utf2string(signature, sigp, 10));
sigp++;
Type outer = Type.noType;
int startSbp = sbp;
while (true) {
final byte c = signature[sigp++];
switch (c) {
case ';': { // end
ClassSymbol t = enterClass(names.fromUtf(signatureBuffer,
startSbp,
sbp - startSbp));
if (outer == Type.noType)
outer = t.erasure(types);
else
outer = new ClassType(outer, List.< Type >nil(), t);
sbp = startSbp;
return outer;
}
case '< ': // generic arguments
ClassSymbol t = enterClass(names.fromUtf(signatureBuffer,
startSbp,
sbp - startSbp));
outer = new ClassType(outer, sigToTypes(' >'), t) {
boolean completed = false;
@Override
public Type getEnclosingType() {
if (!completed) {
completed = true;
tsym.complete();
Type enclosingType = tsym.type.getEnclosingType();
if (enclosingType != Type.noType) {
List< Type > typeArgs =
super.getEnclosingType().allparams();
List< Type > typeParams =
enclosingType.allparams();
if (typeParams.length() != typeArgs.length()) {
// no "rare" types
super.setEnclosingType(types.erasure(enclosingType));
} else {
super.setEnclosingType(types.subst(enclosingType,
typeParams,
typeArgs));
}
} else {
super.setEnclosingType(Type.noType);
}
}
return super.getEnclosingType();
}
@Override
public void setEnclosingType(Type outer) {
throw new UnsupportedOperationException();
}
};
switch (signature[sigp++]) {
case ';':
if (sigp < signature.length && signature[sigp] == '.') {
// support old-style GJC signatures
// The signature produced was
// Lfoo/Outer< Lfoo/X; >;.Lfoo/Outer$Inner< Lfoo/Y; >;
// rather than say
// Lfoo/Outer< Lfoo/X; >.Inner< Lfoo/Y; >;
// so we skip past ".Lfoo/Outer$"
sigp += (sbp - startSbp) + // "foo/Outer"
3; // ".L" and "$"
signatureBuffer[sbp++] = (byte)'$';
break;
} else {
sbp = startSbp;
return outer;
}
case '.':
signatureBuffer[sbp++] = (byte)'$';
break;
default:
throw new AssertionError(signature[sigp-1]);
}
continue;
case '.':
signatureBuffer[sbp++] = (byte)'$';
continue;
case '/':
signatureBuffer[sbp++] = (byte)'.';
continue;
default:
signatureBuffer[sbp++] = c;
continue;
}
}
}
Convert class signature to type, where signature is implicit. |
public void complete(Symbol sym) throws CompletionFailure {
if (sym.kind == TYP) {
ClassSymbol c = (ClassSymbol)sym;
c.members_field = new Scope.ErrorScope(c); // make sure it's always defined
boolean saveSuppressFlush = suppressFlush;
suppressFlush = true;
try {
completeOwners(c.owner);
completeEnclosing(c);
} finally {
suppressFlush = saveSuppressFlush;
}
fillIn(c);
} else if (sym.kind == PCK) {
PackageSymbol p = (PackageSymbol)sym;
try {
fillIn(p);
} catch (IOException ex) {
throw new CompletionFailure(sym, ex.getLocalizedMessage()).initCause(ex);
}
}
if (!filling && !suppressFlush)
annotate.flush(); // finish attaching annotations
}
Completion for classes to be loaded. Before a class is loaded
we make sure its enclosing class (if any) is loaded. |
public ClassSymbol defineClass(Name name,
Symbol owner) {
ClassSymbol c = new ClassSymbol(0, name, owner);
if (owner.kind == PCK)
Assert.checkNull(classes.get(c.flatname), c);
c.completer = this;
return c;
}
Define a new class given its name and owner. |
public ClassSymbol enterClass(Name flatname) {
ClassSymbol c = classes.get(flatname);
if (c == null)
return enterClass(flatname, (JavaFileObject)null);
else
return c;
}
Create a new member or toplevel class symbol with given flat name
and enter in `classes' unless already there. |
public ClassSymbol enterClass(Name name,
TypeSymbol owner) {
Name flatname = TypeSymbol.formFlatName(name, owner);
ClassSymbol c = classes.get(flatname);
if (c == null) {
c = defineClass(name, owner);
classes.put(flatname, c);
} else if ((c.name != name || c.owner != owner) && owner.kind == TYP && c.owner.kind == PCK) {
// reassign fields of classes that might have been loaded with
// their flat names.
c.owner.members().remove(c);
c.name = name;
c.owner = owner;
c.fullname = ClassSymbol.formFullName(name, owner);
}
return c;
}
Create a new toplevel or member class symbol with given name
and owner and enter in `classes' unless already there. |
public ClassSymbol enterClass(Name flatName,
JavaFileObject classFile) {
ClassSymbol cs = classes.get(flatName);
if (cs != null) {
String msg = Log.format("%s: completer = %s; class file = %s; source file = %s",
cs.fullname,
cs.completer,
cs.classfile,
cs.sourcefile);
throw new AssertionError(msg);
}
Name packageName = Convert.packagePart(flatName);
PackageSymbol owner = packageName.isEmpty()
? syms.unnamedPackage
: enterPackage(packageName);
cs = defineClass(Convert.shortName(flatName), owner);
cs.classfile = classFile;
classes.put(flatName, cs);
return cs;
}
Creates a new toplevel class symbol with given flat name and
given class (or source) file. |
public PackageSymbol enterPackage(Name fullname) {
PackageSymbol p = packages.get(fullname);
if (p == null) {
Assert.check(!fullname.isEmpty(), "rootPackage missing!");
p = new PackageSymbol(
Convert.shortName(fullname),
enterPackage(Convert.packagePart(fullname)));
p.completer = this;
packages.put(fullname, p);
}
return p;
}
Make a package, given its fully qualified name. |
public PackageSymbol enterPackage(Name name,
PackageSymbol owner) {
return enterPackage(TypeSymbol.formFullName(name, owner));
}
Make a package, given its unqualified name and enclosing package. |
protected void enterTypevars(Type t) {
if (t.getEnclosingType() != null && t.getEnclosingType().tag == CLASS)
enterTypevars(t.getEnclosingType());
for (List< Type > xs = t.getTypeArguments(); xs.nonEmpty(); xs = xs.tail)
typevars.enter(xs.head.tsym);
}
Enter type variables of this classtype and all enclosing ones in
`typevars'. |
protected void enterTypevars(Symbol sym) {
if (sym.owner.kind == MTH) {
enterTypevars(sym.owner);
enterTypevars(sym.owner.owner);
}
enterTypevars(sym.type);
}
|
protected void extraFileActions(PackageSymbol pack,
JavaFileObject fe) {
}
this is used to support javadoc |
Type findTypeVar(Name name) {
Scope.Entry e = typevars.lookup(name);
if (e.scope != null) {
return e.sym.type;
} else {
if (readingClassAttr) {
// While reading the class attribute, the supertypes
// might refer to a type variable from an enclosing element
// (method or class).
// If the type variable is defined in the enclosing class,
// we can actually find it in
// currentOwner.owner.type.getTypeArguments()
// However, until we have read the enclosing method attribute
// we don't know for sure if this owner is correct. It could
// be a method and there is no way to tell before reading the
// enclosing method attribute.
TypeVar t = new TypeVar(name, currentOwner, syms.botType);
missingTypeVariables = missingTypeVariables.prepend(t);
// System.err.println("Missing type var " + name);
return t;
}
throw badClassFile("undecl.type.var", name);
}
}
Find type variable with given name in `typevars' scope. |
char getChar(int bp) {
return
(char)(((buf[bp] & 0xFF) < < 8) + (buf[bp+1] & 0xFF));
}
Extract a character at position bp from buf. |
double getDouble(int bp) {
DataInputStream bufin =
new DataInputStream(new ByteArrayInputStream(buf, bp, 8));
try {
return bufin.readDouble();
} catch (IOException e) {
throw new AssertionError(e);
}
}
Extract a double at position bp from buf. |
float getFloat(int bp) {
DataInputStream bufin =
new DataInputStream(new ByteArrayInputStream(buf, bp, 4));
try {
return bufin.readFloat();
} catch (IOException e) {
throw new AssertionError(e);
}
}
Extract a float at position bp from buf. |
int getInt(int bp) {
return
((buf[bp] & 0xFF) < < 24) +
((buf[bp+1] & 0xFF) < < 16) +
((buf[bp+2] & 0xFF) < < 8) +
(buf[bp+3] & 0xFF);
}
Extract an integer at position bp from buf. |
long getLong(int bp) {
DataInputStream bufin =
new DataInputStream(new ByteArrayInputStream(buf, bp, 8));
try {
return bufin.readLong();
} catch (IOException e) {
throw new AssertionError(e);
}
}
Extract a long integer at position bp from buf. |
protected EnumSet<Kind> getPackageFileKinds() {
return EnumSet.of(JavaFileObject.Kind.CLASS, JavaFileObject.Kind.SOURCE);
}
specifies types of files to be read when filling in a package symbol |
protected void includeClassFile(PackageSymbol p,
JavaFileObject file) {
if ((p.flags_field & EXISTS) == 0)
for (Symbol q = p; q != null && q.kind == PCK; q = q.owner)
q.flags_field |= EXISTS;
JavaFileObject.Kind kind = file.getKind();
int seen;
if (kind == JavaFileObject.Kind.CLASS)
seen = CLASS_SEEN;
else
seen = SOURCE_SEEN;
String binaryName = fileManager.inferBinaryName(currentLoc, file);
int lastDot = binaryName.lastIndexOf(".");
Name classname = names.fromString(binaryName.substring(lastDot + 1));
boolean isPkgInfo = classname == names.package_info;
ClassSymbol c = isPkgInfo
? p.package_info
: (ClassSymbol) p.members_field.lookup(classname).sym;
if (c == null) {
c = enterClass(classname, p);
if (c.classfile == null) // only update the file if's it's newly created
c.classfile = file;
if (isPkgInfo) {
p.package_info = c;
} else {
if (c.owner == p) // it might be an inner class
p.members_field.enter(c);
}
} else if (c.classfile != null && (c.flags_field & seen) == 0) {
// if c.classfile == null, we are currently compiling this class
// and no further action is necessary.
// if (c.flags_field & seen) != 0, we have already encountered
// a file of the same kind; again no further action is necessary.
if ((c.flags_field & (CLASS_SEEN | SOURCE_SEEN)) != 0)
c.classfile = preferredFileObject(file, c.classfile);
}
c.flags_field |= seen;
}
Include class corresponding to given class file in package,
unless (1) we already have one the same kind (.class or .java), or
(2) we have one of the other kind, and the given class file
is older. |
void indexPool() {
poolIdx = new int[nextChar()];
poolObj = new Object[poolIdx.length];
int i = 1;
while (i < poolIdx.length) {
poolIdx[i++] = bp;
byte tag = buf[bp++];
switch (tag) {
case CONSTANT_Utf8: case CONSTANT_Unicode: {
int len = nextChar();
bp = bp + len;
break;
}
case CONSTANT_Class:
case CONSTANT_String:
case CONSTANT_MethodType:
bp = bp + 2;
break;
case CONSTANT_MethodHandle:
bp = bp + 3;
break;
case CONSTANT_Fieldref:
case CONSTANT_Methodref:
case CONSTANT_InterfaceMethodref:
case CONSTANT_NameandType:
case CONSTANT_Integer:
case CONSTANT_Float:
case CONSTANT_InvokeDynamic:
bp = bp + 4;
break;
case CONSTANT_Long:
case CONSTANT_Double:
bp = bp + 8;
i++;
break;
default:
throw badClassFile("bad.const.pool.tag.at",
Byte.toString(tag),
Integer.toString(bp -1));
}
}
}
Index all constant pool entries, writing their start addresses into
poolIdx. |
public void init(Symtab syms) {
init(syms, true);
}
Initialize classes and packages, treating this as the definitive classreader. |
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;
}
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. |
public static ClassReader instance(Context context) {
ClassReader instance = context.get(classReaderKey);
if (instance == null)
instance = new ClassReader(context, true);
return instance;
}
Get the ClassReader instance for this invocation. |
public ClassSymbol loadClass(Name flatname) throws CompletionFailure {
boolean absent = classes.get(flatname) == null;
ClassSymbol c = enterClass(flatname);
if (c.members_field == null && c.completer != null) {
try {
c.complete();
} catch (CompletionFailure ex) {
if (absent) classes.remove(flatname);
throw ex;
}
}
return c;
}
Load a toplevel class with given fully qualified name
The class is entered into `classes' only if load was successful. |
byte nextByte() {
return buf[bp++];
}
|
char nextChar() {
return (char)(((buf[bp++] & 0xFF) < < 8) + (buf[bp++] & 0xFF));
}
|
int nextInt() {
return
((buf[bp++] & 0xFF) < < 24) +
((buf[bp++] & 0xFF) < < 16) +
((buf[bp++] & 0xFF) < < 8) +
(buf[bp++] & 0xFF);
}
|
public boolean packageExists(Name fullname) {
return enterPackage(fullname).exists();
}
Check to see if a package exists, given its fully qualified name. |
protected JavaFileObject preferredFileObject(JavaFileObject a,
JavaFileObject b) {
if (preferSource)
return (a.getKind() == JavaFileObject.Kind.SOURCE) ? a : b;
else {
long adate = a.getLastModified();
long bdate = b.getLastModified();
// 6449326: policy for bad lastModifiedTime in ClassReader
//assert adate >= 0 && bdate >= 0;
return (adate > bdate) ? a : b;
}
}
Implement policy to choose to derive information from a source
file or a class file when both are present. May be overridden
by subclasses. |
Attribute readAttributeValue() {
char c = (char) buf[bp++];
switch (c) {
case 'B':
return new Attribute.Constant(syms.byteType, readPool(nextChar()));
case 'C':
return new Attribute.Constant(syms.charType, readPool(nextChar()));
case 'D':
return new Attribute.Constant(syms.doubleType, readPool(nextChar()));
case 'F':
return new Attribute.Constant(syms.floatType, readPool(nextChar()));
case 'I':
return new Attribute.Constant(syms.intType, readPool(nextChar()));
case 'J':
return new Attribute.Constant(syms.longType, readPool(nextChar()));
case 'S':
return new Attribute.Constant(syms.shortType, readPool(nextChar()));
case 'Z':
return new Attribute.Constant(syms.booleanType, readPool(nextChar()));
case 's':
return new Attribute.Constant(syms.stringType, readPool(nextChar()).toString());
case 'e':
return new EnumAttributeProxy(readEnumType(nextChar()), readName(nextChar()));
case 'c':
return new Attribute.Class(types, readTypeOrClassSymbol(nextChar()));
case '[': {
int n = nextChar();
ListBuffer< Attribute > l = new ListBuffer< Attribute >();
for (int i=0; i< n; i++)
l.append(readAttributeValue());
return new ArrayAttributeProxy(l.toList());
}
case '@':
return readCompoundAnnotation();
default:
throw new AssertionError("unknown annotation tag '" + c + "'");
}
}
|
void readAttrs(Symbol sym,
AttributeKind kind) {
char ac = nextChar();
for (int i = 0; i < ac; i++) {
Name attrName = readName(nextChar());
int attrLen = nextInt();
AttributeReader r = attributeReaders.get(attrName);
if (r != null && r.accepts(kind))
r.read(sym, attrLen);
else {
unrecognized(attrName);
bp = bp + attrLen;
}
}
}
|
void readClass(ClassSymbol c) {
ClassType ct = (ClassType)c.type;
// allocate scope for members
c.members_field = new Scope(c);
// prepare type variable table
typevars = typevars.dup(currentOwner);
if (ct.getEnclosingType().tag == CLASS)
enterTypevars(ct.getEnclosingType());
// read flags, or skip if this is an inner class
long flags = adjustClassFlags(nextChar());
if (c.owner.kind == PCK) c.flags_field = flags;
// read own class name and check that it matches
ClassSymbol self = readClassSymbol(nextChar());
if (c != self)
throw badClassFile("class.file.wrong.class",
self.flatname);
// class attributes must be read before class
// skip ahead to read class attributes
int startbp = bp;
nextChar();
char interfaceCount = nextChar();
bp += interfaceCount * 2;
char fieldCount = nextChar();
for (int i = 0; i < fieldCount; i++) skipMember();
char methodCount = nextChar();
for (int i = 0; i < methodCount; i++) skipMember();
readClassAttrs(c);
if (readAllOfClassFile) {
for (int i = 1; i < poolObj.length; i++) readPool(i);
c.pool = new Pool(poolObj.length, poolObj);
}
// reset and read rest of classinfo
bp = startbp;
int n = nextChar();
if (ct.supertype_field == null)
ct.supertype_field = (n == 0)
? Type.noType
: readClassSymbol(n).erasure(types);
n = nextChar();
List< Type > is = List.nil();
for (int i = 0; i < n; i++) {
Type _inter = readClassSymbol(nextChar()).erasure(types);
is = is.prepend(_inter);
}
if (ct.interfaces_field == null)
ct.interfaces_field = is.reverse();
Assert.check(fieldCount == nextChar());
for (int i = 0; i < fieldCount; i++) enterMember(c, readField());
Assert.check(methodCount == nextChar());
for (int i = 0; i < methodCount; i++) enterMember(c, readMethod());
typevars = typevars.leave();
}
Read contents of a given class symbol `c'. Both external and internal
versions of an inner class are read. |
void readClassAttrs(ClassSymbol c) {
readAttrs(c, AttributeKind.CLASS);
}
|
Object readClassOrType(int i) {
int index = poolIdx[i];
int len = getChar(index + 1);
int start = index + 3;
Assert.check(buf[start] == '[' || buf[start + len - 1] != ';');
// by the above assertion, the following test can be
// simplified to (buf[start] == '[')
return (buf[start] == '[' || buf[start + len - 1] == ';')
? (Object)sigToType(buf, start, len)
: (Object)enterClass(names.fromUtf(internalize(buf, start,
len)));
}
If name is an array type or class signature, return the
corresponding type; otherwise return a ClassSymbol with given name. |
ClassSymbol readClassSymbol(int i) {
return (ClassSymbol) (readPool(i));
}
|
Code readCode(Symbol owner) {
nextChar(); // max_stack
nextChar(); // max_locals
final int code_length = nextInt();
bp += code_length;
final char exception_table_length = nextChar();
bp += exception_table_length * 8;
readMemberAttrs(owner);
return null;
}
|
CompoundAnnotationProxy readCompoundAnnotation() {
Type t = readTypeOrClassSymbol(nextChar());
int numFields = nextChar();
ListBuffer< Pair< Name,Attribute > > pairs =
new ListBuffer< Pair< Name,Attribute > >();
for (int i=0; i< numFields; i++) {
Name name = readName(nextChar());
Attribute value = readAttributeValue();
pairs.append(new Pair< Name,Attribute >(name, value));
}
return new CompoundAnnotationProxy(t, pairs.toList());
}
|
void readEnclosingMethodAttr(Symbol sym) {
// sym is a nested class with an "Enclosing Method" attribute
// remove sym from it's current owners scope and place it in
// the scope specified by the attribute
sym.owner.members().remove(sym);
ClassSymbol self = (ClassSymbol)sym;
ClassSymbol c = readClassSymbol(nextChar());
NameAndType nt = (NameAndType)readPool(nextChar());
if (c.members_field == null)
throw badClassFile("bad.enclosing.class", self, c);
MethodSymbol m = findMethod(nt, c.members_field, self.flags());
if (nt != null && m == null)
throw badClassFile("bad.enclosing.method", self);
self.name = simpleBinaryName(self.flatname, c.flatname) ;
self.owner = m != null ? m : c;
if (self.name.isEmpty())
self.fullname = names.empty;
else
self.fullname = ClassSymbol.formFullName(self.name, self.owner);
if (m != null) {
((ClassType)sym.type).setEnclosingType(m.type);
} else if ((self.flags_field & STATIC) == 0) {
((ClassType)sym.type).setEnclosingType(c.type);
} else {
((ClassType)sym.type).setEnclosingType(Type.noType);
}
enterTypevars(self);
if (!missingTypeVariables.isEmpty()) {
ListBuffer< Type > typeVars = new ListBuffer< Type >();
for (Type typevar : missingTypeVariables) {
typeVars.append(findTypeVar(typevar.tsym.name));
}
foundTypeVariables = typeVars.toList();
} else {
foundTypeVariables = List.nil();
}
}
|
Type readEnumType(int i) {
// support preliminary jsr175-format class files
int index = poolIdx[i];
int length = getChar(index + 1);
if (buf[index + length + 2] != ';')
return enterClass(readName(i)).type;
return readType(i);
}
|
VarSymbol readField() {
long flags = adjustFieldFlags(nextChar());
Name name = readName(nextChar());
Type type = readType(nextChar());
VarSymbol v = new VarSymbol(flags, name, type, currentOwner);
readMemberAttrs(v);
return v;
}
|
void readInnerClasses(ClassSymbol c) {
int n = nextChar();
for (int i = 0; i < n; i++) {
nextChar(); // skip inner class symbol
ClassSymbol outer = readClassSymbol(nextChar());
Name name = readName(nextChar());
if (name == null) name = names.empty;
long flags = adjustClassFlags(nextChar());
if (outer != null) { // we have a member class
if (name == names.empty)
name = names.one;
ClassSymbol member = enterClass(name, outer);
if ((flags & STATIC) == 0) {
((ClassType)member.type).setEnclosingType(outer.type);
if (member.erasure_field != null)
((ClassType)member.erasure_field).setEnclosingType(types.erasure(outer.type));
}
if (c == outer) {
member.flags_field = flags;
enterMember(c, member);
}
}
}
}
Read inner class info. For each inner/outer pair allocate a
member class. |
void readMemberAttrs(Symbol sym) {
readAttrs(sym, AttributeKind.MEMBER);
}
|
MethodSymbol readMethod() {
long flags = adjustMethodFlags(nextChar());
Name name = readName(nextChar());
Type type = readType(nextChar());
if (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())
type = new MethodType(adjustMethodParams(flags, type.getParameterTypes()),
type.getReturnType(),
type.getThrownTypes(),
syms.methodClass);
}
MethodSymbol m = new MethodSymbol(flags, name, type, currentOwner);
if (saveParameterNames)
initParameterNames(m);
Symbol prevOwner = currentOwner;
currentOwner = m;
try {
readMemberAttrs(m);
} finally {
currentOwner = prevOwner;
}
if (saveParameterNames)
setParameterNames(m, type);
return m;
}
|
Name readName(int i) {
return (Name) (readPool(i));
}
|
Object readPool(int i) {
Object result = poolObj[i];
if (result != null) return result;
int index = poolIdx[i];
if (index == 0) return null;
byte tag = buf[index];
switch (tag) {
case CONSTANT_Utf8:
poolObj[i] = names.fromUtf(buf, index + 3, getChar(index + 1));
break;
case CONSTANT_Unicode:
throw badClassFile("unicode.str.not.supported");
case CONSTANT_Class:
poolObj[i] = readClassOrType(getChar(index + 1));
break;
case CONSTANT_String:
// FIXME: (footprint) do not use toString here
poolObj[i] = readName(getChar(index + 1)).toString();
break;
case CONSTANT_Fieldref: {
ClassSymbol owner = readClassSymbol(getChar(index + 1));
NameAndType nt = (NameAndType)readPool(getChar(index + 3));
poolObj[i] = new VarSymbol(0, nt.name, nt.type, owner);
break;
}
case CONSTANT_Methodref:
case CONSTANT_InterfaceMethodref: {
ClassSymbol owner = readClassSymbol(getChar(index + 1));
NameAndType nt = (NameAndType)readPool(getChar(index + 3));
poolObj[i] = new MethodSymbol(0, nt.name, nt.type, owner);
break;
}
case CONSTANT_NameandType:
poolObj[i] = new NameAndType(
readName(getChar(index + 1)),
readType(getChar(index + 3)));
break;
case CONSTANT_Integer:
poolObj[i] = getInt(index + 1);
break;
case CONSTANT_Float:
poolObj[i] = new Float(getFloat(index + 1));
break;
case CONSTANT_Long:
poolObj[i] = new Long(getLong(index + 1));
break;
case CONSTANT_Double:
poolObj[i] = new Double(getDouble(index + 1));
break;
case CONSTANT_MethodHandle:
skipBytes(4);
break;
case CONSTANT_MethodType:
skipBytes(3);
break;
case CONSTANT_InvokeDynamic:
skipBytes(5);
break;
default:
throw badClassFile("bad.const.pool.tag", Byte.toString(tag));
}
return poolObj[i];
}
Read constant pool entry at start address i, use pool as a cache. |
Type readType(int i) {
int index = poolIdx[i];
return sigToType(buf, index + 3, getChar(index + 1));
}
Read signature and convert to type. |
Type readTypeOrClassSymbol(int i) {
// support preliminary jsr175-format class files
if (buf[poolIdx[i]] == CONSTANT_Class)
return readClassSymbol(i).type;
return readType(i);
}
|
List<Type> readTypeParams(int i) {
int index = poolIdx[i];
return sigToTypeParams(buf, index + 3, getChar(index + 1));
}
Read signature and convert to type parameters. |
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();
}
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. |
Type sigToType() {
switch ((char) signature[sigp]) {
case 'T':
sigp++;
int start = sigp;
while (signature[sigp] != ';') sigp++;
sigp++;
return sigEnterPhase
? Type.noType
: findTypeVar(names.fromUtf(signature, start, sigp - 1 - start));
case '+': {
sigp++;
Type t = sigToType();
return new WildcardType(t, BoundKind.EXTENDS,
syms.boundClass);
}
case '*':
sigp++;
return new WildcardType(syms.objectType, BoundKind.UNBOUND,
syms.boundClass);
case '-': {
sigp++;
Type t = sigToType();
return new WildcardType(t, BoundKind.SUPER,
syms.boundClass);
}
case 'B':
sigp++;
return syms.byteType;
case 'C':
sigp++;
return syms.charType;
case 'D':
sigp++;
return syms.doubleType;
case 'F':
sigp++;
return syms.floatType;
case 'I':
sigp++;
return syms.intType;
case 'J':
sigp++;
return syms.longType;
case 'L':
{
// int oldsigp = sigp;
Type t = classSigToType();
if (sigp < siglimit && signature[sigp] == '.')
throw badClassFile("deprecated inner class signature syntax " +
"(please recompile from source)");
/*
System.err.println(" decoded " +
new String(signature, oldsigp, sigp-oldsigp) +
" = > " + t + " outer " + t.outer());
*/
return t;
}
case 'S':
sigp++;
return syms.shortType;
case 'V':
sigp++;
return syms.voidType;
case 'Z':
sigp++;
return syms.booleanType;
case '[':
sigp++;
return new ArrayType(sigToType(), syms.arrayClass);
case '(':
sigp++;
List< Type > argtypes = sigToTypes(')');
Type restype = sigToType();
List< Type > thrown = List.nil();
while (signature[sigp] == '^') {
sigp++;
thrown = thrown.prepend(sigToType());
}
return new MethodType(argtypes,
restype,
thrown.reverse(),
syms.methodClass);
case '< ':
typevars = typevars.dup(currentOwner);
Type poly = new ForAll(sigToTypeParams(), sigToType());
typevars = typevars.leave();
return poly;
default:
throw badClassFile("bad.signature",
Convert.utf2string(signature, sigp, 10));
}
}
Convert signature to type, where signature is implicit. |
Type sigToType(byte[] sig,
int offset,
int len) {
signature = sig;
sigp = offset;
siglimit = offset + len;
return sigToType();
}
Convert signature to type, where signature is a byte array segment. |
Type sigToTypeParam() {
int start = sigp;
while (signature[sigp] != ':') sigp++;
Name name = names.fromUtf(signature, start, sigp - start);
TypeVar tvar;
if (sigEnterPhase) {
tvar = new TypeVar(name, currentOwner, syms.botType);
typevars.enter(tvar.tsym);
} else {
tvar = (TypeVar)findTypeVar(name);
}
List< Type > bounds = List.nil();
Type st = null;
if (signature[sigp] == ':' && signature[sigp+1] == ':') {
sigp++;
st = syms.objectType;
}
while (signature[sigp] == ':') {
sigp++;
bounds = bounds.prepend(sigToType());
}
if (!sigEnterPhase) {
types.setBounds(tvar, bounds.reverse(), st);
}
return tvar;
}
Convert (implicit) signature to type parameter. |
List<Type> sigToTypeParams() {
List< Type > tvars = List.nil();
if (signature[sigp] == '< ') {
sigp++;
int start = sigp;
sigEnterPhase = true;
while (signature[sigp] != ' >')
tvars = tvars.prepend(sigToTypeParam());
sigEnterPhase = false;
sigp = start;
while (signature[sigp] != ' >')
sigToTypeParam();
sigp++;
}
return tvars.reverse();
}
Convert signature to type parameters, where signature is implicit. |
List<Type> sigToTypeParams(byte[] sig,
int offset,
int len) {
signature = sig;
sigp = offset;
siglimit = offset + len;
return sigToTypeParams();
}
Convert signature to type parameters, where signature is a byte
array segment. |
List<Type> sigToTypes(char terminator) {
List< Type > head = List.of(null);
List< Type > tail = head;
while (signature[sigp] != terminator)
tail = tail.setTail(List.of(sigToType()));
sigp++;
return head.tail;
}
Convert (implicit) signature to list of types
until `terminator' is encountered. |
void skipBytes(int n) {
bp = bp + n;
}
|
void skipMember() {
bp = bp + 6;
char ac = nextChar();
for (int i = 0; i < ac; i++) {
bp = bp + 2;
int attrLen = nextInt();
bp = bp + attrLen;
}
}
|
void unrecognized(Name attrName) {
if (checkClassFile)
printCCF("ccf.unrecognized.attribute", attrName);
}
Report unrecognized attribute. |