JVM字节码常量池解析
前言
最近写J2ME深感各种java反编译不得我心,决定自己尝试写一个自己的java反编译,第一步实现javap。现在把字节码的常量池的解析代码分享出来。
常量池类型
前面已经分析过了,现在直接贴代码
cpp
// §4.4.1
#define CONSTANT_Class 7
// §4.4.2
#define CONSTANT_Fieldref 9
// §4.4.2
#define CONSTANT_Methodref 10
// §4.4.2
#define CONSTANT_InterfaceMethodref 11
// §4.4.3
#define CONSTANT_String 8
// §4.4.4
#define CONSTANT_Integer 3
// §4.4.4
#define CONSTANT_Float 4
// §4.4.5
#define CONSTANT_Long 5
// §4.4.5
#define CONSTANT_Double 6
// §4.4.6
#define CONSTANT_NameAndType 12
// §4.4.7
#define CONSTANT_Utf8 1
// §4.4.8
#define CONSTANT_MethodHandle 15
// §4.4.9
#define CONSTANT_MethodType 16
// §4.4.10
#define CONSTANT_Dynamic 17
// §4.4.10
#define CONSTANT_InvokeDynamic 18
// §4.4.11
#define CONSTANT_Module 19
// §4.4.12
#define CONSTANT_Package 20
代码定义
ConstPool.h
3.1常量池基类定义
cpp
// ==================== 常量池基类定义 ====================
/**
* 常量池项基类 - 所有常量池项的抽象基类
* 定义了常量池项的基本接口和公共属性
*/
class constant_pool_info {
public:
u1 tag; // 常量池项类型标识
virtual ~constant_pool_info() = default;
// 获取常量池项的字符串表示
virtual std::string toString() const = 0;
// 获取常量池项的大小(字节)
virtual size_t getSize() const = 0;
// 验证常量池项的有效性
virtual bool validate() const = 0;
// 从文件流中读取数据
virtual void readFrom(std::istream& file) = 0;
};
3.2 CONSTANT_Class_info (tag=7) - 类或接口引用
cpp
/**
* CONSTANT_Class_info (tag=7) - 类或接口引用
* 表示一个类或接口的符号引用
*/
class CONSTANT_Class_info : public constant_pool_info {
public:
u2 name_index; // 指向常量池中UTF8字符串的索引,表示类的全限定名
CONSTANT_Class_info() { tag = CONSTANT_Class; }
std::string toString() const override;
size_t getSize() const override { return 3; } // 1字节tag + 2字节name_index
bool validate() const override;
void readFrom(std::istream& file) override;
};
3.3 CONSTANT_Fieldref_info (tag=9) - 字段引用
cpp
/**
* CONSTANT_Fieldref_info (tag=9) - 字段引用
* 表示对一个字段的符号引用
*/
class CONSTANT_Fieldref_info : public constant_pool_info {
public:
u2 class_index; // 指向类或接口的CONSTANT_Class_info索引
u2 name_and_type_index; // 指向字段名和类型的CONSTANT_NameAndType_info索引
CONSTANT_Fieldref_info() { tag = CONSTANT_Fieldref; }
std::string toString() const override;
size_t getSize() const override { return 5; } // 1字节tag + 4字节索引
bool validate() const override;
void readFrom(std::istream& file) override;
};
3.4 CONSTANT_Methodref_info (tag=10) - 方法引用
cpp
/**
* CONSTANT_Methodref_info (tag=10) - 方法引用
* 表示对一个方法的符号引用
*/
class CONSTANT_Methodref_info : public constant_pool_info {
public:
u2 class_index; // 指向类或接口的CONSTANT_Class_info索引
u2 name_and_type_index; // 指向方法名和类型的CONSTANT_NameAndType_info索引
CONSTANT_Methodref_info() { tag = CONSTANT_Methodref; }
std::string toString() const override;
size_t getSize() const override { return 5; }
bool validate() const override;
void readFrom(std::istream& file) override;
};
3.5 CONSTANT_InterfaceMethodref_info (tag=11) - 接口方法引用
cpp
/**
* CONSTANT_InterfaceMethodref_info (tag=11) - 接口方法引用
* 表示对一个接口方法的符号引用
*/
class CONSTANT_InterfaceMethodref_info : public constant_pool_info {
public:
u2 class_index; // 指向接口的CONSTANT_Class_info索引
u2 name_and_type_index; // 指向方法名和类型的CONSTANT_NameAndType_info索引
CONSTANT_InterfaceMethodref_info() { tag = CONSTANT_InterfaceMethodref; }
std::string toString() const override;
size_t getSize() const override { return 5; }
bool validate() const override;
void readFrom(std::istream& file) override;
};
3.6 CONSTANT_String_info (tag=8) - 字符串引用
cpp
/**
* CONSTANT_String_info (tag=8) - 字符串引用
* 表示对一个字符串字面量的引用
*/
class CONSTANT_String_info : public constant_pool_info {
public:
u2 string_index; // 指向CONSTANT_Utf8_info的索引,表示字符串内容
CONSTANT_String_info() { tag = CONSTANT_String; }
std::string toString() const override;
size_t getSize() const override { return 3; }
bool validate() const override;
void readFrom(std::istream& file) override;
};
3.7 CONSTANT_Integer_info (tag=3) - 整型常量
cpp
/**
* CONSTANT_Integer_info (tag=3) - 整型常量
* 表示4字节int类型的常量值
*/
class CONSTANT_Integer_info : public constant_pool_info {
public:
u4 bytes; // 整数值,按大端序存储
CONSTANT_Integer_info() { tag = CONSTANT_Integer; }
std::string toString() const override;
size_t getSize() const override { return 5; }
bool validate() const override;
void readFrom(std::istream& file) override;
// 获取整数值
int32_t getValue() const { return static_cast<int32_t>(bytes); }
};
3.8 CONSTANT_Float_info (tag=4) - 浮点常量
cpp
/**
* CONSTANT_Float_info (tag=4) - 浮点常量
* 表示4字节float类型的常量值
*/
class CONSTANT_Float_info : public constant_pool_info {
public:
u4 bytes; // 浮点数值,按IEEE 754格式存储
CONSTANT_Float_info() { tag = CONSTANT_Float; }
std::string toString() const override;
size_t getSize() const override { return 5; }
bool validate() const override;
void readFrom(std::istream& file) override;
// 获取浮点数值
float getValue() const {
auto val = bytes;
return *reinterpret_cast<float*>(&val);
}
};
3.9 CONSTANT_Long_info (tag=5) - 长整型常量
cpp
/**
* CONSTANT_Long_info (tag=5) - 长整型常量
* 表示8字节long类型的常量值
* 注意:此类型在常量池中占用两个位置
*/
class CONSTANT_Long_info : public constant_pool_info {
public:
u4 high_bytes; // 高32位
u4 low_bytes; // 低32位
CONSTANT_Long_info() { tag = CONSTANT_Long; }
std::string toString() const override;
size_t getSize() const override { return 9; } // 在文件中占9字节,但在常量池中占两个位置
bool validate() const override;
void readFrom(std::istream& file) override;
// 获取长整数值
int64_t getValue() const {
return (static_cast<int64_t>(high_bytes) << 32) | low_bytes;
}
};
3.10 CONSTANT_Double_info (tag=6) - 双精度浮点常量
cpp
/**
* CONSTANT_Double_info (tag=6) - 双精度浮点常量
* 表示8字节double类型的常量值
* 注意:此类型在常量池中占用两个位置
*/
class CONSTANT_Double_info : public constant_pool_info {
public:
u4 high_bytes; // 高32位
u4 low_bytes; // 低32位
CONSTANT_Double_info() { tag = CONSTANT_Double; }
std::string toString() const override;
size_t getSize() const override { return 9; }
bool validate() const override;
void readFrom(std::istream& file) override;
// 获取双精度浮点数值
double getValue() const {
auto val = (static_cast<long long>(high_bytes) << 32) | low_bytes;
return *reinterpret_cast<double*>(&val);
}
};
3.11 CONSTANT_NameAndType_info (tag=12) - 名称和类型
cpp
/**
* CONSTANT_NameAndType_info (tag=12) - 名称和类型
* 表示字段或方法的名称和描述符
*/
class CONSTANT_NameAndType_info : public constant_pool_info {
public:
u2 name_index; // 指向名称的CONSTANT_Utf8_info索引
u2 descriptor_index; // 指向描述符的CONSTANT_Utf8_info索引
CONSTANT_NameAndType_info() { tag = CONSTANT_NameAndType; }
std::string toString() const override;
size_t getSize() const override { return 5; }
bool validate() const override;
void readFrom(std::istream& file) override;
};
3.12 CONSTANT_Utf8_info (tag=1) - UTF-8字符串
cpp
/**
* CONSTANT_Utf8_info (tag=1) - UTF-8字符串
* 表示UTF-8编码的字符串,常量池中实际的字符串存储
*/
class CONSTANT_Utf8_info : public constant_pool_info {
public:
u2 length; // 字符串长度(字节数)
u1 *bytes; // UTF-8编码的字节数组
CONSTANT_Utf8_info() {
tag = CONSTANT_Utf8;
bytes = nullptr;
length = 0;
}
~CONSTANT_Utf8_info() override {
delete[] bytes;
}
// 拷贝构造函数和赋值操作符
CONSTANT_Utf8_info(const CONSTANT_Utf8_info& other);
CONSTANT_Utf8_info& operator=(const CONSTANT_Utf8_info& other);
std::string toString() const override;
size_t getSize() const override { return 3 + length; }
bool validate() const override;
void readFrom(std::istream& file) override;
// 获取字符串
std::string getString() const;
// 设置字符串
void setString(const std::string& str);
};
3.13 CONSTANT_MethodHandle_info (tag=15) - 方法句柄
cpp
/**
* CONSTANT_MethodHandle_info (tag=15) - 方法句柄
* Java 7引入,表示方法句柄,用于动态语言支持
*/
class CONSTANT_MethodHandle_info : public constant_pool_info {
public:
u1 reference_kind; // 引用类型 (1-9)
u2 reference_index; // 引用索引,指向常量池中的一项
CONSTANT_MethodHandle_info() { tag = CONSTANT_MethodHandle; }
std::string toString() const override;
size_t getSize() const override { return 4; }
bool validate() const override;
void readFrom(std::istream& file) override;
};
3.14 CONSTANT_MethodType_info (tag=16) - 方法类型
cpp
/**
* CONSTANT_MethodType_info (tag=16) - 方法类型
* Java 7引入,表示方法类型,用于动态语言支持
*/
class CONSTANT_MethodType_info : public constant_pool_info {
public:
u2 descriptor_index; // 指向方法描述符的CONSTANT_Utf8_info索引
CONSTANT_MethodType_info() { tag = CONSTANT_MethodType; }
std::string toString() const override;
size_t getSize() const override { return 3; }
bool validate() const override;
void readFrom(std::istream& file) override;
};
3.15 CONSTANT_Dynamic_info (tag=17) - 动态调用点
cpp
/**
* CONSTANT_Dynamic_info (tag=17) - 动态调用点
* Java 11引入,用于更高级的动态语言特性
*/
class CONSTANT_Dynamic_info : public constant_pool_info {
public:
u2 bootstrap_method_attr_index; // 指向BootstrapMethods属性的索引
u2 name_and_type_index; // 指向名称和类型的CONSTANT_NameAndType_info索引
CONSTANT_Dynamic_info() { tag = CONSTANT_Dynamic; }
std::string toString() const override;
size_t getSize() const override { return 5; }
bool validate() const override;
void readFrom(std::istream& file) override;
};
3.16 CONSTANT_InvokeDynamic_info (tag=18) - 调用动态
cpp
/**
* CONSTANT_InvokeDynamic_info (tag=18) - 调用动态
* Java 7引入,用于invokedynamic指令
*/
class CONSTANT_InvokeDynamic_info : public constant_pool_info {
public:
u2 bootstrap_method_attr_index; // 指向BootstrapMethods属性的索引
u2 name_and_type_index; // 指向方法名和类型的CONSTANT_NameAndType_info索引
CONSTANT_InvokeDynamic_info() { tag = CONSTANT_InvokeDynamic; }
std::string toString() const override;
size_t getSize() const override { return 5; }
bool validate() const override;
void readFrom(std::istream& file) override;
};
3.17 CONSTANT_Module_info (tag=19) - 模块名
cpp
/**
* CONSTANT_Module_info (tag=19) - 模块名
* Java 9引入,用于模块系统
*/
class CONSTANT_Module_info : public constant_pool_info {
public:
u2 name_index; // 指向模块名的CONSTANT_Utf8_info索引
CONSTANT_Module_info() { tag = CONSTANT_Module; }
std::string toString() const override;
size_t getSize() const override { return 3; }
bool validate() const override;
void readFrom(std::istream& file) override;
};
3.18 CONSTANT_Package_info (tag=20) - 包名
cpp
/**
* CONSTANT_Package_info (tag=20) - 包名
* Java 9引入,用于模块系统
*/
class CONSTANT_Package_info : public constant_pool_info {
public:
u2 name_index; // 指向包名的CONSTANT_Utf8_info索引
CONSTANT_Package_info() { tag = CONSTANT_Package; }
std::string toString() const override;
size_t getSize() const override { return 3; }
bool validate() const override;
void readFrom(std::istream& file) override;
};
实现代码与管理代码
4.1工厂管理工具类
cpp
/**
* 常量池工厂类 - 根据tag创建对应的常量池对象
* 使用工厂模式,提供统一的创建接口
*/
class ConstantPoolFactory {
public:
/**
* 根据tag值创建对应的常量池对象
* @param tag 常量池项类型标识
* @return 对应的常量池对象指针,如果tag无效则返回nullptr
*/
static constant_pool_info* createConstant(u1 tag);
/**
* 检查tag是否为有效的常量池类型
* @param tag 要检查的tag值
* @return 是否有效
*/
static bool isValidTag(u1 tag);
/**
* 获取常量池类型的名称
* @param tag 常量池类型标识
* @return 类型名称字符串
*/
static std::string getConstantTypeName(u1 tag);
/**
* 检查该常量池类型是否在常量池中占用两个位置
* @param tag 常量池类型标识
* @return 是否占用两个位置
*/
static bool takesTwoSlots(u1 tag);
};
这里的实现逻辑比较简单switch或者if判断tag的类型就行
cpp
constant_pool_info *ConstantPoolFactory::createConstant(u1 tag) {
switch (tag) {
case CONSTANT_Class:
return new CONSTANT_Class_info();
case CONSTANT_Fieldref:
return new CONSTANT_Fieldref_info();
case CONSTANT_Methodref:
return new CONSTANT_Methodref_info();
case CONSTANT_InterfaceMethodref:
// 省略机械重复性代码
4.2 具体常量实现代码
贴两个示例
cpp
// CONSTANT_Long_info
void CONSTANT_Long_info::readFrom(std::istream& file) {
high_bytes = IoUtil::readU4(file);
low_bytes = IoUtil::readU4(file);
}
// CONSTANT_Utf8_info
void CONSTANT_Utf8_info::readFrom(std::istream& file) {
// 读取长度
length = IoUtil::readU2(file);
delete[] bytes;
// 读取字符串数据
if (length > 0) {
bytes = new u1[length];
for (u2 i = 0; i < length; i++) {
bytes[i] = IoUtil::readU1(file);
}
} else {
bytes = nullptr;
}
}
读取代码
这里注意几点
- long和duble占用两个索引
- 常量池的个数是constant_pool_count-1
- 我这里设计的ConstPool会用一个空的展位下标为0的
cpp
// 读取常量池
void ClassFileReader::readConstantPool(std::istream& file, ClassFile* classFile) {
classFile->constant_pool_count = IoUtil::readU2(file);
// 创建新的常量池对象
classFile->constant_pool = new ConstPool();
// 读取每个常量池项
for (u2 i = 1; i < classFile->constant_pool_count; i++) {
u1 tag = IoUtil::readU1(file);
// 使用工厂创建对应的常量池对象
auto constant = std::unique_ptr<constant_pool_info>(ConstantPoolFactory::createConstant(tag));
if (!constant) {
throw std::runtime_error("Invalid constant pool tag: " + std::to_string(tag));
}
// 根据类型填充具体数据
constant->readFrom(file);
// 添加到常量池
classFile->constant_pool->addConstant(std::move(constant));
// Long和Double类型占用两个位置,需要跳过下一个位置
if (ConstantPoolFactory::takesTwoSlots(tag)) {
i++; // 跳过下一个位置,常量池会自动处理
}
}
classFile->constant_pool->nameMapping();
}
运行代码展示
示例代码 本期略,发现还没实现完善的toString
结束以及参考
本文重点在于分享常量池的数据结构定义,实现代码较为简单不是本文重点。这里充分利用面向对象的设计思路,把解析分担给各个实现类。
参考和链接: