📄 classreader.java
字号:
/**
* @(#)ClassReader.java 1.55 03/01/23
*
* Copyright 2003 Sun Microsystems, Inc. All rights reserved.
* SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*/
package com.sun.tools.javac.v8.code;
import com.sun.tools.javac.v8.util.*;
import java.io.*;
import java.util.zip.*;
import java.util.StringTokenizer;
import com.sun.tools.javac.v8.code.Type.*;
import com.sun.tools.javac.v8.code.Symbol.*;
import com.sun.tools.javac.v8.code.Symtab;
/**
* This class provides operations to read a classfile into an internal
* representation. The internal representation is anchored in a
* ClassSymbol which contains in its scope symbol representations
* for all other definitions in the classfile. Top-level Classes themselves
* appear as members of the scopes of PackageSymbols.
*/
public class ClassReader extends ClassFile implements Completer, Flags, Kinds,
TypeTags {
/**
* The context key for the class reader.
*/
private static final Context.Key classReaderKey = new Context.Key();
/**
* The string used as separator in class paths.
*/
public static final String pathSep = System.getProperty("path.separator");
/**
* Switch: verbose output.
*/
public boolean verbose;
/**
* Switch: check class file for correct minor version, unrecognized
* attributes.
*/
public boolean checkClassFile;
/**
* Switch: read constant pool and code sections. This switch is initially
* set to false but can be turned on from outside.
*/
public boolean readAllOfClassFile = false;
/**
* The log to use for verbose output
*/
private final Log log;
/**
* The symbol table.
*/
private final Symtab syms;
/**
* The name table.
*/
protected final Name.Table names;
/**
* Force a completion failure on this name
*/
final Name completionFailureName;
/**
* Can be reassigned from outside:
* the class path to be searched for user classes.
*/
public String classPath;
/**
* The class path to be searched for system classes.
*/
public String bootClassPath;
/**
* The path to be searched for sources
*/
public String sourceClassPath;
/**
* Can be reassigned from outside:
* the completer to be used for ".java" files. If this remains unassigned
* ".java" files will not be loaded.
*/
public SourceCompleter sourceCompleter = null;
/**
* A hashtable containing the encountered top-level and member classes,
* indexed by flat names. The table does not contain local classes.
*/
private Hashtable classes;
/**
* A hashtable containing the encountered packages.
*/
private Hashtable packages;
/**
* The current scope where type variables are entered.
*/
Scope typevars = new Scope(null);
/**
* The path name of the class file currently being read.
*/
String currentClassFileName = null;
/**
* The class or method currently being read.
*/
Symbol currentOwner = null;
/**
* The buffer containing the currently read class file.
*/
byte[] buf = new byte[65520];
/**
* The current input pointer.
*/
int bp;
/**
* The objects of the constant pool.
*/
Object[] poolObj;
/**
* For every constant pool entry, an index into buf where the
* defining section of the entry is found.
*/
int[] poolIdx;
/**
* Get the ClassReader instance for this invocation.
*/
public static ClassReader instance(Context context) {
ClassReader instance = (ClassReader) context.get(classReaderKey);
if (instance == null)
instance = new ClassReader(context, true);
return instance;
}
/**
* Initialize classes and packages, treating this as the definitive classreader.
*/
public void init(Symtab syms) {
init(syms, true);
}
/**
* Initialize classes and packages, optionally treating this as
* the definitive classreader.
*/
private void init(Symtab syms, boolean definitive) {
if (classes != null)
return;
if (definitive) {
assert packages == null || packages == syms.packages;
packages = syms.packages;
assert classes == null || classes == syms.classes;
classes = syms.classes;
} else {
packages = new Hashtable();
classes = new Hashtable();
}
packages.put(syms.rootPackage.fullname, syms.rootPackage);
syms.rootPackage.completer = this;
packages.put(syms.emptyPackage.fullname, syms.emptyPackage);
syms.emptyPackage.completer = this;
}
/**
* Construct a new class reader, optionally treated as the
* definitive classreader for this invocation.
*/
protected ClassReader(Context context, boolean definitive) {
super();
if (definitive)
context.put(classReaderKey, this);
names = Name.Table.instance(context);
syms = Symtab.instance(context);
init(syms, definitive);
log = Log.instance(context);
Options options = Options.instance(context);
verbose = options.get("-verbose") != null;
checkClassFile = options.get("-checkclassfile") != null;
setClassPaths(options);
completionFailureName = (options.get("failcomplete") != null) ?
names.fromString((String) options.get("failcomplete")) : null;
}
/**
* Set classPath, bootClassPath, and sourceClassPath.
*/
private void setClassPaths(Options options) {
String cp = (String) options.get("-classpath");
if (cp == null)
cp = System.getProperty("env.class.path");
if (cp == null && System.getProperty("application.home") == null)
cp = System.getProperty("java.class.path");
if (cp == null)
cp = ".";
classPath = terminate(cp);
String bp = (String) options.get("-bootclasspath");
if (bp == null) {
bp = System.getProperty("sun.boot.class.path");
if (bp == null)
bp = System.getProperty("java.class.path");
if (bp == null)
bp = ".";
}
String bpp = (String) options.get("-Xbootclasspath/p:");
if (bpp != null)
bp = bpp + System.getProperty("path.separator") + bp;
bootClassPath = terminate(bp);
String ed = (String) options.get("-extdirs");
if (ed == null)
ed = System.getProperty("java.ext.dirs");
if (ed == null)
ed = "";
String extdirs = terminate(ed);
int i = 0;
int edlen = extdirs.length();
while (i < edlen) {
int end = extdirs.indexOf(pathSep, i);
String extdir = extdirs.substring(i, end);
addArchives(extdir);
i = end + 1;
}
String sp = (String) options.get("-sourcepath");
if (sp != null) {
sourceClassPath = terminate(sp);
} else {
sourceClassPath = null;
}
}
/**
* Add all archives in `extdir' to boot class path
*/
private void addArchives(String extdir) {
String[] archives = new File(extdir).list();
for (int i = 0; archives != null && i < archives.length; i++) {
if (archives[i].endsWith(".jar")) {
String prefix = (extdir.endsWith(File.separator)) ? extdir :
(extdir + File.separator);
bootClassPath = bootClassPath + prefix + archives[i] + pathSep;
}
}
}
/**
* Add path separator to string if it does not end in one already
*/
private String terminate(String s) {
return (s.endsWith(pathSep)) ? s : s + pathSep;
}
/**
* Add member to class unless it is synthetic
*/
private void enterMember(ClassSymbol c, Symbol sym) {
if ((sym.flags_field & SYNTHETIC) == 0)
c.members_field.enter(sym);
}
/**
* Error Diagnoses
*/
public static class BadClassFile extends CompletionFailure {
/**
* @param msg A localized message.
*/
public BadClassFile(ClassSymbol c, String cname, String msg) {
super(c, Log.getLocalizedString("bad.class.file.header", cname, msg));
}
}
public BadClassFile badClassFile(String key) {
return new BadClassFile(currentOwner.enclClass(), currentClassFileName,
Log.getLocalizedString(key));
}
public BadClassFile badClassFile(String key, String arg0) {
return new BadClassFile(currentOwner.enclClass(), currentClassFileName,
Log.getLocalizedString(key, arg0));
}
public BadClassFile badClassFile(String key, String arg0, String arg1) {
return new BadClassFile(currentOwner.enclClass(), currentClassFileName,
Log.getLocalizedString(key, arg0, arg1));
}
public BadClassFile badClassFile(String key, String arg0, String arg1,
String arg2) {
return new BadClassFile(currentOwner.enclClass(), currentClassFileName,
Log.getLocalizedString(key, arg0, arg1, arg2));
}
public BadClassFile badClassFile(String key, String arg0, String arg1,
String arg2, String arg3) {
return new BadClassFile(currentOwner.enclClass(), currentClassFileName,
Log.getLocalizedString(key, arg0, arg1, arg2, arg3));
}
/**
* Read a character.
*/
char nextChar() {
return (char)(((buf[bp++] & 255)<< 8) + (buf[bp++] & 255));
}
/**
* Read an integer.
*/
int nextInt() {
return ((buf[bp++] & 255)<< 24) + ((buf[bp++] & 255)<< 16) +
((buf[bp++] & 255)<< 8) + (buf[bp++] & 255);
}
/**
* Extract a character at position bp from buf.
*/
char getChar(int bp) {
return (char)(((buf[bp] & 255)<< 8) + (buf[bp + 1] & 255));
}
/**
* Extract an integer at position bp from buf.
*/
int getInt(int bp) {
return ((buf[bp] & 255)<< 24) + ((buf[bp + 1] & 255)<< 16) +
((buf[bp + 2] & 255)<< 8) + (buf[bp + 3] & 255);
}
/**
* Extract a long 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();
}
}
/**
* Extract a float 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();
}
}
/**
* Extract a double 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();
}
}
/**
* Index all constant pool entries, writing their start addresses into
* poolIdx.
*/
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:
bp = bp + 2;
break;
case CONSTANT_Fieldref:
case CONSTANT_Methodref:
case CONSTANT_InterfaceMethodref:
case CONSTANT_NameandType:
case CONSTANT_Integer:
case CONSTANT_Float:
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));
}
}
}
/**
* Read constant pool entry at start address i, use pool as a cache.
*/
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:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -