package miniJVM.loader;
import miniJVM.attr.CodeAttr;
import miniJVM.attr.LineNumberTable;
import miniJVM.attr.LocalVariableTable;
import miniJVM.attr.StackMapTable;
import miniJVM.clz.AccessFlag;
import miniJVM.clz.ClassFile;
import miniJVM.clz.ClassIndex;
import miniJVM.constant.*;
import miniJVM.field.Field;
import miniJVM.method.Method;
public class ClassFileParser {
private ClassFile clzFile = new ClassFile();
private ByteCodeIterator iter;
private static final int MAGIC_NUMBER_LENGTH = 4;
private static ConstantPool pool;
public ClassFile parse(byte[] codes) {
iter = new ByteCodeIterator(codes);
iter.pos = MAGIC_NUMBER_LENGTH;
//1. 版本信息
parseVersions(iter);
//2. 常量池
pool = new ConstantPool();
parseConstantPool(iter);
//3. 访问标记
parseAccessFlag(iter);
//4. classIndex superClassIndex
parseClassIndex(iter);
//5. 接口,即便没有也要调用,因为字节码里是固定有的
parseInterfaces(iter);
//6. 字段
parseFields(iter);
//7. 方法
parseMethods(iter);
//8. class文件结尾的stackMapTable, 只读取,不处理
parseStackMapTable(iter);
return clzFile;
}
private void parseVersions(ByteCodeIterator iter) {
int minorVersion = iter.nextU2ToInt();
clzFile.setMinorVersion(minorVersion);
int majorVersion = iter.nextU2ToInt();
clzFile.setMajorVersion(majorVersion);
}
private void parseAccessFlag(ByteCodeIterator iter) {
int accessValue = iter.nextU2ToInt();
AccessFlag accessFlag = new AccessFlag(accessValue);
clzFile.setAccessFlag(accessFlag);
}
private void parseClassIndex(ByteCodeIterator iter) {
int thisClass = iter.nextU2ToInt();
int superClass = iter.nextU2ToInt();
ClassIndex classInfo = new ClassIndex(thisClass, superClass);
clzFile.setClassIndex(classInfo);
}
private void parseConstantPool(ByteCodeIterator iter) {
try {
//常量池个数
int cnstSize = iter.nextU2ToInt();
for (int i = 0; i < cnstSize; i++) {
int index = -1;
if (i == 0) {
pool.addConstantInfo(null);
continue;
} else {
index = iter.nextU1ToInt();
}
// System.out.println("i -> " + i + ", index -> " + index);
if (index == ConstantInfo.CLASS_INFO) {
ClassInfo classInfo = new ClassInfo(pool);
classInfo.setUtf8Index(iter.nextU2ToInt());
pool.addConstantInfo(classInfo);
} else if (index == ConstantInfo.UTF8_INFO) {
UTF8Info utf8Info = new UTF8Info(pool);
int length = iter.nextU2ToInt();
utf8Info.setLength(length);
utf8Info.setValue(new String(iter.getBytes(length), "utf8"));
pool.addConstantInfo(utf8Info);
} else if (index == ConstantInfo.METHOD_INFO) {
MethodRefInfo methodRefInfo = new MethodRefInfo(pool);
methodRefInfo.setClassInfoIndex(iter.nextU2ToInt());
methodRefInfo.setNameAndTypeIndex(iter.nextU2ToInt());
pool.addConstantInfo(methodRefInfo);
} else if (index == ConstantInfo.NAME_AND_TYPE_INFO) {
NameAndTypeInfo nameAndTypeInfo = new NameAndTypeInfo(pool);
nameAndTypeInfo.setIndex1(iter.nextU2ToInt());
nameAndTypeInfo.setIndex2(iter.nextU2ToInt());
pool.addConstantInfo(nameAndTypeInfo);
} else if (index == ConstantInfo.FIELD_INFO) {
FieldRefInfo fieldRefInfo = new FieldRefInfo(pool);
fieldRefInfo.setClassInfoIndex(iter.nextU2ToInt());
fieldRefInfo.setNameAndTypeIndex(iter.nextU2ToInt());
pool.addConstantInfo(fieldRefInfo);
} else if (index == ConstantInfo.STRING_INFO) {
StringInfo stringInfo = new StringInfo(pool);
stringInfo.setIndex(iter.nextU2ToInt());
pool.addConstantInfo(stringInfo);
} else if (index == 0) {
pool.addConstantInfo(null);
} else {
throw new Exception("没有针对tag=" + index + "的数据进行处理");
}
}
clzFile.setConstPool(pool);
} catch (Exception e) {
e.printStackTrace();
}
}
private void parseInterfaces(ByteCodeIterator iter) {
int interfaceCount = iter.nextU2ToInt();
// System.out.println("interfaceCount:" + interfaceCount);
// TODO : 如果实现了interface, 这里需要解析
}
private void parseFields(ByteCodeIterator iter) {
int fieldsCount = iter.nextU2ToInt();
for (int i = 0; i < fieldsCount; i++) {
int accessFlag = iter.nextU2ToInt();
int nameIndex = iter.nextU2ToInt();
int descriptorIndex = iter.nextU2ToInt();
int attributeCount = iter.nextU2ToInt();
Field field = new Field(accessFlag, nameIndex, descriptorIndex, attributeCount, pool);
clzFile.addField(field);
}
}
private void parseMethods(ByteCodeIterator iter) {
int methodCount = iter.nextU2ToInt();
for (int i = 0; i < methodCount; i++) {
int accessFlag = iter.nextU2ToInt();
int nameIndex = iter.nextU2ToInt();
int descriptorIndex = iter.nextU2ToInt();
Method method = new Method(clzFile, accessFlag, nameIndex, descriptorIndex);
int attributeCount = iter.nextU2ToInt();//=1
while(attributeCount > 0){
CodeAttr codeAttr = CodeAttr.parse(clzFile, iter);
int exceptionTableLength = iter.nextU2ToInt();
//异常先不处理
String exceptionTable = iter.nextUxToHexString(exceptionTableLength);
int subAttributeCount = iter.nextU2ToInt();
while(subAttributeCount > 0){
LineNumberTable lineNumberTable = LineNumberTable.parse(iter);
codeAttr.setLineNumberTable(lineNumberTable);
subAttributeCount--;
LocalVariableTable localVariableTable = LocalVariableTable.parse(iter);
codeAttr.setLocalVariableTable(localVariableTable);
subAttributeCount--;
}
method.setCodeAttr(codeAttr);
attributeCount--;
}
clzFile.addMethod(method);
}
}
private void parseStackMapTable(ByteCodeIterator iter){
int stackMapCount = iter.nextU2ToInt();
StackMapTable table = StackMapTable.parse(iter);
}
}