Javac 生成字节码文件
Javac 生成 Class 文件的过程,主要类是 com.sun.tools.javac.jvm.ClassWriter.
Class 文件的结构
Class 文件中存储了两种数据类型:无符号数和表。
表是用来描述有层次关系的复合结构的数据.
而无符号数可以用来标识一个具体结构的类型,或者还可以表示数量及属性长度等.
在 Javac 的 ByteBuffer 类中提供了写入基本类型的常用方法,如 appendByte() 方法
ByteBuffer 对象表示一个具体的缓冲,主要通过 elems 来保存缓冲的内容,Javac 在向 Class 文件中写入字节码时不会一个字节一个字节地写,而是先写入 ByteBuffer 缓冲中,然后一次性写入 Class 文件来提高写入的效率。
/** Write constant pool to pool buffer.
* Note: during writing, constant pool
* might grow since some parts of constants still need to be entered.
*/
void writePool(Pool pool) throws PoolOverflow, StringOverflow {
int poolCountIdx = poolbuf.length;
poolbuf.appendChar(0); // 追加一个 0 值, 表示不引用任何一个常量池项
int i = 1;
while (i < pool.pp) { // writePool() 方法循环读取 pool.pool 数组中存储的所有常量池信息,并按照 JVMS 规定的常量池项的格式存储到 poolbuf 缓冲中
Object value = pool.pool[i];
Assert.checkNonNull(value);
if (value instanceof Method || value instanceof Variable)
value = ((DelegatedSymbol)value).getUnderlyingSymbol();
if (value instanceof MethodSymbol) {
MethodSymbol m = (MethodSymbol)value;
if (!m.isDynamic()) {
poolbuf.appendByte((m.owner.flags() & INTERFACE) != 0
? CONSTANT_InterfaceMethodref
: CONSTANT_Methodref);
poolbuf.appendChar(pool.put(m.owner));
poolbuf.appendChar(pool.put(nameType(m)));
} else {
//invokedynamic
DynamicMethodSymbol dynSym = (DynamicMethodSymbol)m;
MethodHandle handle = new MethodHandle(dynSym.bsmKind, dynSym.bsm, types);
DynamicMethod dynMeth = new DynamicMethod(dynSym, types);
bootstrapMethods.put(dynMeth, handle);
//init cp entries
pool.put(names.BootstrapMethods);
pool.put(handle);
for (Object staticArg : dynSym.staticArgs) {
pool.put(staticArg);
}
poolbuf.appendByte(CONSTANT_InvokeDynamic);
poolbuf.appendChar(bootstrapMethods.size() - 1);
poolbuf.appendChar(pool.put(nameType(dynSym)));
}
} else if (value instanceof VarSymbol) {
VarSymbol v = (VarSymbol)value;
poolbuf.appendByte(CONSTANT_Fieldref);
poolbuf.appendChar(pool.put(v.owner));
poolbuf.appendChar(pool.put(nameType(v)));
} else if (value instanceof Name) { // 当 value 是 Name 对象时会写入一个 CONSTANT_Utf8_info 常量池项
poolbuf.appendByte(CONSTANT_Utf8); // 值为 1
byte[] bs = ((Name)value).toUtf();
poolbuf.appendChar(bs.length); // 写入使用 2 个字节表示的字符串长度
poolbuf.appendBytes(bs, 0, bs.length); // 保存具体的字符串信息
if (bs.length> Pool.MAX_STRING_LENGTH)
throw new StringOverflow(value.toString());
} else if (value instanceof ClassSymbol) {
ClassSymbol c = (ClassSymbol)value;
if (c.owner.kind == TYP) pool.put(c.owner);
poolbuf.appendByte(CONSTANT_Class);
if (c.type.hasTag(ARRAY)) {
poolbuf.appendChar(pool.put(typeSig(c.type)));
} else {
poolbuf.appendChar(pool.put(names.fromUtf(externalize(c.flatname))));
enterInner(c);
}
} else if (value instanceof NameAndType) {
NameAndType nt = (NameAndType)value;
poolbuf.appendByte(CONSTANT_NameandType);
poolbuf.appendChar(pool.put(nt.name));
poolbuf.appendChar(pool.put(typeSig(nt.uniqueType.type)));
} else if (value instanceof Integer) {
poolbuf.appendByte(CONSTANT_Integer);
poolbuf.appendInt(((Integer)value).intValue());
} else if (value instanceof Long) {
poolbuf.appendByte(CONSTANT_Long);
poolbuf.appendLong(((Long)value).longValue());
i++;
} else if (value instanceof Float) {
poolbuf.appendByte(CONSTANT_Float);
poolbuf.appendFloat(((Float)value).floatValue());
} else if (value instanceof Double) {
poolbuf.appendByte(CONSTANT_Double);
poolbuf.appendDouble(((Double)value).doubleValue());
i++;
} else if (value instanceof String) {
poolbuf.appendByte(CONSTANT_String);
poolbuf.appendChar(pool.put(names.fromString((String)value)));
} else if (value instanceof UniqueType) {
Type type = ((UniqueType)value).type;
if (type instanceof MethodType) {
poolbuf.appendByte(CONSTANT_MethodType);
poolbuf.appendChar(pool.put(typeSig((MethodType)type)));
} else {
if (type.hasTag(CLASS)) enterInner((ClassSymbol)type.tsym);
poolbuf.appendByte(CONSTANT_Class);
poolbuf.appendChar(pool.put(xClassName(type)));
}
} else if (value instanceof MethodHandle) {
MethodHandle ref = (MethodHandle)value;
poolbuf.appendByte(CONSTANT_MethodHandle);
poolbuf.appendByte(ref.refKind);
poolbuf.appendChar(pool.put(ref.refSym));
} else {
Assert.error("writePool" + value);
}
i++;
}
if (pool.pp> Pool.MAX_ENTRIES)
throw new PoolOverflow();
putChar(poolbuf, poolCountIdx, pool.pp); // 将 pool.pp 写入 ByteBuffer 对象的 elems 数组中, 具体就是写入到下标为 poolCountIdx 与 poolCountIdx+1 的位置,poolCountIdx 的值是 8,要在 Class 文件的第 8 个和第 9 个字节中写入常量池项的数量,而 pool.pp 保存了常量池项的数量
}