Files
jvm_emulator/classfile.h
T
2026-03-30 19:20:11 +00:00

222 lines
8.0 KiB
C

#ifndef CLASSFILE_H
#define CLASSFILE_H
#include <stdint.h>
#include <stddef.h>
#include <string.h>
// https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.htmls table 4.3
#define CP_UTF8 1
#define CP_INTEGER 3
#define CP_FLOAT 4
#define CP_LONG 5
#define CP_DOUBLE 6
#define CP_CLASS 7
#define CP_STRING 8
#define CP_FIELDREF 9
#define CP_METHODREF 10
#define CP_IFACE_METHODREF 11
#define CP_NAME_AND_TYPE 12
// https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html table 4.1
#define ACC_PUBLIC 0x0001
#define ACC_PRIVATE 0x0002
#define ACC_PROTECTED 0x0004
#define ACC_STATIC 0x0008
#define ACC_FINAL 0x0010
#define ACC_SYNCHRONIZED 0x0020
#define ACC_NATIVE 0x0100
#define ACC_ABSTRACT 0x0400
/* ── opcodes we handle ──────────────────────────────────────────────────── */
#define OP_NOP 0x00
#define OP_ACONST_NULL 0x01
#define OP_ICONST_M1 0x02
#define OP_ICONST_0 0x03
#define OP_ICONST_1 0x04
#define OP_ICONST_2 0x05
#define OP_ICONST_3 0x06
#define OP_ICONST_4 0x07
#define OP_ICONST_5 0x08
#define OP_LCONST_0 0x09
#define OP_LCONST_1 0x0A
#define OP_BIPUSH 0x10
#define OP_SIPUSH 0x11
#define OP_LDC 0x12
#define OP_LDC_W 0x13
#define OP_LDC2_W 0x14
#define OP_ILOAD 0x15
#define OP_ALOAD 0x19
#define OP_ILOAD_0 0x1A
#define OP_ILOAD_1 0x1B
#define OP_ILOAD_2 0x1C
#define OP_ILOAD_3 0x1D
#define OP_ALOAD_0 0x2A
#define OP_ALOAD_1 0x2B
#define OP_ALOAD_2 0x2C
#define OP_ALOAD_3 0x2D
#define OP_IALOAD 0x2E
#define OP_ISTORE 0x36
#define OP_ASTORE 0x3A
#define OP_ISTORE_0 0x3B
#define OP_ISTORE_1 0x3C
#define OP_ISTORE_2 0x3D
#define OP_ISTORE_3 0x3E
#define OP_ASTORE_0 0x4B
#define OP_ASTORE_1 0x4C
#define OP_ASTORE_2 0x4D
#define OP_ASTORE_3 0x4E
#define OP_IASTORE 0x4F
#define OP_POP 0x57
#define OP_POP2 0x58
#define OP_DUP 0x59
#define OP_DUP_X1 0x5A
#define OP_SWAP 0x5F
#define OP_IADD 0x60
#define OP_LADD 0x61
#define OP_ISUB 0x64
#define OP_IMUL 0x68
#define OP_IDIV 0x6C
#define OP_IREM 0x70
#define OP_INEG 0x74
#define OP_ISHL 0x78
#define OP_ISHR 0x7A
#define OP_IUSHR 0x7C
#define OP_IAND 0x7E
#define OP_IOR 0x80
#define OP_IXOR 0x82
#define OP_IINC 0x84
#define OP_I2L 0x85
#define OP_I2C 0x92
#define OP_LCMP 0x94
#define OP_IFEQ 0x99
#define OP_IFNE 0x9A
#define OP_IFLT 0x9B
#define OP_IFGE 0x9C
#define OP_IFGT 0x9D
#define OP_IFLE 0x9E
#define OP_IF_ICMPEQ 0x9F
#define OP_IF_ICMPNE 0xA0
#define OP_IF_ICMPLT 0xA1
#define OP_IF_ICMPGE 0xA2
#define OP_IF_ICMPGT 0xA3
#define OP_IF_ICMPLE 0xA4
#define OP_IF_ACMPEQ 0xA5
#define OP_IF_ACMPNE 0xA6
#define OP_GOTO 0xA7
#define OP_IRETURN 0xAC
#define OP_LRETURN 0xAD
#define OP_ARETURN 0xB0
#define OP_RETURN 0xB1
#define OP_GETSTATIC 0xB2
#define OP_PUTSTATIC 0xB3
#define OP_GETFIELD 0xB4
#define OP_PUTFIELD 0xB5
#define OP_INVOKEVIRTUAL 0xB6
#define OP_INVOKESPECIAL 0xB7
#define OP_INVOKESTATIC 0xB8
#define OP_NEW 0xBB
#define OP_NEWARRAY 0xBC
#define OP_ANEWARRAY 0xBD
#define OP_ARRAYLENGTH 0xBE
#define OP_ATHROW 0xBF
#define OP_CHECKCAST 0xC0
#define OP_INSTANCEOF 0xC1
#define OP_IFNULL 0xC6
#define OP_IFNONNULL 0xC7
/* ── constant pool entry ────────────────────────────────────────────────── */
typedef struct {
uint8_t tag;
union {
/* CP_UTF8 */
struct { uint16_t len; char *bytes; } utf8;
/* CP_INTEGER */
struct { int32_t value; } integer;
/* CP_FLOAT */
struct { float value; } flt;
/* CP_LONG */
struct { int64_t value; } lng;
/* CP_DOUBLE */
struct { double value; } dbl;
/* CP_CLASS, CP_STRING */
struct { uint16_t index; } cls_or_str;
/* CP_FIELDREF, CP_METHODREF, CP_IFACE_METHODREF */
struct { uint16_t class_index; uint16_t name_and_type_index; } ref;
/* CP_NAME_AND_TYPE */
struct { uint16_t name_index; uint16_t descriptor_index; } nat;
};
} CPEntry;
/* ── exception handler table entry ─────────────────────────────────────── */
typedef struct {
uint16_t start_pc;
uint16_t end_pc;
uint16_t handler_pc;
uint16_t catch_type; /* CP index to Class, or 0 = catch all */
} ExceptionHandler;
/* ── Code attribute (lives inside a Method) ─────────────────────────────── */
typedef struct {
uint16_t max_stack;
uint16_t max_locals;
uint32_t code_len;
uint8_t *code;
uint16_t exception_table_len;
ExceptionHandler *exception_table;
} CodeAttr;
/* ── field ──────────────────────────────────────────────────────────────── */
typedef struct {
uint16_t access_flags;
uint16_t name_index; /* → CP_UTF8 */
uint16_t descriptor_index; /* → CP_UTF8 */
} Field;
/* ── method ─────────────────────────────────────────────────────────────── */
typedef struct {
uint16_t access_flags;
uint16_t name_index; /* → CP_UTF8 */
uint16_t descriptor_index; /* → CP_UTF8 */
CodeAttr code; /* zeroed if native/abstract */
int has_code;
} Method;
/* ── top-level class file ───────────────────────────────────────────────── */
typedef struct {
uint16_t minor_version;
uint16_t major_version; /* 46 = Java 1.2 … 50 = Java 6 */
uint16_t cp_count; /* constant_pool_count from spec (1-indexed) */
CPEntry *cp; /* cp[1..cp_count-1], cp[0] unused */
uint16_t access_flags;
uint16_t this_class; /* CP index */
uint16_t super_class; /* CP index (0 = java/lang/Object) */
uint16_t interfaces_count;
uint16_t *interfaces; /* array of CP indices */
uint16_t fields_count;
Field *fields;
uint16_t methods_count;
Method *methods;
} ClassFile;
/* ── helper: resolve UTF8 string from CP ───────────────────────────────── */
static inline const char *cp_utf8(const ClassFile *cf, uint16_t idx) {
if (idx == 0 || idx >= cf->cp_count) return "";
if (cf->cp[idx].tag != CP_UTF8) return "";
return cf->cp[idx].utf8.bytes;
}
/* ── function declarations ──────────────────────────────────────────────── */
ClassFile *classfile_load(const char *path);
void classfile_free(ClassFile *cf);
Method *classfile_find_method(ClassFile *cf, const char *name, const char *descriptor);
void classfile_dump(const ClassFile *cf); /* debug print */
#endif /* CLASSFILE_H */