commit 39f53e8ee416a489afb8c2d0d37da0b3dcd70d99 Author: Zack Buhman Date: Mon Dec 23 14:41:20 2024 -0600 initial diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2556324 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +.~* +*.o +*.d +*.gch +*.csv +*.class +main +print_class \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..fb05457 --- /dev/null +++ b/Makefile @@ -0,0 +1,51 @@ +%.csv: %.ods + libreoffice --headless --convert-to csv:"Text - txt - csv (StarCalc)":44,34,76,,,,true --outdir $(dir $@) $< + +%.class: %.java + javac $< + +OBJ = \ + c/decode.o \ + c/class_file.o \ + c/debug_class_file.o \ + c/malloc.o \ + c/file.o \ + c/execute.o \ + c/memory_allocator.o + +MAIN_OBJ = \ + $(OBJ) \ + c/frame.o + +PRINT_CLASS_OBJ = \ + $(OBJ) \ + c/print_class.o \ + +CC ?= gcc +ARCH = -m32 +CFLAGS ?= -Wall -Werror -Wfatal-errors -Wno-error=unused-variable -std=c2x -DDEBUG -g +OPT ?= -Og +DEPFLAGS = -MMD -MP + +%.o: %.c + $(CC) $(ARCH) $(CFLAGS) $(OPT) $(DEPFLAGS) -MF ${<}.d -c $< -o $@ + +print_class: $(PRINT_CLASS_OBJ) + $(CC) $(ARCH) $^ -o $@ + +main: $(MAIN_OBJ) + $(CC) $(ARCH) $^ -o $@ + +clean: + rm -f main print_class c/*.o + +.SUFFIXES: +.INTERMEDIATE: +.SECONDARY: +.PHONY: all clean phony + +%: RCS/%,v +%: RCS/% +%: %,v +%: s.% +%: SCCS/s.% diff --git a/c/a.out b/c/a.out new file mode 100755 index 0000000..ef552a8 Binary files /dev/null and b/c/a.out differ diff --git a/c/bswap.h b/c/bswap.h new file mode 100644 index 0000000..d745044 --- /dev/null +++ b/c/bswap.h @@ -0,0 +1,7 @@ +#pragma once + +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +#define BE_BSWAP32(n) (n) +#else +#define BE_BSWAP32(n) (__builtin_bswap32(n)) +#endif diff --git a/c/bytes.h b/c/bytes.h new file mode 100644 index 0000000..0943767 --- /dev/null +++ b/c/bytes.h @@ -0,0 +1,80 @@ +#include + +#include "malloc.h" + +static inline uint32_t parse_u4(const uint8_t ** buf) +{ + uint32_t n = + (*buf)[0] << 24 + | (*buf)[1] << 16 + | (*buf)[2] << 8 + | (*buf)[3] << 0 + ; + (*buf) += 4; + return n; +} + +static inline uint32_t parse_u2(const uint8_t ** buf) +{ + uint32_t n = + (*buf)[0] << 8 + | (*buf)[1] << 0 + ; + (*buf) += 2; + return n; +} + +static inline uint32_t parse_u1(const uint8_t ** buf) +{ + uint32_t n = (*buf)[0]; + (*buf) += 1; + return n; +} + +static inline int32_t parse_s4(const uint8_t ** buf) +{ + int32_t n = + (*buf)[0] << 24 + | (*buf)[1] << 16 + | (*buf)[2] << 8 + | (*buf)[3] << 0 + ; + (*buf) += 4; + return n; +} + +static inline int32_t parse_s2(const uint8_t ** buf) +{ + int16_t n = + (*buf)[0] << 8 + | (*buf)[1] << 0 + ; + (*buf) += 2; + return n; +} + +static inline int32_t parse_s1(const uint8_t ** buf) +{ + int8_t n = (*buf)[0]; + (*buf) += 1; + return n; +} + +static inline void * parse_bytes(const uint8_t ** buf, int length) +{ + uint8_t * dest = malloc_class_arena(length); + for (int i = 0; i < length; i++) + dest[i] = (*buf)[i]; + (*buf) += length; + return dest; +} + +static inline bool bytes_equal(int length, const uint8_t * a, const char * b) +{ + int i; + for (i = 0; i < length; i++) { + if (((char)a[i]) != ((char)b[i])) + return false; + } + return b[i] == 0; +} diff --git a/c/class_file.c b/c/class_file.c new file mode 100644 index 0000000..332aa81 --- /dev/null +++ b/c/class_file.c @@ -0,0 +1,225 @@ +#ifdef DEBUG +#include +#endif + +#include "class_file.h" +#include "malloc.h" +#include "bytes.h" + +struct attribute_info * attribute_info_parse(const uint8_t ** buf, int attribute_count, struct constant * constant_pool); + +void * attribute_info_parse_info(const uint8_t * buf, struct attribute_info * attribute, struct constant * constant_pool) +{ + struct constant * attribute_name = &constant_pool[attribute->attribute_name_index - 1]; +#ifdef DEBUG + assert(attribute_name->tag == CONSTANT_Utf8); +#endif + + if (bytes_equal(attribute_name->utf8.length, attribute_name->utf8.bytes, "ConstantValue")) { + struct ConstantValue_attribute * constantvalue = malloc_class_arena((sizeof (struct ConstantValue_attribute))); + constantvalue->constantvalue_index = parse_u2(&buf); + return constantvalue; + } else if (bytes_equal(attribute_name->utf8.length, attribute_name->utf8.bytes, "Code")) { + // parse Code + struct Code_attribute * code = malloc_class_arena((sizeof (struct Code_attribute))); + + code->max_stack = parse_u2(&buf); + code->max_locals = parse_u2(&buf); + code->code_length = parse_u4(&buf); + + code->code = parse_bytes(&buf, code->code_length); + code->exception_table_length = parse_u2(&buf); + uint32_t exception_table_size = (sizeof (struct exception_table_entry)) * code->exception_table_length; + code->exception_table = malloc_class_arena(exception_table_size); + for (int i = 0; i < code->exception_table_length; i++) { + // parse exception_table_entry + code->exception_table[i].start_pc = parse_u2(&buf); + code->exception_table[i].end_pc = parse_u2(&buf); + code->exception_table[i].handler_pc = parse_u2(&buf); + code->exception_table[i].catch_type = parse_u2(&buf); + } + code->attributes_count = parse_u2(&buf); + + code->attributes = attribute_info_parse(&buf, code->attributes_count, constant_pool); + + return code; + } else if (bytes_equal(attribute_name->utf8.length, attribute_name->utf8.bytes, "BootstrapMethods")) { + // parse BootstrapMethods + struct BootstrapMethods_attribute * bootstrapmethods = malloc_class_arena((sizeof (struct BootstrapMethods_attribute))); + + bootstrapmethods->num_bootstrap_methods = parse_u2(&buf); + + uint32_t bootstrap_methods_size = (sizeof (struct bootstrap_method)) * bootstrapmethods->num_bootstrap_methods; + bootstrapmethods->bootstrap_methods = malloc_class_arena(bootstrap_methods_size); + + for (int i = 0; i < bootstrapmethods->num_bootstrap_methods; i++) { + bootstrapmethods->bootstrap_methods[i].bootstrap_method_ref = parse_u2(&buf); + bootstrapmethods->bootstrap_methods[i].num_bootstrap_arguments = parse_u2(&buf); + + uint32_t bootstrap_arguments_size = (sizeof (u2)) * bootstrapmethods->bootstrap_methods[i].num_bootstrap_arguments; + bootstrapmethods->bootstrap_methods[i].bootstrap_arguments = malloc_class_arena(bootstrap_arguments_size); + for (int j = 0; j < bootstrapmethods->bootstrap_methods[i].num_bootstrap_arguments; j++) { + bootstrapmethods->bootstrap_methods[i].bootstrap_arguments[j] = parse_u2(&buf); + } + } + + return bootstrapmethods; + } else if (bytes_equal(attribute_name->utf8.length, attribute_name->utf8.bytes, "BootstrapMethods")) { + } else if (bytes_equal(attribute_name->utf8.length, attribute_name->utf8.bytes, "NestHost")) { + struct NestHost_attribute * nesthost = malloc_class_arena((sizeof (struct NestHost_attribute))); + nesthost->host_class_index = parse_u2(&buf); + + return nesthost; + } else if (bytes_equal(attribute_name->utf8.length, attribute_name->utf8.bytes, "NestMembers")) { + struct NestMembers_attribute * nestmembers = malloc_class_arena((sizeof (struct NestMembers_attribute))); + + nestmembers->number_of_classes = parse_u2(&buf); + uint32_t classes_size = (sizeof (u2)) * nestmembers->number_of_classes; + nestmembers->classes = malloc_class_arena(classes_size); + + for (int i = 0; i < nestmembers->number_of_classes; i++) { + nestmembers->classes[i] = parse_u2(&buf); + } + + return nestmembers; + } else { + return nullptr; + } + + assert(false); +} + +struct attribute_info * attribute_info_parse(const uint8_t ** buf, int attribute_count, struct constant * constant_pool) +{ + uint32_t attributes_size = (sizeof (struct attribute_info)) * attribute_count; + struct attribute_info * attributes = malloc_class_arena(attributes_size); + for (int i = 0; i < attribute_count; i++) { + attributes[i].attribute_name_index = parse_u2(buf); + attributes[i].attribute_length = parse_u4(buf); + + attributes[i].info = attribute_info_parse_info(*buf, &attributes[i], constant_pool); + + (*buf) += attributes[i].attribute_length; + } + return attributes; +} + +struct class_file * class_file_parse(const uint8_t * buf) +{ + struct class_file * class_file = malloc_class_arena((sizeof (struct class_file))); + + class_file->magic = parse_u4(&buf); + class_file->minor_version = parse_u2(&buf); + class_file->major_version = parse_u2(&buf); + class_file->constant_pool_count = parse_u2(&buf); + + uint32_t constant_pool_size = (sizeof (struct constant)) * (class_file->constant_pool_count - 1); + class_file->constant_pool = malloc_class_arena(constant_pool_size); + + // parse constants + for (int i = 0; i < class_file->constant_pool_count - 1; i++) { + struct constant * constant = &class_file->constant_pool[i]; + u1 tag = parse_u1(&buf); + #ifdef DEBUG + constant->tag = tag; + #endif + switch (tag) { + case CONSTANT_Class: + constant->class.name_index = parse_u2(&buf); + break; + case CONSTANT_Fieldref: [[fallthrough]]; + case CONSTANT_Methodref: [[fallthrough]]; + case CONSTANT_InterfaceMethodref: + constant->fieldref.class_index = parse_u2(&buf); + constant->fieldref.name_and_type_index = parse_u2(&buf); + break; + case CONSTANT_String: + constant->string.string_index = parse_u2(&buf); + break; + case CONSTANT_Integer: [[fallthrough]]; + case CONSTANT_Float: + constant->integer.bytes = parse_u4(&buf); + break; + case CONSTANT_Long: [[fallthrough]]; + case CONSTANT_Double: + constant->_long.high_bytes = parse_u4(&buf); + constant->_long.low_bytes = parse_u4(&buf); + break; + case CONSTANT_NameAndType: + constant->nameandtype.name_index = parse_u2(&buf); + constant->nameandtype.descriptor_index = parse_u2(&buf); + break; + case CONSTANT_Utf8: + constant->utf8.length = parse_u2(&buf); + constant->utf8.bytes = parse_bytes(&buf, constant->utf8.length); + break; + case CONSTANT_MethodHandle: + constant->methodhandle.reference_kind = parse_u1(&buf); + constant->methodhandle.reference_index = parse_u2(&buf); + break; + case CONSTANT_MethodType: + constant->methodtype.descriptor_index = parse_u2(&buf); + break; + case CONSTANT_Dynamic: [[fallthrough]]; + case CONSTANT_InvokeDynamic: + constant->dynamic.bootstrap_method_attr_index = parse_u2(&buf); + constant->dynamic.name_and_type_index = parse_u2(&buf); + break; + case CONSTANT_Module: [[fallthrough]]; + case CONSTANT_Package: + constant->module.name_index = parse_u2(&buf); + break; + default: + #ifdef DEBUG + assert(false); + #endif + break; + } + } + + class_file->access_flags = parse_u2(&buf); + class_file->this_class = parse_u2(&buf); + class_file->super_class = parse_u2(&buf); + class_file->interfaces_count = parse_u2(&buf); + + // parse interfaces + uint32_t interfaces_size = (sizeof (class_file->interfaces[0])) * class_file->interfaces_count; + class_file->interfaces = malloc_class_arena(interfaces_size); + for (int i = 0; i < class_file->interfaces_count; i++) + class_file->interfaces[i] = parse_u2(&buf); + + // parse fields + class_file->fields_count = parse_u2(&buf); + uint32_t fields_size = (sizeof (struct field_info)) * class_file->fields_count; + class_file->fields = malloc_class_arena(fields_size); + for (int i = 0; i < class_file->fields_count; i++) { + class_file->fields[i].access_flags = parse_u2(&buf); + class_file->fields[i].name_index = parse_u2(&buf); + class_file->fields[i].descriptor_index = parse_u2(&buf); + class_file->fields[i].attributes_count = parse_u2(&buf); + + // parse attributes + class_file->fields[i].attributes = attribute_info_parse(&buf, class_file->fields[i].attributes_count, class_file->constant_pool); + } + + + // parse methods + class_file->methods_count = parse_u2(&buf); + uint32_t methods_size = (sizeof (struct method_info)) * class_file->methods_count; + class_file->methods = malloc_class_arena(methods_size); + for (int i = 0; i < class_file->methods_count; i++) { + class_file->methods[i].access_flags = parse_u2(&buf); + class_file->methods[i].name_index = parse_u2(&buf); + class_file->methods[i].descriptor_index = parse_u2(&buf); + class_file->methods[i].attributes_count = parse_u2(&buf); + + // parse attributes + class_file->methods[i].attributes = attribute_info_parse(&buf, class_file->methods[i].attributes_count, class_file->constant_pool); + } + + // parse attributes + class_file->attributes_count = parse_u2(&buf); + class_file->attributes = attribute_info_parse(&buf, class_file->attributes_count, class_file->constant_pool); + + return class_file; +} diff --git a/c/class_file.h b/c/class_file.h new file mode 100644 index 0000000..b621f41 --- /dev/null +++ b/c/class_file.h @@ -0,0 +1,271 @@ +#pragma once + +#include + +typedef uint32_t u4; +typedef uint16_t u2; +typedef uint8_t u1; + +enum CONSTANT { + CONSTANT_Class = 7, // §4.4.1 + CONSTANT_Fieldref = 9, // §4.4.2 + CONSTANT_Methodref = 10, // §4.4.2 + CONSTANT_InterfaceMethodref = 11, // §4.4.2 + CONSTANT_String = 8, // §4.4.3 + CONSTANT_Integer = 3, // §4.4.4 + CONSTANT_Float = 4, // §4.4.4 + CONSTANT_Long = 5, // §4.4.5 + CONSTANT_Double = 6, // §4.4.5 + CONSTANT_NameAndType = 12, // §4.4.6 + CONSTANT_Utf8 = 1, // §4.4.7 + CONSTANT_MethodHandle = 15, // §4.4.8 + CONSTANT_MethodType = 16, // §4.4.9 + CONSTANT_Dynamic = 17, // §4.4.10 + CONSTANT_InvokeDynamic = 18, // §4.4.10 + CONSTANT_Module = 19, // §4.4.11 + CONSTANT_Package = 20, // §4.4.12 +}; + +struct constant_Class_info { + u2 name_index; +}; + +struct constant_Fieldref_info { + u2 class_index; + u2 name_and_type_index; +}; + +struct constant_Methodref_info { + u2 class_index; + u2 name_and_type_index; +}; + +struct constant_InterfaceMethodref_info { + u2 class_index; + u2 name_and_type_index; +}; + +struct constant_String_info { + u2 string_index; +}; + +struct constant_Integer_info { + u4 bytes; +}; + +struct constant_Float_info { + u4 bytes; +}; + +struct constant_Long_info { + u4 high_bytes; + u4 low_bytes; +}; + +struct constant_Double_info { + u4 high_bytes; + u4 low_bytes; +}; + +struct constant_NameAndType_info { + u2 name_index; + u2 descriptor_index; +}; + +struct constant_Utf8_info { + u2 length; + u1 * bytes; +}; + +struct constant_MethodHandle_info { + u1 reference_kind; + u2 reference_index; +}; + +struct constant_MethodType_info { + u2 descriptor_index; +}; + +struct constant_Dynamic_info { + u2 bootstrap_method_attr_index; + u2 name_and_type_index; +}; + +struct constant_InvokeDynamic_info { + u2 bootstrap_method_attr_index; + u2 name_and_type_index; +}; + +struct constant_Module_info { + u2 name_index; +}; + +struct constant_Package_info { + u2 name_index; +}; + +struct constant { + #ifdef DEBUG + u1 tag; + #endif + union { + struct constant_Class_info class; + struct constant_Fieldref_info fieldref; + struct constant_Methodref_info methodref; + struct constant_InterfaceMethodref_info interfacemethodref; + struct constant_String_info string; + struct constant_Integer_info integer; + struct constant_Float_info _float; + struct constant_Long_info _long; + struct constant_Double_info _double; + struct constant_NameAndType_info nameandtype; + struct constant_Utf8_info utf8; + struct constant_MethodHandle_info methodhandle; + struct constant_MethodType_info methodtype; + struct constant_Dynamic_info dynamic; + struct constant_InvokeDynamic_info invokedynamic; + struct constant_Module_info module; + struct constant_Package_info package; + }; +}; + +struct ConstantValue_attribute; +struct Code_attribute; +struct StackMapTable_attribute; +struct BootstrapMethods_attribute; +struct NestHost_attribute; +struct NestMembers_attribute; +struct PermittedSubclasses_attribute; + +struct attribute_info { + u2 attribute_name_index; + u4 attribute_length; + union { + void * info; + struct ConstantValue_attribute * constantvalue; + struct Code_attribute * code; + //struct StackMapTable_attribute * stackmaptable; + struct BootstrapMethods_attribute * bootstrapmethods; + struct NestHost_attribute * nesthost; + struct NestMembers_attribute * nestmembers; + //struct PermittedSubclasses_attribute * permittedsubclasses; + }; +}; + +struct ConstantValue_attribute { + u2 constantvalue_index; +}; + +struct exception_table_entry { + u2 start_pc; + u2 end_pc; + u2 handler_pc; + u2 catch_type; +}; + +struct Code_attribute { + u2 max_stack; + u2 max_locals; + u4 code_length; + u1 * code; + u2 exception_table_length; + struct exception_table_entry * exception_table; + u2 attributes_count; + struct attribute_info * attributes; +}; + +struct bootstrap_method { + u2 bootstrap_method_ref; + u2 num_bootstrap_arguments; + u2 * bootstrap_arguments; +}; + +struct BootstrapMethods_attribute { + u2 num_bootstrap_methods; + struct bootstrap_method * bootstrap_methods; +}; + +struct NestHost_attribute { + u2 host_class_index; +}; + +struct NestMembers_attribute { + u2 number_of_classes; + u2 * classes; +}; + +enum FIELD_ACC { + FIELD_ACC_PUBLIC = 0x0001, // Declared public; may be accessed from outside its package. + FIELD_ACC_PRIVATE = 0x0002, // Declared private; accessible only within the defining class and other classes belonging to the same nest (§5.4.4). + FIELD_ACC_PROTECTED = 0x0004, // Declared protected; may be accessed within subclasses. + FIELD_ACC_STATIC = 0x0008, // Declared static. + FIELD_ACC_FINAL = 0x0010, // Declared final; never directly assigned to after object construction (JLS §17.5). + FIELD_ACC_VOLATILE = 0x0040, // Declared volatile; cannot be cached. + FIELD_ACC_TRANSIENT = 0x0080, // Declared transient; not written or read by a persistent object manager. + FIELD_ACC_SYNTHETIC = 0x1000, // Declared synthetic; not present in the source code. + FIELD_ACC_ENUM = 0x4000, // Declared as an element of an enum class. +}; + +struct field_info { + u2 access_flags; + u2 name_index; + u2 descriptor_index; + u2 attributes_count; + struct attribute_info * attributes; +}; + +enum METHOD_ACC { + METHOD_ACC_PUBLIC = 0x0001, // Declared public; may be accessed from outside its package. + METHOD_ACC_PRIVATE = 0x0002, // Declared private; accessible only within the defining class and other classes belonging to the same nest (§5.4.4). + METHOD_ACC_PROTECTED = 0x0004, // Declared protected; may be accessed within subclasses. + METHOD_ACC_STATIC = 0x0008, // Declared static. + METHOD_ACC_FINAL = 0x0010, // Declared final; must not be overridden (§5.4.5). + METHOD_ACC_SYNCHRONIZED = 0x0020, // Declared synchronized; invocation is wrapped by a monitor use. + METHOD_ACC_BRIDGE = 0x0040, // A bridge method, generated by the compiler. + METHOD_ACC_VARARGS = 0x0080, // Declared with variable number of arguments. + METHOD_ACC_NATIVE = 0x0100, // Declared native; implemented in a language other than the Java programming language. + METHOD_ACC_ABSTRACT = 0x0400, // Declared abstract; no implementation is provided. + METHOD_ACC_STRICT = 0x0800, // In a class file whose major version number is at least 46 and at most 60: Declared strictfp. + METHOD_ACC_SYNTHETIC = 0x1000, // Declared synthetic; not present in the source code. +}; + +struct method_info { + u2 access_flags; + u2 name_index; + u2 descriptor_index; + u2 attributes_count; + struct attribute_info * attributes; +}; + +enum CLASS_ACC { + CLASS_ACC_PUBLIC = 0x0001, // Declared public; may be accessed from outside its package. + CLASS_ACC_FINAL = 0x0010, // Declared final; no subclasses allowed. + CLASS_ACC_SUPER = 0x0020, // Treat superclass methods specially when invoked by the invokespecial instruction. + CLASS_ACC_INTERFACE = 0x0200, // Is an interface, not a class. + CLASS_ACC_ABSTRACT = 0x0400, // Declared abstract; must not be instantiated. + CLASS_ACC_SYNTHETIC = 0x1000, // Declared synthetic; not present in the source code. + CLASS_ACC_ANNOTATION = 0x2000, // Declared as an annotation interface. + CLASS_ACC_ENUM = 0x4000, // Declared as an enum class. + CLASS_ACC_MODULE = 0x8000, // Is a module, not a class or interface. +}; + +struct class_file { + u4 magic; + u2 minor_version; + u2 major_version; + u2 constant_pool_count; + struct constant * constant_pool; + u2 access_flags; + u2 this_class; + u2 super_class; + u2 interfaces_count; + u2 * interfaces; + u2 fields_count; + struct field_info * fields; + u2 methods_count; + struct method_info * methods; + u2 attributes_count; + struct attribute_info * attributes; +}; + +struct class_file * class_file_parse(const uint8_t * buf); diff --git a/c/constant.h b/c/constant.h new file mode 100644 index 0000000..e69de29 diff --git a/c/debug_class_file.c b/c/debug_class_file.c new file mode 100644 index 0000000..21c1dfa --- /dev/null +++ b/c/debug_class_file.c @@ -0,0 +1,278 @@ +#include +#include +#include +#include + +#include "class_file.h" +#include "bytes.h" +#include "decode.h" +#include "debug_class_file.h" + +void print_constant(struct constant * constant) +{ + switch (constant->tag) { + case CONSTANT_Class: + printf("CONSTANT_Class name_index=%d\n", + constant->class.name_index); + break; + case CONSTANT_Fieldref: + printf("CONSTANT_Fieldref class_index=%d name_and_type_index=%d\n", + constant->fieldref.class_index, + constant->fieldref.name_and_type_index); + break; + case CONSTANT_Methodref: + printf("CONSTANT_Methodref class_index=%d name_and_type_index=%d\n", + constant->methodref.class_index, + constant->methodref.name_and_type_index); + break; + case CONSTANT_InterfaceMethodref: + printf("CONSTANT_InterfaceMethodref class_index=%d name_and_type_index=%d\n", + constant->interfacemethodref.class_index, + constant->interfacemethodref.name_and_type_index); + break; + case CONSTANT_String: + printf("CONSTANT_String string_index=%d\n", + constant->string.string_index); + break; + case CONSTANT_Integer: + printf("CONSTANT_Integer bytes=%d\n", + constant->integer.bytes); + break; + case CONSTANT_Float: + printf("CONSTANT_Float bytes=%f\n", + *(float *)(&constant->_float.bytes)); + break; + case CONSTANT_Long: + printf("CONSTANT_Long high_bytes=%d low_bytes=%d\n", + constant->_long.high_bytes, + constant->_long.low_bytes); + break; + case CONSTANT_Double: + printf("CONSTANT_Double high_bytes=%d low_bytes=%d\n", + constant->_long.high_bytes, + constant->_long.low_bytes); + break; + case CONSTANT_NameAndType: + printf("CONSTANT_NameAndType %d %d\n", + constant->nameandtype.name_index, + constant->nameandtype.descriptor_index); + break; + case CONSTANT_Utf8: + printf("CONSTANT_Utf8 length=%d bytes=", + constant->utf8.length); + for (int i = 0; i < constant->utf8.length; i++) { + fputc(constant->utf8.bytes[i], stdout); + } + fputc('\n', stdout); + break; + case CONSTANT_MethodHandle: + printf("CONSTANT_MethodHandle reference_kind=%d reference_index=%d\n", + constant->methodhandle.reference_kind, + constant->methodhandle.reference_index); + break; + case CONSTANT_MethodType: + printf("CONSTANT_MethodType descriptor_index=%d\n", + constant->methodtype.descriptor_index); + break; + case CONSTANT_Dynamic: + printf("CONSTANT_Dynamic bootstrap_method_attr_index=%d name_and_type_index=%d\n", + constant->dynamic.bootstrap_method_attr_index, + constant->dynamic.name_and_type_index); + break; + case CONSTANT_InvokeDynamic: + printf("CONSTANT_InvokeDynamic bootstrap_method_attr_index=%d name_and_type_index=%d\n", + constant->invokedynamic.bootstrap_method_attr_index, + constant->invokedynamic.name_and_type_index); + break; + case CONSTANT_Module: + printf("CONSTANT_Module name_index=%d\n", + constant->module.name_index); + break; + case CONSTANT_Package: + printf("CONSTANT_Package name_index=%d\n", + constant->package.name_index); + break; + } +} + +void print_attribute(const char * indent, struct attribute_info * attribute, struct constant * constant_pool) +{ + fputs(indent, stdout); + printf("attribute_name_index: %d\n", attribute->attribute_name_index); + struct constant * attribute_name = &constant_pool[attribute->attribute_name_index - 1]; + fputs(indent, stdout); + fputs(" ", stdout); + print_constant(attribute_name); + + if (bytes_equal(attribute_name->utf8.length, attribute_name->utf8.bytes, "ConstantValue")) { + fputs(indent, stdout); + printf("constantvalue_index %d\n", attribute->constantvalue->constantvalue_index); + + + struct constant * value = &constant_pool[attribute->constantvalue->constantvalue_index - 1]; + fputs(indent, stdout); + fputs(" ", stdout); + print_constant(value); + if (value->tag == CONSTANT_String) { + fputs(indent, stdout); + fputs(" ", stdout); + print_constant(&constant_pool[value->string.string_index - 1]); + } + } else if (bytes_equal(attribute_name->utf8.length, attribute_name->utf8.bytes, "Code")) { + // print code + fputs(indent, stdout); + printf("max_stack %d\n", attribute->code->max_stack); + fputs(indent, stdout); + printf("max_locals %d\n", attribute->code->max_locals); + fputs(indent, stdout); + printf("code_length %d\n", attribute->code->code_length); + + // dump code + fputs(indent, stdout); + printf("code:\n"); + uint32_t pc = 0; + while (pc < attribute->code->code_length) { + fputs(indent, stdout); + fputs(" ", stdout); + pc = decode_print_instruction(attribute->code->code, pc); + } + + + fputs(indent, stdout); + printf("exception_table_length: %d\n", attribute->code->exception_table_length); + fputs(indent, stdout); + printf("exceptions:\n"); + for (int i = 0; i < attribute->code->exception_table_length; i++) { + fputs(indent, stdout); + printf(" exception %d:\n", i); + fputs(indent, stdout); + printf(" start_pc: %d\n", attribute->code->exception_table[i].start_pc); + fputs(indent, stdout); + printf(" end_pc: %d\n", attribute->code->exception_table[i].end_pc); + fputs(indent, stdout); + printf(" handler_pc: %d\n", attribute->code->exception_table[i].handler_pc); + fputs(indent, stdout); + printf(" catch_type: %d\n", attribute->code->exception_table[i].catch_type); + } + fputs(indent, stdout); + printf("attributes_count: %d\n", attribute->code->attributes_count); + fputs(indent, stdout); + printf("attributes:\n"); + for (int i = 0; i < attribute->code->attributes_count; i++) { + char indent2[strlen(indent) + 2 + 1]; + strcpy(indent2, indent); + strcpy(indent2 + strlen(indent), " "); + fputs(indent, stdout); + printf(" attribute %d:\n", i); + print_attribute(indent2, &attribute->code->attributes[i], constant_pool); + } + } else if (bytes_equal(attribute_name->utf8.length, attribute_name->utf8.bytes, "BootstrapMethods")) { + fputs(indent, stdout); + printf("num_bootstrap_methods: %d\n", attribute->bootstrapmethods->num_bootstrap_methods); + fputs(indent, stdout); + printf("bootstrap methods:\n"); + for (int i = 0; i < attribute->bootstrapmethods->num_bootstrap_methods; i++) { + fputs(indent, stdout); + printf(" bootstrap_method %d:\n", i); + fputs(indent, stdout); + printf(" bootstrap_method_ref: %d\n", attribute->bootstrapmethods->bootstrap_methods[i].bootstrap_method_ref); + fputs(indent, stdout); + printf(" num_bootstrap_arguments: %d\n", attribute->bootstrapmethods->bootstrap_methods[i].num_bootstrap_arguments); + fputs(indent, stdout); + printf(" bootstrap_arguments:\n"); + for (int j = 0; j < attribute->bootstrapmethods->bootstrap_methods[i].num_bootstrap_arguments; j++) { + fputs(indent, stdout); + printf(" bootstrap_argument %d: %d\n", j, attribute->bootstrapmethods->bootstrap_methods[i].bootstrap_arguments[j]); + } + } + } else if (bytes_equal(attribute_name->utf8.length, attribute_name->utf8.bytes, "NestHost")) { + fputs(indent, stdout); + printf("host_class_index: %d\n", attribute->nesthost->host_class_index); + } else if (bytes_equal(attribute_name->utf8.length, attribute_name->utf8.bytes, "NestMembers")) { + fputs(indent, stdout); + printf("number_of_classes: %d\n", attribute->nestmembers->number_of_classes); + fputs(indent, stdout); + printf("classes:\n"); + for (int i = 0; i < attribute->nestmembers->number_of_classes; i++) { + fputs(indent, stdout); + printf(" class %d:\n", i); + fputs(indent, stdout); + fputs(" ", stdout); + print_constant(&constant_pool[attribute->nestmembers->classes[i] - 1]); + int ix = constant_pool[attribute->nestmembers->classes[i] - 1].class.name_index; + fputs(indent, stdout); + fputs(" ", stdout); + print_constant(&constant_pool[ix - 1]); + } + } +} + +void print_class_file(struct class_file * class_file) +{ + printf("magic %08x\n", class_file->magic); + printf("minor_version %d\n", class_file->minor_version); + printf("major_version %d\n", class_file->major_version); + printf("constant_pool_count %d\n", class_file->constant_pool_count); + + printf("constants:\n"); + for (int i = 0; i < class_file->constant_pool_count - 1; i++) { + printf("% 3d: ", i + 1); + print_constant(&class_file->constant_pool[i]); + } + + printf("access_flags %04x\n", class_file->access_flags); + printf("this_class %d\n", class_file->this_class); + printf("super_class %d\n", class_file->super_class); + printf("interfaces_count %d\n", class_file->interfaces_count); + + printf("interfaces:\n"); + for (int i = 0; i < class_file->interfaces_count; i++) { + printf("% 3d: %d\n", i + 1, class_file->interfaces[i]); + } + + printf("fields_count %d\n", class_file->fields_count); + printf("fields:\n"); + for (int i = 0; i < class_file->fields_count; i++) { + printf(" field %d:\n", i); + printf(" access_flags %d\n", class_file->fields[i].access_flags); + printf(" name_index %d\n", class_file->fields[i].name_index); + printf(" "); + print_constant(&class_file->constant_pool[class_file->fields[i].name_index - 1]); + printf(" descriptor_index %d\n", class_file->fields[i].descriptor_index); + printf(" "); + print_constant(&class_file->constant_pool[class_file->fields[i].descriptor_index - 1]); + printf(" attributes_count %d\n", class_file->fields[i].attributes_count); + printf(" attributes:\n"); + for (int j = 0; j < class_file->fields[i].attributes_count; j++) { + printf(" attribute %d:\n", j); + print_attribute(" ", &class_file->fields[i].attributes[j], class_file->constant_pool); + } + } + + printf("methods_count %d\n", class_file->methods_count); + printf("methods:\n"); + for (int i = 0; i < class_file->methods_count; i++) { + printf(" method %d:\n", i); + printf(" access_flags %04x\n", class_file->methods[i].access_flags); + printf(" name_index %d\n", class_file->methods[i].name_index); + printf(" "); + print_constant(&class_file->constant_pool[class_file->methods[i].name_index - 1]); + printf(" descriptor_index %d\n", class_file->methods[i].descriptor_index); + printf(" "); + print_constant(&class_file->constant_pool[class_file->methods[i].descriptor_index - 1]); + printf(" attributes_count %d\n", class_file->methods[i].attributes_count); + printf(" attributes:\n"); + for (int j = 0; j < class_file->methods[i].attributes_count; j++) { + printf(" attribute %d:\n", j); + print_attribute(" ", &class_file->methods[i].attributes[j], class_file->constant_pool); + } + } + + + printf("attributes_count %d\n", class_file->attributes_count); + printf("attributes:\n"); + for (int i = 0; i < class_file->attributes_count; i++) { + printf(" attribute %d:\n", i); + print_attribute(" ", &class_file->attributes[i], class_file->constant_pool); + } +} diff --git a/c/debug_class_file.h b/c/debug_class_file.h new file mode 100644 index 0000000..895039d --- /dev/null +++ b/c/debug_class_file.h @@ -0,0 +1,7 @@ +#pragma once + +#include "class_file.h" + +void print_constant(struct constant * constant); +void print_attribute(const char * indent, struct attribute_info * attribute, struct constant * constant_pool); +void print_class_file(struct class_file * class_file); diff --git a/c/decode.c b/c/decode.c new file mode 100644 index 0000000..0557117 --- /dev/null +++ b/c/decode.c @@ -0,0 +1,97 @@ +#include +#include +#include + +#include "decode.h" +#include "execute.h" +#include "bswap.h" + +static inline uint32_t _u4(const uint8_t * buf) +{ + uint32_t n = + buf[0] << 24 + | buf[1] << 16 + | buf[2] << 8 + | buf[3] << 0 + ; + return n; +} + +static inline uint32_t _u2(const uint8_t * buf) +{ + uint32_t n = + buf[0] << 8 + | buf[1] << 0 + ; + return n; +} + +static inline uint32_t _u1(const uint8_t * buf) +{ + uint32_t n = buf[0]; + return n; +} + +static inline int32_t _s4(const uint8_t * buf) +{ + int32_t n = + buf[0] << 24 + | buf[1] << 16 + | buf[2] << 8 + | buf[3] << 0 + ; + return n; +} + +static inline int32_t _s2(const uint8_t * buf) +{ + int16_t n = + buf[0] << 8 + | buf[1] << 0 + ; + return n; +} + +static inline int32_t _s1(const uint8_t * buf) +{ + int8_t n = buf[0]; + return n; +} + +static inline int32_t aligned_s4(const void * buf) +{ + uint32_t n = *((uint32_t *)buf); + return BE_BSWAP32(n); +} + +#define TABLESWITCH_ARGS \ + uint32_t args = ((pc + 1) + 3) & (~3); \ + int32_t defaultbyte = aligned_s4(&code[args + 0]); \ + int32_t lowbyte = aligned_s4(&code[args + 4]); \ + int32_t highbyte = aligned_s4(&code[args + 8]); \ + const int32_t * table = (const int32_t *)&code[args + 12]; + +#define TABLESWITCH_PRINT_ARGS() \ + do { \ + for (int i = lowbyte; i <= highbyte; i++) { \ + printf(" %d: %d\n", i, aligned_s4(&table[i - lowbyte])); \ + } \ + printf("default: %d\n", defaultbyte); \ + } while (0); + +#define TABLESWITCH_NEXT_PC \ + (args + (3 * 4) + ((highbyte - lowbyte + 1) * 4)) + +#define LOOKUPSWITCH_ARGS assert(false); + +#define LOOKUPSWITCH_PRINT_ARGS() + +#define LOOKUPSWITCH_NEXT_PC 0 + +#define WIDE_ARGS assert(false); + +#define WIDE_PRINT_ARGS() + +#define WIDE_NEXT_PC 0 + +#include "decode.inc.c" diff --git a/c/decode.h b/c/decode.h new file mode 100644 index 0000000..703064f --- /dev/null +++ b/c/decode.h @@ -0,0 +1,6 @@ +#pragma once + +#include "frame.h" + +uint32_t decode_print_instruction(const uint8_t * code, uint32_t pc); +uint32_t decode_execute_instruction(struct vm * vm, const uint8_t * code, uint32_t pc); diff --git a/c/decode.inc.c b/c/decode.inc.c new file mode 100644 index 0000000..bb9adf3 --- /dev/null +++ b/c/decode.inc.c @@ -0,0 +1,2192 @@ +uint32_t decode_print_instruction(const uint8_t * code, uint32_t pc) +{ + switch (code[pc]) { + case 0: // nop + { + printf("%4d: nop \n", pc); + return pc + 1; + } + case 1: // aconst_null + { + printf("%4d: aconst_null \n", pc); + return pc + 1; + } + case 2: // iconst_m1 + { + printf("%4d: iconst_m1 \n", pc); + return pc + 1; + } + case 3: // iconst_0 + { + printf("%4d: iconst_0 \n", pc); + return pc + 1; + } + case 4: // iconst_1 + { + printf("%4d: iconst_1 \n", pc); + return pc + 1; + } + case 5: // iconst_2 + { + printf("%4d: iconst_2 \n", pc); + return pc + 1; + } + case 6: // iconst_3 + { + printf("%4d: iconst_3 \n", pc); + return pc + 1; + } + case 7: // iconst_4 + { + printf("%4d: iconst_4 \n", pc); + return pc + 1; + } + case 8: // iconst_5 + { + printf("%4d: iconst_5 \n", pc); + return pc + 1; + } + case 9: // lconst_0 + { + printf("%4d: lconst_0 \n", pc); + return pc + 1; + } + case 10: // lconst_1 + { + printf("%4d: lconst_1 \n", pc); + return pc + 1; + } + case 11: // fconst_0 + { + printf("%4d: fconst_0 \n", pc); + return pc + 1; + } + case 12: // fconst_1 + { + printf("%4d: fconst_1 \n", pc); + return pc + 1; + } + case 13: // fconst_2 + { + printf("%4d: fconst_2 \n", pc); + return pc + 1; + } + case 14: // dconst_0 + { + printf("%4d: dconst_0 \n", pc); + return pc + 1; + } + case 15: // dconst_1 + { + printf("%4d: dconst_1 \n", pc); + return pc + 1; + } + case 16: // bipush + { + int32_t byte = _s1(&code[pc + 1]); + printf("%4d: bipush %d\n", pc, byte); + return pc + 2; + } + case 17: // sipush + { + int32_t byte = _s2(&code[pc + 1]); + printf("%4d: sipush %d\n", pc, byte); + return pc + 3; + } + case 18: // ldc + { + uint32_t index = _u1(&code[pc + 1]); + printf("%4d: ldc %u\n", pc, index); + return pc + 2; + } + case 19: // ldc_w + { + uint32_t index = _u2(&code[pc + 1]); + printf("%4d: ldc_w %u\n", pc, index); + return pc + 3; + } + case 20: // ldc2_w + { + uint32_t index = _u2(&code[pc + 1]); + printf("%4d: ldc2_w %u\n", pc, index); + return pc + 3; + } + case 21: // iload + { + uint32_t index = _u1(&code[pc + 1]); + printf("%4d: iload %u\n", pc, index); + return pc + 2; + } + case 22: // lload + { + uint32_t index = _u1(&code[pc + 1]); + printf("%4d: lload %u\n", pc, index); + return pc + 2; + } + case 23: // fload + { + uint32_t index = _u1(&code[pc + 1]); + printf("%4d: fload %u\n", pc, index); + return pc + 2; + } + case 24: // dload + { + uint32_t index = _u1(&code[pc + 1]); + printf("%4d: dload %u\n", pc, index); + return pc + 2; + } + case 25: // aload + { + uint32_t index = _u1(&code[pc + 1]); + printf("%4d: aload %u\n", pc, index); + return pc + 2; + } + case 26: // iload_0 + { + printf("%4d: iload_0 \n", pc); + return pc + 1; + } + case 27: // iload_1 + { + printf("%4d: iload_1 \n", pc); + return pc + 1; + } + case 28: // iload_2 + { + printf("%4d: iload_2 \n", pc); + return pc + 1; + } + case 29: // iload_3 + { + printf("%4d: iload_3 \n", pc); + return pc + 1; + } + case 30: // lload_0 + { + printf("%4d: lload_0 \n", pc); + return pc + 1; + } + case 31: // lload_1 + { + printf("%4d: lload_1 \n", pc); + return pc + 1; + } + case 32: // lload_2 + { + printf("%4d: lload_2 \n", pc); + return pc + 1; + } + case 33: // lload_3 + { + printf("%4d: lload_3 \n", pc); + return pc + 1; + } + case 34: // fload_0 + { + printf("%4d: fload_0 \n", pc); + return pc + 1; + } + case 35: // fload_1 + { + printf("%4d: fload_1 \n", pc); + return pc + 1; + } + case 36: // fload_2 + { + printf("%4d: fload_2 \n", pc); + return pc + 1; + } + case 37: // fload_3 + { + printf("%4d: fload_3 \n", pc); + return pc + 1; + } + case 38: // dload_0 + { + printf("%4d: dload_0 \n", pc); + return pc + 1; + } + case 39: // dload_1 + { + printf("%4d: dload_1 \n", pc); + return pc + 1; + } + case 40: // dload_2 + { + printf("%4d: dload_2 \n", pc); + return pc + 1; + } + case 41: // dload_3 + { + printf("%4d: dload_3 \n", pc); + return pc + 1; + } + case 42: // aload_0 + { + printf("%4d: aload_0 \n", pc); + return pc + 1; + } + case 43: // aload_1 + { + printf("%4d: aload_1 \n", pc); + return pc + 1; + } + case 44: // aload_2 + { + printf("%4d: aload_2 \n", pc); + return pc + 1; + } + case 45: // aload_3 + { + printf("%4d: aload_3 \n", pc); + return pc + 1; + } + case 46: // iaload + { + printf("%4d: iaload \n", pc); + return pc + 1; + } + case 47: // laload + { + printf("%4d: laload \n", pc); + return pc + 1; + } + case 48: // faload + { + printf("%4d: faload \n", pc); + return pc + 1; + } + case 49: // daload + { + printf("%4d: daload \n", pc); + return pc + 1; + } + case 50: // aaload + { + printf("%4d: aaload \n", pc); + return pc + 1; + } + case 51: // baload + { + printf("%4d: baload \n", pc); + return pc + 1; + } + case 52: // caload + { + printf("%4d: caload \n", pc); + return pc + 1; + } + case 53: // saload + { + printf("%4d: saload \n", pc); + return pc + 1; + } + case 54: // istore + { + uint32_t index = _u1(&code[pc + 1]); + printf("%4d: istore %u\n", pc, index); + return pc + 2; + } + case 55: // lstore + { + uint32_t index = _u1(&code[pc + 1]); + printf("%4d: lstore %u\n", pc, index); + return pc + 2; + } + case 56: // fstore + { + uint32_t index = _u1(&code[pc + 1]); + printf("%4d: fstore %u\n", pc, index); + return pc + 2; + } + case 57: // dstore + { + uint32_t index = _u1(&code[pc + 1]); + printf("%4d: dstore %u\n", pc, index); + return pc + 2; + } + case 58: // astore + { + uint32_t index = _u1(&code[pc + 1]); + printf("%4d: astore %u\n", pc, index); + return pc + 2; + } + case 59: // istore_0 + { + printf("%4d: istore_0 \n", pc); + return pc + 1; + } + case 60: // istore_1 + { + printf("%4d: istore_1 \n", pc); + return pc + 1; + } + case 61: // istore_2 + { + printf("%4d: istore_2 \n", pc); + return pc + 1; + } + case 62: // istore_3 + { + printf("%4d: istore_3 \n", pc); + return pc + 1; + } + case 63: // lstore_0 + { + printf("%4d: lstore_0 \n", pc); + return pc + 1; + } + case 64: // lstore_1 + { + printf("%4d: lstore_1 \n", pc); + return pc + 1; + } + case 65: // lstore_2 + { + printf("%4d: lstore_2 \n", pc); + return pc + 1; + } + case 66: // lstore_3 + { + printf("%4d: lstore_3 \n", pc); + return pc + 1; + } + case 67: // fstore_0 + { + printf("%4d: fstore_0 \n", pc); + return pc + 1; + } + case 68: // fstore_1 + { + printf("%4d: fstore_1 \n", pc); + return pc + 1; + } + case 69: // fstore_2 + { + printf("%4d: fstore_2 \n", pc); + return pc + 1; + } + case 70: // fstore_3 + { + printf("%4d: fstore_3 \n", pc); + return pc + 1; + } + case 71: // dstore_0 + { + printf("%4d: dstore_0 \n", pc); + return pc + 1; + } + case 72: // dstore_1 + { + printf("%4d: dstore_1 \n", pc); + return pc + 1; + } + case 73: // dstore_2 + { + printf("%4d: dstore_2 \n", pc); + return pc + 1; + } + case 74: // dstore_3 + { + printf("%4d: dstore_3 \n", pc); + return pc + 1; + } + case 75: // astore_0 + { + printf("%4d: astore_0 \n", pc); + return pc + 1; + } + case 76: // astore_1 + { + printf("%4d: astore_1 \n", pc); + return pc + 1; + } + case 77: // astore_2 + { + printf("%4d: astore_2 \n", pc); + return pc + 1; + } + case 78: // astore_3 + { + printf("%4d: astore_3 \n", pc); + return pc + 1; + } + case 79: // iastore + { + printf("%4d: iastore \n", pc); + return pc + 1; + } + case 80: // lastore + { + printf("%4d: lastore \n", pc); + return pc + 1; + } + case 81: // fastore + { + printf("%4d: fastore \n", pc); + return pc + 1; + } + case 82: // dastore + { + printf("%4d: dastore \n", pc); + return pc + 1; + } + case 83: // aastore + { + printf("%4d: aastore \n", pc); + return pc + 1; + } + case 84: // bastore + { + printf("%4d: bastore \n", pc); + return pc + 1; + } + case 85: // castore + { + printf("%4d: castore \n", pc); + return pc + 1; + } + case 86: // sastore + { + printf("%4d: sastore \n", pc); + return pc + 1; + } + case 87: // pop + { + printf("%4d: pop \n", pc); + return pc + 1; + } + case 88: // pop2 + { + printf("%4d: pop2 \n", pc); + return pc + 1; + } + case 89: // dup + { + printf("%4d: dup \n", pc); + return pc + 1; + } + case 90: // dup_x1 + { + printf("%4d: dup_x1 \n", pc); + return pc + 1; + } + case 91: // dup_x2 + { + printf("%4d: dup_x2 \n", pc); + return pc + 1; + } + case 92: // dup2 + { + printf("%4d: dup2 \n", pc); + return pc + 1; + } + case 93: // dup2_x1 + { + printf("%4d: dup2_x1 \n", pc); + return pc + 1; + } + case 94: // dup2_x2 + { + printf("%4d: dup2_x2 \n", pc); + return pc + 1; + } + case 95: // swap + { + printf("%4d: swap \n", pc); + return pc + 1; + } + case 96: // iadd + { + printf("%4d: iadd \n", pc); + return pc + 1; + } + case 97: // ladd + { + printf("%4d: ladd \n", pc); + return pc + 1; + } + case 98: // fadd + { + printf("%4d: fadd \n", pc); + return pc + 1; + } + case 99: // dadd + { + printf("%4d: dadd \n", pc); + return pc + 1; + } + case 100: // isub + { + printf("%4d: isub \n", pc); + return pc + 1; + } + case 101: // lsub + { + printf("%4d: lsub \n", pc); + return pc + 1; + } + case 102: // fsub + { + printf("%4d: fsub \n", pc); + return pc + 1; + } + case 103: // dsub + { + printf("%4d: dsub \n", pc); + return pc + 1; + } + case 104: // imul + { + printf("%4d: imul \n", pc); + return pc + 1; + } + case 105: // lmul + { + printf("%4d: lmul \n", pc); + return pc + 1; + } + case 106: // fmul + { + printf("%4d: fmul \n", pc); + return pc + 1; + } + case 107: // dmul + { + printf("%4d: dmul \n", pc); + return pc + 1; + } + case 108: // idiv + { + printf("%4d: idiv \n", pc); + return pc + 1; + } + case 109: // ldiv + { + printf("%4d: ldiv \n", pc); + return pc + 1; + } + case 110: // fdiv + { + printf("%4d: fdiv \n", pc); + return pc + 1; + } + case 111: // ddiv + { + printf("%4d: ddiv \n", pc); + return pc + 1; + } + case 112: // irem + { + printf("%4d: irem \n", pc); + return pc + 1; + } + case 113: // lrem + { + printf("%4d: lrem \n", pc); + return pc + 1; + } + case 114: // frem + { + printf("%4d: frem \n", pc); + return pc + 1; + } + case 115: // drem + { + printf("%4d: drem \n", pc); + return pc + 1; + } + case 116: // ineg + { + printf("%4d: ineg \n", pc); + return pc + 1; + } + case 117: // lneg + { + printf("%4d: lneg \n", pc); + return pc + 1; + } + case 118: // fneg + { + printf("%4d: fneg \n", pc); + return pc + 1; + } + case 119: // dneg + { + printf("%4d: dneg \n", pc); + return pc + 1; + } + case 120: // ishl + { + printf("%4d: ishl \n", pc); + return pc + 1; + } + case 121: // lshl + { + printf("%4d: lshl \n", pc); + return pc + 1; + } + case 122: // ishr + { + printf("%4d: ishr \n", pc); + return pc + 1; + } + case 123: // lshr + { + printf("%4d: lshr \n", pc); + return pc + 1; + } + case 124: // iushr + { + printf("%4d: iushr \n", pc); + return pc + 1; + } + case 125: // lushr + { + printf("%4d: lushr \n", pc); + return pc + 1; + } + case 126: // iand + { + printf("%4d: iand \n", pc); + return pc + 1; + } + case 127: // land + { + printf("%4d: land \n", pc); + return pc + 1; + } + case 128: // ior + { + printf("%4d: ior \n", pc); + return pc + 1; + } + case 129: // lor + { + printf("%4d: lor \n", pc); + return pc + 1; + } + case 130: // ixor + { + printf("%4d: ixor \n", pc); + return pc + 1; + } + case 131: // lxor + { + printf("%4d: lxor \n", pc); + return pc + 1; + } + case 132: // iinc + { + uint32_t index = _u1(&code[pc + 1]); + uint32_t _const = _u1(&code[pc + 2]); + printf("%4d: iinc %u, %u\n", pc, index, _const); + return pc + 3; + } + case 133: // i2l + { + printf("%4d: i2l \n", pc); + return pc + 1; + } + case 134: // i2f + { + printf("%4d: i2f \n", pc); + return pc + 1; + } + case 135: // i2d + { + printf("%4d: i2d \n", pc); + return pc + 1; + } + case 136: // l2i + { + printf("%4d: l2i \n", pc); + return pc + 1; + } + case 137: // l2f + { + printf("%4d: l2f \n", pc); + return pc + 1; + } + case 138: // l2d + { + printf("%4d: l2d \n", pc); + return pc + 1; + } + case 139: // f2i + { + printf("%4d: f2i \n", pc); + return pc + 1; + } + case 140: // f2l + { + printf("%4d: f2l \n", pc); + return pc + 1; + } + case 141: // f2d + { + printf("%4d: f2d \n", pc); + return pc + 1; + } + case 142: // d2i + { + printf("%4d: d2i \n", pc); + return pc + 1; + } + case 143: // d2l + { + printf("%4d: d2l \n", pc); + return pc + 1; + } + case 144: // d2f + { + printf("%4d: d2f \n", pc); + return pc + 1; + } + case 145: // i2b + { + printf("%4d: i2b \n", pc); + return pc + 1; + } + case 146: // i2c + { + printf("%4d: i2c \n", pc); + return pc + 1; + } + case 147: // i2s + { + printf("%4d: i2s \n", pc); + return pc + 1; + } + case 148: // lcmp + { + printf("%4d: lcmp \n", pc); + return pc + 1; + } + case 149: // fcmpl + { + printf("%4d: fcmpl \n", pc); + return pc + 1; + } + case 150: // fcmpg + { + printf("%4d: fcmpg \n", pc); + return pc + 1; + } + case 151: // dcmpl + { + printf("%4d: dcmpl \n", pc); + return pc + 1; + } + case 152: // dcmpg + { + printf("%4d: dcmpg \n", pc); + return pc + 1; + } + case 153: // ifeq + { + int32_t branch = _s2(&code[pc + 1]); + printf("%4d: ifeq %d\n", pc, branch); + return pc + 3; + } + case 154: // ifne + { + int32_t branch = _s2(&code[pc + 1]); + printf("%4d: ifne %d\n", pc, branch); + return pc + 3; + } + case 155: // iflt + { + int32_t branch = _s2(&code[pc + 1]); + printf("%4d: iflt %d\n", pc, branch); + return pc + 3; + } + case 156: // ifge + { + int32_t branch = _s2(&code[pc + 1]); + printf("%4d: ifge %d\n", pc, branch); + return pc + 3; + } + case 157: // ifgt + { + int32_t branch = _s2(&code[pc + 1]); + printf("%4d: ifgt %d\n", pc, branch); + return pc + 3; + } + case 158: // ifle + { + int32_t branch = _s2(&code[pc + 1]); + printf("%4d: ifle %d\n", pc, branch); + return pc + 3; + } + case 159: // if_icmpeq + { + int32_t branch = _s2(&code[pc + 1]); + printf("%4d: if_icmpeq %d\n", pc, branch); + return pc + 3; + } + case 160: // if_icmpne + { + int32_t branch = _s2(&code[pc + 1]); + printf("%4d: if_icmpne %d\n", pc, branch); + return pc + 3; + } + case 161: // if_icmplt + { + int32_t branch = _s2(&code[pc + 1]); + printf("%4d: if_icmplt %d\n", pc, branch); + return pc + 3; + } + case 162: // if_icmpge + { + int32_t branch = _s2(&code[pc + 1]); + printf("%4d: if_icmpge %d\n", pc, branch); + return pc + 3; + } + case 163: // if_icmpgt + { + int32_t branch = _s2(&code[pc + 1]); + printf("%4d: if_icmpgt %d\n", pc, branch); + return pc + 3; + } + case 164: // if_icmple + { + int32_t branch = _s2(&code[pc + 1]); + printf("%4d: if_icmple %d\n", pc, branch); + return pc + 3; + } + case 165: // if_acmpeq + { + int32_t branch = _s2(&code[pc + 1]); + printf("%4d: if_acmpeq %d\n", pc, branch); + return pc + 3; + } + case 166: // if_acmpne + { + int32_t branch = _s2(&code[pc + 1]); + printf("%4d: if_acmpne %d\n", pc, branch); + return pc + 3; + } + case 167: // goto + { + int32_t branch = _s2(&code[pc + 1]); + printf("%4d: goto %d\n", pc, branch); + return pc + 3; + } + case 168: // jsr + { + int32_t branch = _s2(&code[pc + 1]); + printf("%4d: jsr %d\n", pc, branch); + return pc + 3; + } + case 169: // ret + { + uint32_t index = _u1(&code[pc + 1]); + printf("%4d: ret %u\n", pc, index); + return pc + 2; + } + case 170: // tableswitch + { + TABLESWITCH_ARGS; + printf("%4d: tableswitch {\n", pc); + TABLESWITCH_PRINT_ARGS(); + printf("}\n"); + return TABLESWITCH_NEXT_PC; + } + case 171: // lookupswitch + { + LOOKUPSWITCH_ARGS; + printf("%4d: lookupswitch {\n", pc); + LOOKUPSWITCH_PRINT_ARGS(); + printf("}\n"); + return LOOKUPSWITCH_NEXT_PC; + } + case 172: // ireturn + { + printf("%4d: ireturn \n", pc); + return pc + 1; + } + case 173: // lreturn + { + printf("%4d: lreturn \n", pc); + return pc + 1; + } + case 174: // freturn + { + printf("%4d: freturn \n", pc); + return pc + 1; + } + case 175: // dreturn + { + printf("%4d: dreturn \n", pc); + return pc + 1; + } + case 176: // areturn + { + printf("%4d: areturn \n", pc); + return pc + 1; + } + case 177: // return + { + printf("%4d: return \n", pc); + return pc + 1; + } + case 178: // getstatic + { + uint32_t index = _u2(&code[pc + 1]); + printf("%4d: getstatic %u\n", pc, index); + return pc + 3; + } + case 179: // putstatic + { + uint32_t index = _u2(&code[pc + 1]); + printf("%4d: putstatic %u\n", pc, index); + return pc + 3; + } + case 180: // getfield + { + uint32_t index = _u2(&code[pc + 1]); + printf("%4d: getfield %u\n", pc, index); + return pc + 3; + } + case 181: // putfield + { + uint32_t index = _u2(&code[pc + 1]); + printf("%4d: putfield %u\n", pc, index); + return pc + 3; + } + case 182: // invokevirtual + { + uint32_t index = _u2(&code[pc + 1]); + printf("%4d: invokevirtual %u\n", pc, index); + return pc + 3; + } + case 183: // invokespecial + { + uint32_t index = _u2(&code[pc + 1]); + printf("%4d: invokespecial %u\n", pc, index); + return pc + 3; + } + case 184: // invokestatic + { + uint32_t index = _u2(&code[pc + 1]); + printf("%4d: invokestatic %u\n", pc, index); + return pc + 3; + } + case 185: // invokeinterface + { + uint32_t index = _u2(&code[pc + 1]); + uint32_t count = _u1(&code[pc + 3]); + printf("%4d: invokeinterface %u, %u\n", pc, index, count); + return pc + 5; + } + case 186: // invokedynamic + { + uint32_t index = _u2(&code[pc + 1]); + printf("%4d: invokedynamic %u\n", pc, index); + return pc + 5; + } + case 187: // new + { + uint32_t index = _u2(&code[pc + 1]); + printf("%4d: new %u\n", pc, index); + return pc + 3; + } + case 188: // newarray + { + uint32_t atype = _u1(&code[pc + 1]); + printf("%4d: newarray %u\n", pc, atype); + return pc + 2; + } + case 189: // anewarray + { + uint32_t index = _u2(&code[pc + 1]); + printf("%4d: anewarray %u\n", pc, index); + return pc + 3; + } + case 190: // arraylength + { + printf("%4d: arraylength \n", pc); + return pc + 1; + } + case 191: // athrow + { + printf("%4d: athrow \n", pc); + return pc + 1; + } + case 192: // checkcast + { + uint32_t index = _u2(&code[pc + 1]); + printf("%4d: checkcast %u\n", pc, index); + return pc + 3; + } + case 193: // instanceof + { + uint32_t index = _u2(&code[pc + 1]); + printf("%4d: instanceof %u\n", pc, index); + return pc + 3; + } + case 194: // monitorenter + { + printf("%4d: monitorenter \n", pc); + return pc + 1; + } + case 195: // monitorexit + { + printf("%4d: monitorexit \n", pc); + return pc + 1; + } + case 196: // wide + { + WIDE_ARGS; + printf("%4d: wide {\n", pc); + WIDE_PRINT_ARGS(); + printf("}\n"); + return WIDE_NEXT_PC; + } + case 197: // multianewarray + { + uint32_t index = _u2(&code[pc + 1]); + uint32_t dimensions = _u1(&code[pc + 3]); + printf("%4d: multianewarray %u, %u\n", pc, index, dimensions); + return pc + 4; + } + case 198: // ifnull + { + int32_t branch = _s2(&code[pc + 1]); + printf("%4d: ifnull %d\n", pc, branch); + return pc + 3; + } + case 199: // ifnonnull + { + int32_t branch = _s2(&code[pc + 1]); + printf("%4d: ifnonnull %d\n", pc, branch); + return pc + 3; + } + case 200: // goto_w + { + int32_t branch = _s2(&code[pc + 1]); + printf("%4d: goto_w %d\n", pc, branch); + return pc + 3; + } + case 201: // jsr_w + { + int32_t branch = _s4(&code[pc + 1]); + printf("%4d: jsr_w %d\n", pc, branch); + return pc + 5; + } + case 202: // breakpoint + { + printf("%4d: breakpoint \n", pc); + return pc + 1; + } + case 254: // impdep1 + { + printf("%4d: impdep1 \n", pc); + return pc + 1; + } + case 255: // impdep2 + { + printf("%4d: impdep2 \n", pc); + return pc + 1; + } + default: + { + assert(false); + return pc; + } + } +} +uint32_t decode_execute_instruction(struct vm * vm, const uint8_t * code, uint32_t pc) +{ + switch (code[pc]) { + case 0: // nop + { + op_nop(vm); + return pc + 1; + } + case 1: // aconst_null + { + op_aconst_null(vm); + return pc + 1; + } + case 2: // iconst_m1 + { + op_iconst_m1(vm); + return pc + 1; + } + case 3: // iconst_0 + { + op_iconst_0(vm); + return pc + 1; + } + case 4: // iconst_1 + { + op_iconst_1(vm); + return pc + 1; + } + case 5: // iconst_2 + { + op_iconst_2(vm); + return pc + 1; + } + case 6: // iconst_3 + { + op_iconst_3(vm); + return pc + 1; + } + case 7: // iconst_4 + { + op_iconst_4(vm); + return pc + 1; + } + case 8: // iconst_5 + { + op_iconst_5(vm); + return pc + 1; + } + case 9: // lconst_0 + { + op_lconst_0(vm); + return pc + 1; + } + case 10: // lconst_1 + { + op_lconst_1(vm); + return pc + 1; + } + case 11: // fconst_0 + { + op_fconst_0(vm); + return pc + 1; + } + case 12: // fconst_1 + { + op_fconst_1(vm); + return pc + 1; + } + case 13: // fconst_2 + { + op_fconst_2(vm); + return pc + 1; + } + case 14: // dconst_0 + { + op_dconst_0(vm); + return pc + 1; + } + case 15: // dconst_1 + { + op_dconst_1(vm); + return pc + 1; + } + case 16: // bipush + { + int32_t byte = _s1(&code[pc + 1]); + op_bipush(vm, byte); + return pc + 2; + } + case 17: // sipush + { + int32_t byte = _s2(&code[pc + 1]); + op_sipush(vm, byte); + return pc + 3; + } + case 18: // ldc + { + uint32_t index = _u1(&code[pc + 1]); + op_ldc(vm, index); + return pc + 2; + } + case 19: // ldc_w + { + uint32_t index = _u2(&code[pc + 1]); + op_ldc_w(vm, index); + return pc + 3; + } + case 20: // ldc2_w + { + uint32_t index = _u2(&code[pc + 1]); + op_ldc2_w(vm, index); + return pc + 3; + } + case 21: // iload + { + uint32_t index = _u1(&code[pc + 1]); + op_iload(vm, index); + return pc + 2; + } + case 22: // lload + { + uint32_t index = _u1(&code[pc + 1]); + op_lload(vm, index); + return pc + 2; + } + case 23: // fload + { + uint32_t index = _u1(&code[pc + 1]); + op_fload(vm, index); + return pc + 2; + } + case 24: // dload + { + uint32_t index = _u1(&code[pc + 1]); + op_dload(vm, index); + return pc + 2; + } + case 25: // aload + { + uint32_t index = _u1(&code[pc + 1]); + op_aload(vm, index); + return pc + 2; + } + case 26: // iload_0 + { + op_iload_0(vm); + return pc + 1; + } + case 27: // iload_1 + { + op_iload_1(vm); + return pc + 1; + } + case 28: // iload_2 + { + op_iload_2(vm); + return pc + 1; + } + case 29: // iload_3 + { + op_iload_3(vm); + return pc + 1; + } + case 30: // lload_0 + { + op_lload_0(vm); + return pc + 1; + } + case 31: // lload_1 + { + op_lload_1(vm); + return pc + 1; + } + case 32: // lload_2 + { + op_lload_2(vm); + return pc + 1; + } + case 33: // lload_3 + { + op_lload_3(vm); + return pc + 1; + } + case 34: // fload_0 + { + op_fload_0(vm); + return pc + 1; + } + case 35: // fload_1 + { + op_fload_1(vm); + return pc + 1; + } + case 36: // fload_2 + { + op_fload_2(vm); + return pc + 1; + } + case 37: // fload_3 + { + op_fload_3(vm); + return pc + 1; + } + case 38: // dload_0 + { + op_dload_0(vm); + return pc + 1; + } + case 39: // dload_1 + { + op_dload_1(vm); + return pc + 1; + } + case 40: // dload_2 + { + op_dload_2(vm); + return pc + 1; + } + case 41: // dload_3 + { + op_dload_3(vm); + return pc + 1; + } + case 42: // aload_0 + { + op_aload_0(vm); + return pc + 1; + } + case 43: // aload_1 + { + op_aload_1(vm); + return pc + 1; + } + case 44: // aload_2 + { + op_aload_2(vm); + return pc + 1; + } + case 45: // aload_3 + { + op_aload_3(vm); + return pc + 1; + } + case 46: // iaload + { + op_iaload(vm); + return pc + 1; + } + case 47: // laload + { + op_laload(vm); + return pc + 1; + } + case 48: // faload + { + op_faload(vm); + return pc + 1; + } + case 49: // daload + { + op_daload(vm); + return pc + 1; + } + case 50: // aaload + { + op_aaload(vm); + return pc + 1; + } + case 51: // baload + { + op_baload(vm); + return pc + 1; + } + case 52: // caload + { + op_caload(vm); + return pc + 1; + } + case 53: // saload + { + op_saload(vm); + return pc + 1; + } + case 54: // istore + { + uint32_t index = _u1(&code[pc + 1]); + op_istore(vm, index); + return pc + 2; + } + case 55: // lstore + { + uint32_t index = _u1(&code[pc + 1]); + op_lstore(vm, index); + return pc + 2; + } + case 56: // fstore + { + uint32_t index = _u1(&code[pc + 1]); + op_fstore(vm, index); + return pc + 2; + } + case 57: // dstore + { + uint32_t index = _u1(&code[pc + 1]); + op_dstore(vm, index); + return pc + 2; + } + case 58: // astore + { + uint32_t index = _u1(&code[pc + 1]); + op_astore(vm, index); + return pc + 2; + } + case 59: // istore_0 + { + op_istore_0(vm); + return pc + 1; + } + case 60: // istore_1 + { + op_istore_1(vm); + return pc + 1; + } + case 61: // istore_2 + { + op_istore_2(vm); + return pc + 1; + } + case 62: // istore_3 + { + op_istore_3(vm); + return pc + 1; + } + case 63: // lstore_0 + { + op_lstore_0(vm); + return pc + 1; + } + case 64: // lstore_1 + { + op_lstore_1(vm); + return pc + 1; + } + case 65: // lstore_2 + { + op_lstore_2(vm); + return pc + 1; + } + case 66: // lstore_3 + { + op_lstore_3(vm); + return pc + 1; + } + case 67: // fstore_0 + { + op_fstore_0(vm); + return pc + 1; + } + case 68: // fstore_1 + { + op_fstore_1(vm); + return pc + 1; + } + case 69: // fstore_2 + { + op_fstore_2(vm); + return pc + 1; + } + case 70: // fstore_3 + { + op_fstore_3(vm); + return pc + 1; + } + case 71: // dstore_0 + { + op_dstore_0(vm); + return pc + 1; + } + case 72: // dstore_1 + { + op_dstore_1(vm); + return pc + 1; + } + case 73: // dstore_2 + { + op_dstore_2(vm); + return pc + 1; + } + case 74: // dstore_3 + { + op_dstore_3(vm); + return pc + 1; + } + case 75: // astore_0 + { + op_astore_0(vm); + return pc + 1; + } + case 76: // astore_1 + { + op_astore_1(vm); + return pc + 1; + } + case 77: // astore_2 + { + op_astore_2(vm); + return pc + 1; + } + case 78: // astore_3 + { + op_astore_3(vm); + return pc + 1; + } + case 79: // iastore + { + op_iastore(vm); + return pc + 1; + } + case 80: // lastore + { + op_lastore(vm); + return pc + 1; + } + case 81: // fastore + { + op_fastore(vm); + return pc + 1; + } + case 82: // dastore + { + op_dastore(vm); + return pc + 1; + } + case 83: // aastore + { + op_aastore(vm); + return pc + 1; + } + case 84: // bastore + { + op_bastore(vm); + return pc + 1; + } + case 85: // castore + { + op_castore(vm); + return pc + 1; + } + case 86: // sastore + { + op_sastore(vm); + return pc + 1; + } + case 87: // pop + { + op_pop(vm); + return pc + 1; + } + case 88: // pop2 + { + op_pop2(vm); + return pc + 1; + } + case 89: // dup + { + op_dup(vm); + return pc + 1; + } + case 90: // dup_x1 + { + op_dup_x1(vm); + return pc + 1; + } + case 91: // dup_x2 + { + op_dup_x2(vm); + return pc + 1; + } + case 92: // dup2 + { + op_dup2(vm); + return pc + 1; + } + case 93: // dup2_x1 + { + op_dup2_x1(vm); + return pc + 1; + } + case 94: // dup2_x2 + { + op_dup2_x2(vm); + return pc + 1; + } + case 95: // swap + { + op_swap(vm); + return pc + 1; + } + case 96: // iadd + { + op_iadd(vm); + return pc + 1; + } + case 97: // ladd + { + op_ladd(vm); + return pc + 1; + } + case 98: // fadd + { + op_fadd(vm); + return pc + 1; + } + case 99: // dadd + { + op_dadd(vm); + return pc + 1; + } + case 100: // isub + { + op_isub(vm); + return pc + 1; + } + case 101: // lsub + { + op_lsub(vm); + return pc + 1; + } + case 102: // fsub + { + op_fsub(vm); + return pc + 1; + } + case 103: // dsub + { + op_dsub(vm); + return pc + 1; + } + case 104: // imul + { + op_imul(vm); + return pc + 1; + } + case 105: // lmul + { + op_lmul(vm); + return pc + 1; + } + case 106: // fmul + { + op_fmul(vm); + return pc + 1; + } + case 107: // dmul + { + op_dmul(vm); + return pc + 1; + } + case 108: // idiv + { + op_idiv(vm); + return pc + 1; + } + case 109: // ldiv + { + op_ldiv(vm); + return pc + 1; + } + case 110: // fdiv + { + op_fdiv(vm); + return pc + 1; + } + case 111: // ddiv + { + op_ddiv(vm); + return pc + 1; + } + case 112: // irem + { + op_irem(vm); + return pc + 1; + } + case 113: // lrem + { + op_lrem(vm); + return pc + 1; + } + case 114: // frem + { + op_frem(vm); + return pc + 1; + } + case 115: // drem + { + op_drem(vm); + return pc + 1; + } + case 116: // ineg + { + op_ineg(vm); + return pc + 1; + } + case 117: // lneg + { + op_lneg(vm); + return pc + 1; + } + case 118: // fneg + { + op_fneg(vm); + return pc + 1; + } + case 119: // dneg + { + op_dneg(vm); + return pc + 1; + } + case 120: // ishl + { + op_ishl(vm); + return pc + 1; + } + case 121: // lshl + { + op_lshl(vm); + return pc + 1; + } + case 122: // ishr + { + op_ishr(vm); + return pc + 1; + } + case 123: // lshr + { + op_lshr(vm); + return pc + 1; + } + case 124: // iushr + { + op_iushr(vm); + return pc + 1; + } + case 125: // lushr + { + op_lushr(vm); + return pc + 1; + } + case 126: // iand + { + op_iand(vm); + return pc + 1; + } + case 127: // land + { + op_land(vm); + return pc + 1; + } + case 128: // ior + { + op_ior(vm); + return pc + 1; + } + case 129: // lor + { + op_lor(vm); + return pc + 1; + } + case 130: // ixor + { + op_ixor(vm); + return pc + 1; + } + case 131: // lxor + { + op_lxor(vm); + return pc + 1; + } + case 132: // iinc + { + uint32_t index = _u1(&code[pc + 1]); + uint32_t _const = _u1(&code[pc + 2]); + op_iinc(vm, index, _const); + return pc + 3; + } + case 133: // i2l + { + op_i2l(vm); + return pc + 1; + } + case 134: // i2f + { + op_i2f(vm); + return pc + 1; + } + case 135: // i2d + { + op_i2d(vm); + return pc + 1; + } + case 136: // l2i + { + op_l2i(vm); + return pc + 1; + } + case 137: // l2f + { + op_l2f(vm); + return pc + 1; + } + case 138: // l2d + { + op_l2d(vm); + return pc + 1; + } + case 139: // f2i + { + op_f2i(vm); + return pc + 1; + } + case 140: // f2l + { + op_f2l(vm); + return pc + 1; + } + case 141: // f2d + { + op_f2d(vm); + return pc + 1; + } + case 142: // d2i + { + op_d2i(vm); + return pc + 1; + } + case 143: // d2l + { + op_d2l(vm); + return pc + 1; + } + case 144: // d2f + { + op_d2f(vm); + return pc + 1; + } + case 145: // i2b + { + op_i2b(vm); + return pc + 1; + } + case 146: // i2c + { + op_i2c(vm); + return pc + 1; + } + case 147: // i2s + { + op_i2s(vm); + return pc + 1; + } + case 148: // lcmp + { + op_lcmp(vm); + return pc + 1; + } + case 149: // fcmpl + { + op_fcmpl(vm); + return pc + 1; + } + case 150: // fcmpg + { + op_fcmpg(vm); + return pc + 1; + } + case 151: // dcmpl + { + op_dcmpl(vm); + return pc + 1; + } + case 152: // dcmpg + { + op_dcmpg(vm); + return pc + 1; + } + case 153: // ifeq + { + int32_t branch = _s2(&code[pc + 1]); + op_ifeq(vm, branch); + return pc + 3; + } + case 154: // ifne + { + int32_t branch = _s2(&code[pc + 1]); + op_ifne(vm, branch); + return pc + 3; + } + case 155: // iflt + { + int32_t branch = _s2(&code[pc + 1]); + op_iflt(vm, branch); + return pc + 3; + } + case 156: // ifge + { + int32_t branch = _s2(&code[pc + 1]); + op_ifge(vm, branch); + return pc + 3; + } + case 157: // ifgt + { + int32_t branch = _s2(&code[pc + 1]); + op_ifgt(vm, branch); + return pc + 3; + } + case 158: // ifle + { + int32_t branch = _s2(&code[pc + 1]); + op_ifle(vm, branch); + return pc + 3; + } + case 159: // if_icmpeq + { + int32_t branch = _s2(&code[pc + 1]); + op_if_icmpeq(vm, branch); + return pc + 3; + } + case 160: // if_icmpne + { + int32_t branch = _s2(&code[pc + 1]); + op_if_icmpne(vm, branch); + return pc + 3; + } + case 161: // if_icmplt + { + int32_t branch = _s2(&code[pc + 1]); + op_if_icmplt(vm, branch); + return pc + 3; + } + case 162: // if_icmpge + { + int32_t branch = _s2(&code[pc + 1]); + op_if_icmpge(vm, branch); + return pc + 3; + } + case 163: // if_icmpgt + { + int32_t branch = _s2(&code[pc + 1]); + op_if_icmpgt(vm, branch); + return pc + 3; + } + case 164: // if_icmple + { + int32_t branch = _s2(&code[pc + 1]); + op_if_icmple(vm, branch); + return pc + 3; + } + case 165: // if_acmpeq + { + int32_t branch = _s2(&code[pc + 1]); + op_if_acmpeq(vm, branch); + return pc + 3; + } + case 166: // if_acmpne + { + int32_t branch = _s2(&code[pc + 1]); + op_if_acmpne(vm, branch); + return pc + 3; + } + case 167: // goto + { + int32_t branch = _s2(&code[pc + 1]); + op_goto(vm, branch); + return pc + 3; + } + case 168: // jsr + { + int32_t branch = _s2(&code[pc + 1]); + op_jsr(vm, branch); + return pc + 3; + } + case 169: // ret + { + uint32_t index = _u1(&code[pc + 1]); + op_ret(vm, index); + return pc + 2; + } + case 170: // tableswitch + { + TABLESWITCH_ARGS; + op_tableswitch(vm, defaultbyte, lowbyte, highbyte, table); + return TABLESWITCH_NEXT_PC; + } + case 171: // lookupswitch + { + LOOKUPSWITCH_ARGS; + op_lookupswitch(vm); + return LOOKUPSWITCH_NEXT_PC; + } + case 172: // ireturn + { + op_ireturn(vm); + return pc + 1; + } + case 173: // lreturn + { + op_lreturn(vm); + return pc + 1; + } + case 174: // freturn + { + op_freturn(vm); + return pc + 1; + } + case 175: // dreturn + { + op_dreturn(vm); + return pc + 1; + } + case 176: // areturn + { + op_areturn(vm); + return pc + 1; + } + case 177: // return + { + op_return(vm); + return pc + 1; + } + case 178: // getstatic + { + uint32_t index = _u2(&code[pc + 1]); + op_getstatic(vm, index); + return pc + 3; + } + case 179: // putstatic + { + uint32_t index = _u2(&code[pc + 1]); + op_putstatic(vm, index); + return pc + 3; + } + case 180: // getfield + { + uint32_t index = _u2(&code[pc + 1]); + op_getfield(vm, index); + return pc + 3; + } + case 181: // putfield + { + uint32_t index = _u2(&code[pc + 1]); + op_putfield(vm, index); + return pc + 3; + } + case 182: // invokevirtual + { + uint32_t index = _u2(&code[pc + 1]); + op_invokevirtual(vm, index); + return pc + 3; + } + case 183: // invokespecial + { + uint32_t index = _u2(&code[pc + 1]); + op_invokespecial(vm, index); + return pc + 3; + } + case 184: // invokestatic + { + uint32_t index = _u2(&code[pc + 1]); + op_invokestatic(vm, index); + return pc + 3; + } + case 185: // invokeinterface + { + uint32_t index = _u2(&code[pc + 1]); + uint32_t count = _u1(&code[pc + 3]); + op_invokeinterface(vm, index, count); + return pc + 5; + } + case 186: // invokedynamic + { + uint32_t index = _u2(&code[pc + 1]); + op_invokedynamic(vm, index); + return pc + 5; + } + case 187: // new + { + uint32_t index = _u2(&code[pc + 1]); + op_new(vm, index); + return pc + 3; + } + case 188: // newarray + { + uint32_t atype = _u1(&code[pc + 1]); + op_newarray(vm, atype); + return pc + 2; + } + case 189: // anewarray + { + uint32_t index = _u2(&code[pc + 1]); + op_anewarray(vm, index); + return pc + 3; + } + case 190: // arraylength + { + op_arraylength(vm); + return pc + 1; + } + case 191: // athrow + { + op_athrow(vm); + return pc + 1; + } + case 192: // checkcast + { + uint32_t index = _u2(&code[pc + 1]); + op_checkcast(vm, index); + return pc + 3; + } + case 193: // instanceof + { + uint32_t index = _u2(&code[pc + 1]); + op_instanceof(vm, index); + return pc + 3; + } + case 194: // monitorenter + { + op_monitorenter(vm); + return pc + 1; + } + case 195: // monitorexit + { + op_monitorexit(vm); + return pc + 1; + } + case 196: // wide + { + WIDE_ARGS; + op_wide(vm); + return WIDE_NEXT_PC; + } + case 197: // multianewarray + { + uint32_t index = _u2(&code[pc + 1]); + uint32_t dimensions = _u1(&code[pc + 3]); + op_multianewarray(vm, index, dimensions); + return pc + 4; + } + case 198: // ifnull + { + int32_t branch = _s2(&code[pc + 1]); + op_ifnull(vm, branch); + return pc + 3; + } + case 199: // ifnonnull + { + int32_t branch = _s2(&code[pc + 1]); + op_ifnonnull(vm, branch); + return pc + 3; + } + case 200: // goto_w + { + int32_t branch = _s2(&code[pc + 1]); + op_goto_w(vm, branch); + return pc + 3; + } + case 201: // jsr_w + { + int32_t branch = _s4(&code[pc + 1]); + op_jsr_w(vm, branch); + return pc + 5; + } + case 202: // breakpoint + { + op_breakpoint(vm); + return pc + 1; + } + case 254: // impdep1 + { + op_impdep1(vm); + return pc + 1; + } + case 255: // impdep2 + { + op_impdep2(vm); + return pc + 1; + } + default: + { + assert(false); + return pc; + } + } +} diff --git a/c/execute.c b/c/execute.c new file mode 100644 index 0000000..8628d91 --- /dev/null +++ b/c/execute.c @@ -0,0 +1,1217 @@ +#include + +#include "execute.h" +#include "memory_allocator.h" +#include "bswap.h" + +void op_aaload(struct vm * vm) +{ + assert(!"op_aaload"); +} + +void op_aastore(struct vm * vm) +{ + assert(!"op_aastore"); +} + +void op_aconst_null(struct vm * vm) +{ + assert(!"op_aconst_null"); +} + +void op_aload(struct vm * vm, uint32_t index) +{ + uint32_t objectref = vm->current_frame->local_variable[index]; + operand_stack_push_u32(vm->current_frame, objectref); +} + +void op_aload_0(struct vm * vm) +{ + uint32_t objectref = vm->current_frame->local_variable[0]; + operand_stack_push_u32(vm->current_frame, objectref); +} + +void op_aload_1(struct vm * vm) +{ + uint32_t objectref = vm->current_frame->local_variable[1]; + operand_stack_push_u32(vm->current_frame, objectref); +} + +void op_aload_2(struct vm * vm) +{ + uint32_t objectref = vm->current_frame->local_variable[2]; + operand_stack_push_u32(vm->current_frame, objectref); +} + +void op_aload_3(struct vm * vm) +{ + uint32_t objectref = vm->current_frame->local_variable[3]; + operand_stack_push_u32(vm->current_frame, objectref); +} + +void op_anewarray(struct vm * vm, uint32_t index) +{ + assert(!"op_anewarray"); +} + +void op_areturn(struct vm * vm) +{ + assert(!"op_areturn"); +} + +void op_arraylength(struct vm * vm) +{ + int32_t * arrayref = (int32_t *)operand_stack_pop_u32(vm->current_frame); + int32_t length = arrayref[0]; + operand_stack_push_u32(vm->current_frame, length); +} + +void op_astore(struct vm * vm, uint32_t index) +{ + uint32_t value = operand_stack_pop_u32(vm->current_frame); + vm->current_frame->local_variable[index] = value; +} + +void op_astore_0(struct vm * vm) +{ + printf("op_astore0 %d\n", vm->current_frame->operand_stack_ix); + uint32_t value = operand_stack_pop_u32(vm->current_frame); + vm->current_frame->local_variable[0] = value; +} + +void op_astore_1(struct vm * vm) +{ + uint32_t value = operand_stack_pop_u32(vm->current_frame); + vm->current_frame->local_variable[1] = value; +} + +void op_astore_2(struct vm * vm) +{ + uint32_t value = operand_stack_pop_u32(vm->current_frame); + vm->current_frame->local_variable[2] = value; +} + +void op_astore_3(struct vm * vm) +{ + uint32_t value = operand_stack_pop_u32(vm->current_frame); + vm->current_frame->local_variable[3] = value; +} + +void op_athrow(struct vm * vm) +{ + assert(!"op_athrow"); +} + +void op_baload(struct vm * vm) +{ + assert(!"op_baload"); +} + +void op_bastore(struct vm * vm) +{ + assert(!"op_bastore"); +} + +void op_bipush(struct vm * vm, int32_t byte) +{ + operand_stack_push_u32(vm->current_frame, byte); +} + +void op_breakpoint(struct vm * vm) +{ + assert(!"op_breakpoint"); +} + +void op_caload(struct vm * vm) +{ + int32_t index = operand_stack_pop_u32(vm->current_frame); + int32_t * arrayref = (int32_t *)operand_stack_pop_u32(vm->current_frame); + assert(arrayref[0] > 0 && index < arrayref[0]); + uint16_t * chararray = (uint16_t *)&arrayref[1]; + uint16_t value = chararray[index]; + operand_stack_push_u32(vm->current_frame, value); +} + +void op_castore(struct vm * vm) +{ + uint16_t value = operand_stack_pop_u32(vm->current_frame); + int32_t index = operand_stack_pop_u32(vm->current_frame); + int32_t * arrayref = (int32_t *)operand_stack_pop_u32(vm->current_frame); + assert(arrayref[0] > 0 && index < arrayref[0]); + uint16_t * chararray = (uint16_t *)&arrayref[1]; + chararray[index] = value; +} + +void op_checkcast(struct vm * vm, uint32_t index) +{ + assert(!"op_checkcast"); +} + +void op_d2f(struct vm * vm) +{ + assert(!"op_d2f"); +} + +void op_d2i(struct vm * vm) +{ + assert(!"op_d2i"); +} + +void op_d2l(struct vm * vm) +{ + assert(!"op_d2l"); +} + +void op_dadd(struct vm * vm) +{ + assert(!"op_dadd"); +} + +void op_daload(struct vm * vm) +{ + assert(!"op_daload"); +} + +void op_dastore(struct vm * vm) +{ + assert(!"op_dastore"); +} + +void op_dcmpg(struct vm * vm) +{ + assert(!"op_dcmpg"); +} + +void op_dcmpl(struct vm * vm) +{ + assert(!"op_dcmpl"); +} + +void op_dconst_0(struct vm * vm) +{ + assert(!"op_dconst_0"); +} + +void op_dconst_1(struct vm * vm) +{ + assert(!"op_dconst_1"); +} + +void op_ddiv(struct vm * vm) +{ + assert(!"op_ddiv"); +} + +void op_dload(struct vm * vm, uint32_t index) +{ + assert(!"op_dload"); +} + +void op_dload_0(struct vm * vm) +{ + assert(!"op_dload_0"); +} + +void op_dload_1(struct vm * vm) +{ + assert(!"op_dload_1"); +} + +void op_dload_2(struct vm * vm) +{ + assert(!"op_dload_2"); +} + +void op_dload_3(struct vm * vm) +{ + assert(!"op_dload_3"); +} + +void op_dmul(struct vm * vm) +{ + assert(!"op_dmul"); +} + +void op_dneg(struct vm * vm) +{ + assert(!"op_dneg"); +} + +void op_drem(struct vm * vm) +{ + assert(!"op_drem"); +} + +void op_dreturn(struct vm * vm) +{ + assert(!"op_dreturn"); +} + +void op_dstore(struct vm * vm, uint32_t index) +{ + assert(!"op_dstore"); +} + +void op_dstore_0(struct vm * vm) +{ + assert(!"op_dstore_0"); +} + +void op_dstore_1(struct vm * vm) +{ + assert(!"op_dstore_1"); +} + +void op_dstore_2(struct vm * vm) +{ + assert(!"op_dstore_2"); +} + +void op_dstore_3(struct vm * vm) +{ + assert(!"op_dstore_3"); +} + +void op_dsub(struct vm * vm) +{ + assert(!"op_dsub"); +} + +void op_dup(struct vm * vm) +{ + operand_stack_dup_u32(vm->current_frame); +} + +void op_dup2(struct vm * vm) +{ + assert(!"op_dup2"); +} + +void op_dup2_x1(struct vm * vm) +{ + assert(!"op_dup2_x1"); +} + +void op_dup2_x2(struct vm * vm) +{ + assert(!"op_dup2_x2"); +} + +void op_dup_x1(struct vm * vm) +{ + assert(!"op_dup_x1"); +} + +void op_dup_x2(struct vm * vm) +{ + assert(!"op_dup_x2"); +} + +void op_f2d(struct vm * vm) +{ + assert(!"op_f2d"); +} + +void op_f2i(struct vm * vm) +{ + assert(!"op_f2i"); +} + +void op_f2l(struct vm * vm) +{ + assert(!"op_f2l"); +} + +void op_fadd(struct vm * vm) +{ + assert(!"op_fadd"); +} + +void op_faload(struct vm * vm) +{ + assert(!"op_faload"); +} + +void op_fastore(struct vm * vm) +{ + assert(!"op_fastore"); +} + +void op_fcmpg(struct vm * vm) +{ + assert(!"op_fcmpg"); +} + +void op_fcmpl(struct vm * vm) +{ + assert(!"op_fcmpl"); +} + +void op_fconst_0(struct vm * vm) +{ + assert(!"op_fconst_0"); +} + +void op_fconst_1(struct vm * vm) +{ + assert(!"op_fconst_1"); +} + +void op_fconst_2(struct vm * vm) +{ + assert(!"op_fconst_2"); +} + +void op_fdiv(struct vm * vm) +{ + assert(!"op_fdiv"); +} + +void op_fload(struct vm * vm, uint32_t index) +{ + assert(!"op_fload"); +} + +void op_fload_0(struct vm * vm) +{ + assert(!"op_fload_0"); +} + +void op_fload_1(struct vm * vm) +{ + assert(!"op_fload_1"); +} + +void op_fload_2(struct vm * vm) +{ + assert(!"op_fload_2"); +} + +void op_fload_3(struct vm * vm) +{ + assert(!"op_fload_3"); +} + +void op_fmul(struct vm * vm) +{ + assert(!"op_fmul"); +} + +void op_fneg(struct vm * vm) +{ + assert(!"op_fneg"); +} + +void op_frem(struct vm * vm) +{ + assert(!"op_frem"); +} + +void op_freturn(struct vm * vm) +{ + assert(!"op_freturn"); +} + +void op_fstore(struct vm * vm, uint32_t index) +{ + assert(!"op_fstore"); +} + +void op_fstore_0(struct vm * vm) +{ + assert(!"op_fstore_0"); +} + +void op_fstore_1(struct vm * vm) +{ + assert(!"op_fstore_1"); +} + +void op_fstore_2(struct vm * vm) +{ + assert(!"op_fstore_2"); +} + +void op_fstore_3(struct vm * vm) +{ + assert(!"op_fstore_3"); +} + +void op_fsub(struct vm * vm) +{ + assert(!"op_fsub"); +} + +void op_getfield(struct vm * vm, uint32_t index) +{ + assert(!"op_getfield"); +} + +void op_getstatic(struct vm * vm, uint32_t index) +{ + assert(!"op_getstatic"); +} + +void op_goto(struct vm * vm, int32_t branch) +{ + vm->current_thread.pc = vm->current_thread.pc + branch; +} + +void op_goto_w(struct vm * vm, int32_t branch) +{ + assert(!"op_goto_w"); +} + +void op_i2b(struct vm * vm) +{ + uint32_t value = operand_stack_pop_u32(vm->current_frame); + uint8_t result = value; + operand_stack_push_u32(vm->current_frame, result); +} + +void op_i2c(struct vm * vm) +{ + uint32_t value = operand_stack_pop_u32(vm->current_frame); + uint16_t result = value; + operand_stack_push_u32(vm->current_frame, result); +} + +void op_i2d(struct vm * vm) +{ + assert(!"op_i2d"); +} + +void op_i2f(struct vm * vm) +{ + assert(!"op_i2f"); +} + +void op_i2l(struct vm * vm) +{ + assert(!"op_i2l"); +} + +void op_i2s(struct vm * vm) +{ + int32_t value = operand_stack_pop_u32(vm->current_frame); + int16_t result = value; + operand_stack_push_u32(vm->current_frame, result); +} + +void op_iadd(struct vm * vm) +{ + int32_t value2 = operand_stack_pop_u32(vm->current_frame); + int32_t value1 = operand_stack_pop_u32(vm->current_frame); + int32_t result = value1 + value2; + operand_stack_push_u32(vm->current_frame, result); +} + +void op_iaload(struct vm * vm) +{ + int32_t index = operand_stack_pop_u32(vm->current_frame); + int32_t * arrayref = (int32_t *)operand_stack_pop_u32(vm->current_frame); + assert(arrayref[0] > 0 && index < arrayref[0]); + int32_t * intarray = (int32_t *)&arrayref[1]; + int32_t value = intarray[index]; + operand_stack_push_u32(vm->current_frame, value); +} + +void op_iand(struct vm * vm) +{ + int32_t value2 = operand_stack_pop_u32(vm->current_frame); + int32_t value1 = operand_stack_pop_u32(vm->current_frame); + int32_t result = value1 & value2; + operand_stack_push_u32(vm->current_frame, result); +} + +void op_iastore(struct vm * vm) +{ + int32_t value = operand_stack_pop_u32(vm->current_frame); + int32_t index = operand_stack_pop_u32(vm->current_frame); + int32_t * arrayref = (int32_t *)operand_stack_pop_u32(vm->current_frame); + assert(arrayref[0] > 0 && index < arrayref[0]); + int32_t * intarray = (int32_t *)&arrayref[1]; + intarray[index] = value; +} + +void op_iconst_0(struct vm * vm) +{ + operand_stack_push_u32(vm->current_frame, 0); +} + +void op_iconst_1(struct vm * vm) +{ + operand_stack_push_u32(vm->current_frame, 1); +} + +void op_iconst_2(struct vm * vm) +{ + operand_stack_push_u32(vm->current_frame, 2); +} + +void op_iconst_3(struct vm * vm) +{ + operand_stack_push_u32(vm->current_frame, 3); +} + +void op_iconst_4(struct vm * vm) +{ + operand_stack_push_u32(vm->current_frame, 4); +} + +void op_iconst_5(struct vm * vm) +{ + operand_stack_push_u32(vm->current_frame, 5); +} + +void op_iconst_m1(struct vm * vm) +{ + operand_stack_push_u32(vm->current_frame, -1); +} + +void op_idiv(struct vm * vm) +{ + int32_t value2 = operand_stack_pop_u32(vm->current_frame); + int32_t value1 = operand_stack_pop_u32(vm->current_frame); + int32_t result = value1 / value2; + operand_stack_push_u32(vm->current_frame, result); +} + +void op_if_acmpeq(struct vm * vm, int32_t branch) +{ + assert(!"op_if_acmpeq"); +} + +void op_if_acmpne(struct vm * vm, int32_t branch) +{ + assert(!"op_if_acmpne"); +} + +void op_if_icmpeq(struct vm * vm, int32_t branch) +{ + int32_t value2 = operand_stack_pop_u32(vm->current_frame); + int32_t value1 = operand_stack_pop_u32(vm->current_frame); + if (value1 == value2) { + vm->current_thread.pc = vm->current_thread.pc + branch; + } +} + +void op_if_icmpge(struct vm * vm, int32_t branch) +{ + int32_t value2 = operand_stack_pop_u32(vm->current_frame); + int32_t value1 = operand_stack_pop_u32(vm->current_frame); + if (value1 >= value2) { + vm->current_thread.pc = vm->current_thread.pc + branch; + } +} + +void op_if_icmpgt(struct vm * vm, int32_t branch) +{ + int32_t value2 = operand_stack_pop_u32(vm->current_frame); + int32_t value1 = operand_stack_pop_u32(vm->current_frame); + if (value1 > value2) { + vm->current_thread.pc = vm->current_thread.pc + branch; + } +} + +void op_if_icmple(struct vm * vm, int32_t branch) +{ + int32_t value2 = operand_stack_pop_u32(vm->current_frame); + int32_t value1 = operand_stack_pop_u32(vm->current_frame); + if (value1 <= value2) { + vm->current_thread.pc = vm->current_thread.pc + branch; + } +} + +void op_if_icmplt(struct vm * vm, int32_t branch) +{ + int32_t value2 = operand_stack_pop_u32(vm->current_frame); + int32_t value1 = operand_stack_pop_u32(vm->current_frame); + if (value1 < value2) { + vm->current_thread.pc = vm->current_thread.pc + branch; + } +} + +void op_if_icmpne(struct vm * vm, int32_t branch) +{ + int32_t value2 = operand_stack_pop_u32(vm->current_frame); + int32_t value1 = operand_stack_pop_u32(vm->current_frame); + if (value1 != value2) { + vm->current_thread.pc = vm->current_thread.pc + branch; + } +} + +void op_ifeq(struct vm * vm, int32_t branch) +{ + int32_t value = operand_stack_pop_u32(vm->current_frame); + if (value == 0) { + vm->current_thread.pc = vm->current_thread.pc + branch; + } +} + +void op_ifge(struct vm * vm, int32_t branch) +{ + int32_t value = operand_stack_pop_u32(vm->current_frame); + if (value >= 0) { + vm->current_thread.pc = vm->current_thread.pc + branch; + } +} + +void op_ifgt(struct vm * vm, int32_t branch) +{ + int32_t value = operand_stack_pop_u32(vm->current_frame); + if (value > 0) { + vm->current_thread.pc = vm->current_thread.pc + branch; + } +} + +void op_ifle(struct vm * vm, int32_t branch) +{ + int32_t value = operand_stack_pop_u32(vm->current_frame); + if (value <= 0) { + vm->current_thread.pc = vm->current_thread.pc + branch; + } +} + +void op_iflt(struct vm * vm, int32_t branch) +{ + int32_t value = operand_stack_pop_u32(vm->current_frame); + if (value < 0) { + vm->current_thread.pc = vm->current_thread.pc + branch; + } +} + +void op_ifne(struct vm * vm, int32_t branch) +{ + int32_t value = operand_stack_pop_u32(vm->current_frame); + if (value != 0) { + vm->current_thread.pc = vm->current_thread.pc + branch; + } +} + +void op_ifnonnull(struct vm * vm, int32_t branch) +{ + void * value = (void *)operand_stack_pop_u32(vm->current_frame); + if (value != nullptr) { + vm->current_thread.pc = vm->current_thread.pc + branch; + } +} + +void op_ifnull(struct vm * vm, int32_t branch) +{ + void * value = (void *)operand_stack_pop_u32(vm->current_frame); + if (value == nullptr) { + vm->current_thread.pc = vm->current_thread.pc + branch; + } +} + +void op_iinc(struct vm * vm, uint32_t index, uint32_t _const) +{ + uint32_t value = vm->current_frame->local_variable[index]; + value += _const; + vm->current_frame->local_variable[index] = value; +} + +void op_iload(struct vm * vm, uint32_t index) +{ + uint32_t value = vm->current_frame->local_variable[index]; + operand_stack_push_u32(vm->current_frame, value); +} + +void op_iload_0(struct vm * vm) +{ + uint32_t value = vm->current_frame->local_variable[0]; + operand_stack_push_u32(vm->current_frame, value); +} + +void op_iload_1(struct vm * vm) +{ + uint32_t value = vm->current_frame->local_variable[1]; + operand_stack_push_u32(vm->current_frame, value); +} + +void op_iload_2(struct vm * vm) +{ + uint32_t value = vm->current_frame->local_variable[2]; + operand_stack_push_u32(vm->current_frame, value); +} + +void op_iload_3(struct vm * vm) +{ + uint32_t value = vm->current_frame->local_variable[3]; + operand_stack_push_u32(vm->current_frame, value); +} + +void op_impdep1(struct vm * vm) +{ + assert(!"op_impdep1"); +} + +void op_impdep2(struct vm * vm) +{ + assert(!"op_impdep2"); +} + +void op_imul(struct vm * vm) +{ + int32_t value2 = operand_stack_pop_u32(vm->current_frame); + int32_t value1 = operand_stack_pop_u32(vm->current_frame); + int32_t result = value1 * value2; + operand_stack_push_u32(vm->current_frame, result); +} + +void op_ineg(struct vm * vm) +{ + int32_t value = operand_stack_pop_u32(vm->current_frame); + int32_t result = -value; + operand_stack_push_u32(vm->current_frame, result); +} + +void op_instanceof(struct vm * vm, uint32_t index) +{ + assert(!"op_instanceof"); +} + +void op_invokedynamic(struct vm * vm, uint32_t index) +{ + assert(!"op_invokedynamic"); +} + +void op_invokeinterface(struct vm * vm, uint32_t index, uint32_t count) +{ + assert(!"op_invokeinterface"); +} + +void op_invokespecial(struct vm * vm, uint32_t index) +{ + assert(!"op_invokespecial"); +} + +void op_invokestatic(struct vm * vm, uint32_t index) +{ + assert(!"op_invokestatic"); +} + +void op_invokevirtual(struct vm * vm, uint32_t index) +{ + assert(!"op_invokevirtual"); +} + +void op_ior(struct vm * vm) +{ + uint32_t value2 = operand_stack_pop_u32(vm->current_frame); + uint32_t value1 = operand_stack_pop_u32(vm->current_frame); + int32_t result = value1 | value2; + operand_stack_push_u32(vm->current_frame, result); +} + +void op_irem(struct vm * vm) +{ + uint32_t value2 = operand_stack_pop_u32(vm->current_frame); + uint32_t value1 = operand_stack_pop_u32(vm->current_frame); + int32_t result = value1 % value2; + operand_stack_push_u32(vm->current_frame, result); +} + +void op_ireturn(struct vm * vm) +{ + uint32_t value = operand_stack_pop_u32(vm->current_frame); + printf("return %d\n", value); +} + +void op_ishl(struct vm * vm) +{ + int32_t value2 = operand_stack_pop_u32(vm->current_frame); + int32_t value1 = operand_stack_pop_u32(vm->current_frame); + int s = value2 & 0b11111; + int32_t result = value1 << s; + operand_stack_push_u32(vm->current_frame, result); +} + +void op_ishr(struct vm * vm) +{ + int32_t value2 = operand_stack_pop_u32(vm->current_frame); + int32_t value1 = operand_stack_pop_u32(vm->current_frame); + int s = value2 & 0b11111; + int32_t result = value1 >> s; + operand_stack_push_u32(vm->current_frame, result); +} + +void op_istore(struct vm * vm, uint32_t index) +{ + uint32_t value = operand_stack_pop_u32(vm->current_frame); + vm->current_frame->local_variable[index] = value; +} + +void op_istore_0(struct vm * vm) +{ + uint32_t value = operand_stack_pop_u32(vm->current_frame); + vm->current_frame->local_variable[0] = value; +} + +void op_istore_1(struct vm * vm) +{ + uint32_t value = operand_stack_pop_u32(vm->current_frame); + vm->current_frame->local_variable[1] = value; +} + +void op_istore_2(struct vm * vm) +{ + uint32_t value = operand_stack_pop_u32(vm->current_frame); + vm->current_frame->local_variable[2] = value; +} + +void op_istore_3(struct vm * vm) +{ + uint32_t value = operand_stack_pop_u32(vm->current_frame); + vm->current_frame->local_variable[3] = value; +} + +void op_isub(struct vm * vm) +{ + int32_t value2 = operand_stack_pop_u32(vm->current_frame); + int32_t value1 = operand_stack_pop_u32(vm->current_frame); + int32_t result = value1 - value2; + operand_stack_push_u32(vm->current_frame, result); +} + +void op_iushr(struct vm * vm) +{ + uint32_t value2 = operand_stack_pop_u32(vm->current_frame); + uint32_t value1 = operand_stack_pop_u32(vm->current_frame); + int s = value2 & 0b11111; + uint32_t result = value1 >> s; + operand_stack_push_u32(vm->current_frame, result); +} + +void op_ixor(struct vm * vm) +{ + uint32_t value2 = operand_stack_pop_u32(vm->current_frame); + uint32_t value1 = operand_stack_pop_u32(vm->current_frame); + int32_t result = value1 ^ value2; + operand_stack_push_u32(vm->current_frame, result); +} + +void op_jsr(struct vm * vm, int32_t branch) +{ + assert(!"op_jsr"); +} + +void op_jsr_w(struct vm * vm, int32_t branch) +{ + assert(!"op_jsr_w"); +} + +void op_l2d(struct vm * vm) +{ + assert(!"op_l2d"); +} + +void op_l2f(struct vm * vm) +{ + assert(!"op_l2f"); +} + +void op_l2i(struct vm * vm) +{ + assert(!"op_l2i"); +} + +void op_ladd(struct vm * vm) +{ + assert(!"op_ladd"); +} + +void op_laload(struct vm * vm) +{ + assert(!"op_laload"); +} + +void op_land(struct vm * vm) +{ + assert(!"op_land"); +} + +void op_lastore(struct vm * vm) +{ + assert(!"op_lastore"); +} + +void op_lcmp(struct vm * vm) +{ + assert(!"op_lcmp"); +} + +void op_lconst_0(struct vm * vm) +{ + assert(!"op_lconst_0"); +} + +void op_lconst_1(struct vm * vm) +{ + assert(!"op_lconst_1"); +} + +void op_ldc(struct vm * vm, uint32_t index) +{ + struct constant * constant = &vm->current_thread.current_class->constant_pool[index - 1]; + #ifdef DEBUG + assert(constant->tag == CONSTANT_Integer); + #endif + int32_t value = constant->integer.bytes; + operand_stack_push_u32(vm->current_frame, value); +} + +void op_ldc2_w(struct vm * vm, uint32_t index) +{ + assert(!"op_ldc2_w"); +} + +void op_ldc_w(struct vm * vm, uint32_t index) +{ + assert(!"op_ldc_w"); +} + +void op_ldiv(struct vm * vm) +{ + assert(!"op_ldiv"); +} + +void op_lload(struct vm * vm, uint32_t index) +{ + assert(!"op_lload"); +} + +void op_lload_0(struct vm * vm) +{ + assert(!"op_lload_0"); +} + +void op_lload_1(struct vm * vm) +{ + assert(!"op_lload_1"); +} + +void op_lload_2(struct vm * vm) +{ + assert(!"op_lload_2"); +} + +void op_lload_3(struct vm * vm) +{ + assert(!"op_lload_3"); +} + +void op_lmul(struct vm * vm) +{ + assert(!"op_lmul"); +} + +void op_lneg(struct vm * vm) +{ + assert(!"op_lneg"); +} + +void op_lookupswitch(struct vm * vm) +{ + assert(!"op_lookupswitch"); +} + +void op_lor(struct vm * vm) +{ + assert(!"op_lor"); +} + +void op_lrem(struct vm * vm) +{ + assert(!"op_lrem"); +} + +void op_lreturn(struct vm * vm) +{ + assert(!"op_lreturn"); +} + +void op_lshl(struct vm * vm) +{ + assert(!"op_lshl"); +} + +void op_lshr(struct vm * vm) +{ + assert(!"op_lshr"); +} + +void op_lstore(struct vm * vm, uint32_t index) +{ + assert(!"op_lstore"); +} + +void op_lstore_0(struct vm * vm) +{ + assert(!"op_lstore_0"); +} + +void op_lstore_1(struct vm * vm) +{ + assert(!"op_lstore_1"); +} + +void op_lstore_2(struct vm * vm) +{ + assert(!"op_lstore_2"); +} + +void op_lstore_3(struct vm * vm) +{ + assert(!"op_lstore_3"); +} + +void op_lsub(struct vm * vm) +{ + assert(!"op_lsub"); +} + +void op_lushr(struct vm * vm) +{ + assert(!"op_lushr"); +} + +void op_lxor(struct vm * vm) +{ + assert(!"op_lxor"); +} + +void op_monitorenter(struct vm * vm) +{ + assert(!"op_monitorenter"); +} + +void op_monitorexit(struct vm * vm) +{ + assert(!"op_monitorexit"); +} + +void op_multianewarray(struct vm * vm, uint32_t index, uint32_t dimensions) +{ + assert(!"op_multianewarray"); +} + +void op_new(struct vm * vm, uint32_t index) +{ + assert(!"op_new"); +} + +enum ARRAY_TYPE { + T_BOOLEAN = 4, // 1 byte + T_CHAR = 5, // 2 bytes + T_FLOAT = 6, // 4 bytes + T_DOUBLE = 7, // 8 bytes + T_BYTE = 8, // 1 byte + T_SHORT = 9, // 2 bytes + T_INT = 10, // 4 bytes + T_LONG = 11, // 8 bytes +}; + +void op_newarray(struct vm * vm, uint32_t atype) +{ + int32_t element_size = 0; + switch (atype) { + case T_BOOLEAN: [[fallthrough]]; // 1 byte + case T_BYTE: // 1 byte + element_size = 1; + break; + case T_CHAR: [[fallthrough]]; // 2 bytes + case T_SHORT: // 2 bytes + element_size = 2; + break; + case T_FLOAT: [[fallthrough]]; // 4 bytes + case T_INT: // 4 bytes + element_size = 4; + break; + case T_DOUBLE: [[fallthrough]]; // 8 bytes + case T_LONG: // 8 bytes + element_size = 8; + break; + default: + assert(false); + break; + } + int32_t count = operand_stack_pop_u32(vm->current_frame); + int32_t size = element_size * count + 4; + int32_t * arrayref = memory_allocate(size); + assert(arrayref != 0); + arrayref[0] = count; + operand_stack_push_u32(vm->current_frame, (uint32_t)arrayref); +} + +void op_nop(struct vm * vm) +{ + assert(!"op_nop"); +} + +void op_pop(struct vm * vm) +{ + assert(!"op_pop"); +} + +void op_pop2(struct vm * vm) +{ + assert(!"op_pop2"); +} + +void op_putfield(struct vm * vm, uint32_t index) +{ + assert(!"op_putfield"); +} + +void op_putstatic(struct vm * vm, uint32_t index) +{ + assert(!"op_putstatic"); +} + +void op_ret(struct vm * vm, uint32_t index) +{ + assert(!"op_ret"); +} + +void op_return(struct vm * vm) +{ + assert(!"op_return"); +} + +void op_saload(struct vm * vm) +{ + assert(!"op_saload"); +} + +void op_sastore(struct vm * vm) +{ + assert(!"op_sastore"); +} + +void op_sipush(struct vm * vm, int32_t byte) +{ + assert(!"op_sipush"); +} + +void op_swap(struct vm * vm) +{ + assert(!"op_swap"); +} + +void op_tableswitch(struct vm * vm, int32_t defaultbyte, int32_t lowbyte, int32_t highbyte, const int32_t * table) +{ + int32_t index = operand_stack_pop_u32(vm->current_frame); + if (index < lowbyte || index > highbyte) { + vm->current_thread.pc = vm->current_thread.pc + defaultbyte; + } else { + int32_t offset = BE_BSWAP32(table[index - lowbyte]); + vm->current_thread.pc = vm->current_thread.pc + offset; + } +} + +void op_wide(struct vm * vm) +{ + assert(!"op_wide"); +} diff --git a/c/execute.h b/c/execute.h new file mode 100644 index 0000000..b1adedd --- /dev/null +++ b/c/execute.h @@ -0,0 +1,211 @@ +#pragma once + +#include + +#include "frame.h" + +void op_aaload(struct vm * vm); +void op_aastore(struct vm * vm); +void op_aconst_null(struct vm * vm); +void op_aload(struct vm * vm, uint32_t index); +void op_aload_0(struct vm * vm); +void op_aload_1(struct vm * vm); +void op_aload_2(struct vm * vm); +void op_aload_3(struct vm * vm); +void op_anewarray(struct vm * vm, uint32_t index); +void op_areturn(struct vm * vm); +void op_arraylength(struct vm * vm); +void op_astore(struct vm * vm, uint32_t index); +void op_astore_0(struct vm * vm); +void op_astore_1(struct vm * vm); +void op_astore_2(struct vm * vm); +void op_astore_3(struct vm * vm); +void op_athrow(struct vm * vm); +void op_baload(struct vm * vm); +void op_bastore(struct vm * vm); +void op_bipush(struct vm * vm, int32_t byte); +void op_breakpoint(struct vm * vm); +void op_caload(struct vm * vm); +void op_castore(struct vm * vm); +void op_checkcast(struct vm * vm, uint32_t index); +void op_d2f(struct vm * vm); +void op_d2i(struct vm * vm); +void op_d2l(struct vm * vm); +void op_dadd(struct vm * vm); +void op_daload(struct vm * vm); +void op_dastore(struct vm * vm); +void op_dcmpg(struct vm * vm); +void op_dcmpl(struct vm * vm); +void op_dconst_0(struct vm * vm); +void op_dconst_1(struct vm * vm); +void op_ddiv(struct vm * vm); +void op_dload(struct vm * vm, uint32_t index); +void op_dload_0(struct vm * vm); +void op_dload_1(struct vm * vm); +void op_dload_2(struct vm * vm); +void op_dload_3(struct vm * vm); +void op_dmul(struct vm * vm); +void op_dneg(struct vm * vm); +void op_drem(struct vm * vm); +void op_dreturn(struct vm * vm); +void op_dstore(struct vm * vm, uint32_t index); +void op_dstore_0(struct vm * vm); +void op_dstore_1(struct vm * vm); +void op_dstore_2(struct vm * vm); +void op_dstore_3(struct vm * vm); +void op_dsub(struct vm * vm); +void op_dup(struct vm * vm); +void op_dup2(struct vm * vm); +void op_dup2_x1(struct vm * vm); +void op_dup2_x2(struct vm * vm); +void op_dup_x1(struct vm * vm); +void op_dup_x2(struct vm * vm); +void op_f2d(struct vm * vm); +void op_f2i(struct vm * vm); +void op_f2l(struct vm * vm); +void op_fadd(struct vm * vm); +void op_faload(struct vm * vm); +void op_fastore(struct vm * vm); +void op_fcmpg(struct vm * vm); +void op_fcmpl(struct vm * vm); +void op_fconst_0(struct vm * vm); +void op_fconst_1(struct vm * vm); +void op_fconst_2(struct vm * vm); +void op_fdiv(struct vm * vm); +void op_fload(struct vm * vm, uint32_t index); +void op_fload_0(struct vm * vm); +void op_fload_1(struct vm * vm); +void op_fload_2(struct vm * vm); +void op_fload_3(struct vm * vm); +void op_fmul(struct vm * vm); +void op_fneg(struct vm * vm); +void op_frem(struct vm * vm); +void op_freturn(struct vm * vm); +void op_fstore(struct vm * vm, uint32_t index); +void op_fstore_0(struct vm * vm); +void op_fstore_1(struct vm * vm); +void op_fstore_2(struct vm * vm); +void op_fstore_3(struct vm * vm); +void op_fsub(struct vm * vm); +void op_getfield(struct vm * vm, uint32_t index); +void op_getstatic(struct vm * vm, uint32_t index); +void op_goto(struct vm * vm, int32_t branch); +void op_goto_w(struct vm * vm, int32_t branch); +void op_i2b(struct vm * vm); +void op_i2c(struct vm * vm); +void op_i2d(struct vm * vm); +void op_i2f(struct vm * vm); +void op_i2l(struct vm * vm); +void op_i2s(struct vm * vm); +void op_iadd(struct vm * vm); +void op_iaload(struct vm * vm); +void op_iand(struct vm * vm); +void op_iastore(struct vm * vm); +void op_iconst_0(struct vm * vm); +void op_iconst_1(struct vm * vm); +void op_iconst_2(struct vm * vm); +void op_iconst_3(struct vm * vm); +void op_iconst_4(struct vm * vm); +void op_iconst_5(struct vm * vm); +void op_iconst_m1(struct vm * vm); +void op_idiv(struct vm * vm); +void op_if_acmpeq(struct vm * vm, int32_t branch); +void op_if_acmpne(struct vm * vm, int32_t branch); +void op_if_icmpeq(struct vm * vm, int32_t branch); +void op_if_icmpge(struct vm * vm, int32_t branch); +void op_if_icmpgt(struct vm * vm, int32_t branch); +void op_if_icmple(struct vm * vm, int32_t branch); +void op_if_icmplt(struct vm * vm, int32_t branch); +void op_if_icmpne(struct vm * vm, int32_t branch); +void op_ifeq(struct vm * vm, int32_t branch); +void op_ifge(struct vm * vm, int32_t branch); +void op_ifgt(struct vm * vm, int32_t branch); +void op_ifle(struct vm * vm, int32_t branch); +void op_iflt(struct vm * vm, int32_t branch); +void op_ifne(struct vm * vm, int32_t branch); +void op_ifnonnull(struct vm * vm, int32_t branch); +void op_ifnull(struct vm * vm, int32_t branch); +void op_iinc(struct vm * vm, uint32_t index, uint32_t _const); +void op_iload(struct vm * vm, uint32_t index); +void op_iload_0(struct vm * vm); +void op_iload_1(struct vm * vm); +void op_iload_2(struct vm * vm); +void op_iload_3(struct vm * vm); +void op_impdep1(struct vm * vm); +void op_impdep2(struct vm * vm); +void op_imul(struct vm * vm); +void op_ineg(struct vm * vm); +void op_instanceof(struct vm * vm, uint32_t index); +void op_invokedynamic(struct vm * vm, uint32_t index); +void op_invokeinterface(struct vm * vm, uint32_t index, uint32_t count); +void op_invokespecial(struct vm * vm, uint32_t index); +void op_invokestatic(struct vm * vm, uint32_t index); +void op_invokevirtual(struct vm * vm, uint32_t index); +void op_ior(struct vm * vm); +void op_irem(struct vm * vm); +void op_ireturn(struct vm * vm); +void op_ishl(struct vm * vm); +void op_ishr(struct vm * vm); +void op_istore(struct vm * vm, uint32_t index); +void op_istore_0(struct vm * vm); +void op_istore_1(struct vm * vm); +void op_istore_2(struct vm * vm); +void op_istore_3(struct vm * vm); +void op_isub(struct vm * vm); +void op_iushr(struct vm * vm); +void op_ixor(struct vm * vm); +void op_jsr(struct vm * vm, int32_t branch); +void op_jsr_w(struct vm * vm, int32_t branch); +void op_l2d(struct vm * vm); +void op_l2f(struct vm * vm); +void op_l2i(struct vm * vm); +void op_ladd(struct vm * vm); +void op_laload(struct vm * vm); +void op_land(struct vm * vm); +void op_lastore(struct vm * vm); +void op_lcmp(struct vm * vm); +void op_lconst_0(struct vm * vm); +void op_lconst_1(struct vm * vm); +void op_ldc(struct vm * vm, uint32_t index); +void op_ldc2_w(struct vm * vm, uint32_t index); +void op_ldc_w(struct vm * vm, uint32_t index); +void op_ldiv(struct vm * vm); +void op_lload(struct vm * vm, uint32_t index); +void op_lload_0(struct vm * vm); +void op_lload_1(struct vm * vm); +void op_lload_2(struct vm * vm); +void op_lload_3(struct vm * vm); +void op_lmul(struct vm * vm); +void op_lneg(struct vm * vm); +void op_lookupswitch(struct vm * vm); +void op_lor(struct vm * vm); +void op_lrem(struct vm * vm); +void op_lreturn(struct vm * vm); +void op_lshl(struct vm * vm); +void op_lshr(struct vm * vm); +void op_lstore(struct vm * vm, uint32_t index); +void op_lstore_0(struct vm * vm); +void op_lstore_1(struct vm * vm); +void op_lstore_2(struct vm * vm); +void op_lstore_3(struct vm * vm); +void op_lsub(struct vm * vm); +void op_lushr(struct vm * vm); +void op_lxor(struct vm * vm); +void op_monitorenter(struct vm * vm); +void op_monitorexit(struct vm * vm); +void op_multianewarray(struct vm * vm, uint32_t index, uint32_t dimensions); +void op_new(struct vm * vm, uint32_t index); +void op_newarray(struct vm * vm, uint32_t atype); +void op_nop(struct vm * vm); +void op_pop(struct vm * vm); +void op_pop2(struct vm * vm); +void op_putfield(struct vm * vm, uint32_t index); +void op_putstatic(struct vm * vm, uint32_t index); +void op_ret(struct vm * vm, uint32_t index); +void op_return(struct vm * vm); +void op_saload(struct vm * vm); +void op_sastore(struct vm * vm); +void op_sipush(struct vm * vm, int32_t byte); +void op_swap(struct vm * vm); +void op_tableswitch(struct vm * vm, int32_t defaultbyte, int32_t lowbyte, int32_t highbyte, const int32_t * table); +void op_wide(struct vm * vm); diff --git a/c/file.c b/c/file.c new file mode 100644 index 0000000..07b9ed4 --- /dev/null +++ b/c/file.c @@ -0,0 +1,25 @@ +#include +#include +#include +#include + +#include "file.h" + +uint8_t * file_read(const char * path) +{ + int ret; + FILE * f = fopen(path, "rb"); + assert(f != nullptr); + ret = fseek(f, 0L, SEEK_END); + assert(ret != -1); + long size = ftell(f); + assert(size != -1); + ret = fseek(f, 0L, SEEK_SET); + assert(ret != -1); + + uint8_t * buf = malloc(size); + size_t read = fread(buf, 1, size, f); + assert(read == size); + + return buf; +} diff --git a/c/file.h b/c/file.h new file mode 100644 index 0000000..69b502c --- /dev/null +++ b/c/file.h @@ -0,0 +1,5 @@ +#pragma once + +#include + +uint8_t * file_read(const char * path); diff --git a/c/frame.c b/c/frame.c new file mode 100644 index 0000000..8fbf809 --- /dev/null +++ b/c/frame.c @@ -0,0 +1,145 @@ +#include +#include +#include + +#include "class_file.h" +#include "file.h" +#include "memory.h" +#include "debug_class_file.h" +#include "bytes.h" +#include "decode.h" +#include "frame.h" + +struct frame * stack_push_frame(struct stack * stack, int num_frames) +{ + struct frame * frame = &stack->frame[stack->ix]; + stack->ix += num_frames; + assert(stack->ix <= stack->capacity); + return frame; +} + +struct frame * stack_pop_frame(struct stack * stack, int num_frames) +{ + stack->ix -= num_frames; + assert(stack->ix >= 0); + struct frame * frame = &stack->frame[stack->ix]; + return frame; +} + +uint32_t * stack_push_data(struct stack * stack, int num_data) +{ + uint32_t * data = &stack->data[stack->ix]; + stack->ix += num_data; + assert(stack->ix <= stack->capacity); + return data; +} + +uint32_t * stack_pop_data(struct stack * stack, int num_data) +{ + stack->ix -= num_data; + assert(stack->ix >= 0); + uint32_t * data = &stack->data[stack->ix]; + return data; +} + +struct Code_attribute * get_code_attribute(int code_name_index, + int attributes_count, + struct attribute_info * attributes) +{ + for (int i = 0; i < attributes_count; i++) { + if (attributes[i].attribute_name_index == code_name_index) + return attributes[i].code; + } + return nullptr; +} + +int find_code_name_index(struct class_file * class_file) +{ + for (int i = 0; i < class_file->constant_pool_count; i++) { + struct constant * constant = &class_file->constant_pool[i]; + if (constant->tag == CONSTANT_Utf8) { + if (bytes_equal(constant->utf8.length, constant->utf8.bytes, "Code")) { + return i + 1; + } + } + } + return 0; +} + +void vm_execute(struct vm * vm) +{ + printf("execute:\n"); + struct constant * class = &vm->current_thread.current_class->constant_pool[vm->current_thread.current_class->this_class - 1]; + print_constant(class); + print_constant(&vm->current_thread.current_class->constant_pool[class->class.name_index - 1]); + print_constant(&vm->current_thread.current_class->constant_pool[vm->current_thread.current_method->name_index - 1]); + + int code_name_index = find_code_name_index(vm->current_thread.current_class); + assert(code_name_index > 0); + printf("code_name_index %d\n", code_name_index); + + struct Code_attribute * code = get_code_attribute(code_name_index, + vm->current_thread.current_method->attributes_count, + vm->current_thread.current_method->attributes); + assert(code != nullptr); + + vm->current_frame = stack_push_frame(&vm->frame_stack, 1); + vm->current_frame->local_variable = stack_push_data(&vm->data_stack, code->max_locals); + vm->current_frame->operand_stack = stack_push_data(&vm->data_stack, code->max_stack); + vm->current_frame->operand_stack_ix = 0; + + while (true) { + printf("[ "); + for (int i = 5; i > 0; i--) { + if (i > vm->current_frame->operand_stack_ix) { + printf(" "); + continue; + } + int32_t value = vm->current_frame->operand_stack[vm->current_frame->operand_stack_ix - i]; + if (value > 65536) + printf("0x%08x ", value); + else + printf("%10d ", value); + } + printf("]\n"); + decode_print_instruction(code->code, vm->current_thread.pc); + uint32_t old_pc = vm->current_thread.pc; + uint32_t next_pc = decode_execute_instruction(vm, code->code, vm->current_thread.pc); + if (vm->current_thread.pc == old_pc) { + // if the instruction did not branch, increment pc + vm->current_thread.pc = next_pc; + } + + if (vm->current_thread.pc >= code->code_length) { + printf("terminate\n"); + break; + } + } +} + +int main(int argc, char * argv[]) +{ + assert(argc >= 2); + uint8_t * buf = file_read(argv[1]); + struct class_file * class_file = class_file_parse(buf); + + assert(class_file->magic == 0xcafebabe); + assert(class_file->methods_count >= 1); + + struct vm vm; + vm.current_thread.pc = 0; + vm.current_thread.current_class = class_file; + vm.current_thread.current_method = &class_file->methods[1]; + + vm.frame_stack.ix = 0; + vm.frame_stack.capacity = 1024; + struct frame frames[vm.frame_stack.capacity]; + vm.frame_stack.frame = frames; + + vm.data_stack.ix = 0; + vm.data_stack.capacity = 0x100000; + uint32_t data[vm.data_stack.capacity]; + vm.data_stack.data = data; + + vm_execute(&vm); +} diff --git a/c/frame.h b/c/frame.h new file mode 100644 index 0000000..8f2dc56 --- /dev/null +++ b/c/frame.h @@ -0,0 +1,57 @@ +#pragma once + +#include + +#include "class_file.h" + +struct frame { + uint32_t * local_variable; + uint32_t * operand_stack; + uint16_t operand_stack_ix; + #ifdef DEBUG + uint32_t operand_stack_capacity; + #endif +}; + +struct thread { + uint32_t pc; + struct class_file * current_class; + struct method_info * current_method; +}; + +struct stack { + union { + struct frame * frame; + uint32_t * data; + }; + uint32_t ix; + uint32_t capacity; +}; + +struct vm { + struct stack frame_stack; + struct stack data_stack; + struct thread current_thread; + struct frame * current_frame; +}; + +static inline void operand_stack_push_u32(struct frame * frame, uint32_t value) +{ + frame->operand_stack[frame->operand_stack_ix] = value; + frame->operand_stack_ix++; +} + +static inline uint32_t operand_stack_pop_u32(struct frame * frame) +{ + frame->operand_stack_ix--; + uint32_t value = frame->operand_stack[frame->operand_stack_ix]; + frame->operand_stack[frame->operand_stack_ix] = -1; + return value; +} + +static inline void operand_stack_dup_u32(struct frame * frame) +{ + uint32_t value = frame->operand_stack[frame->operand_stack_ix - 1]; + frame->operand_stack[frame->operand_stack_ix] = value; + frame->operand_stack_ix++; +} diff --git a/c/hash_table.c b/c/hash_table.c new file mode 100644 index 0000000..3f77d0c --- /dev/null +++ b/c/hash_table.c @@ -0,0 +1,268 @@ +#include + +static uint32_t fnv_1(const uint8_t * buf, int length) +{ + const uint32_t fnv_offset_basis = 0x811c9dc5; + const uint32_t fnv_prime = 0x01000193; + + uint32_t hash = fnv_offset_basis; + + for (int i = 0; i < length; i++) { + hash = hash * fnv_prime; + hash = hash ^ buf[i]; + } + + return hash; +} + +struct hash_table_entry { + const uint8_t * key; + int key_length; + void * value; + struct hash_table_entry * next; +}; + +void hash_table_init(int hash_table_length, + struct hash_table_entry * entry, + struct hash_table_entry * overflow) +{ + for (int i = 0; i < hash_table_length; i++) { + entry[i].key = nullptr; + entry[i].next = nullptr; + overflow[i].key = nullptr; + overflow[i].next = nullptr; + } +} + +static int max = 0; + +void hash_table_add(int hash_table_length, + struct hash_table_entry * entry, + struct hash_table_entry * overflow, + int * overflow_length, + const uint8_t * key, + int key_length, + void * value) +{ + uint32_t hash = fnv_1(key, key_length) & (hash_table_length - 1); + struct hash_table_entry * e = &entry[hash]; + + while (e->next != nullptr) { + e = e->next; + } + + int i = 0; + if (e->key != nullptr) { + if ((++i) > max) max = i; + + // allocate e from overflow + e->next = &overflow[(*overflow_length)++]; + e = e->next; + } + + e->key = key; + e->key_length = key_length; + e->value = value; +} + +static inline bool key_equal(const uint8_t * a, const uint8_t * b, int length) +{ + for (int i = 0; i < length; i++) { + if (a[i] != b[i]) + return false; + } + return true; +} + + +#include + +struct hash_table_entry * hash_table_find(int hash_table_length, + struct hash_table_entry * entry, + struct hash_table_entry * overflow, + const uint8_t * key, + int key_length) +{ + uint32_t hash = fnv_1(key, key_length) & (hash_table_length - 1); + struct hash_table_entry * e = &entry[hash]; + + while (e->key != nullptr) { + if (e->key_length == key_length && key_equal(e->key, key, key_length)) { + return e; + } + printf("collision %s %s\n", (char *)e->key, (char *)key); + e = e->next; + } + return nullptr; +} + +#include +#include +#include +#include + +static const char * names[] = { + "java/beans/Introspector.java", + "java/beans/PropertyDescriptor.java", + "java/beans/PropertyVetoException.java", + "java/beans/BeanInfo.java", + "java/beans/Customizer.java", + "java/beans/FeatureDescriptor.java", + "java/beans/BeanDescriptor.java", + "java/beans/Beans.java", + "java/beans/AppletInitializer.java", + "java/beans/Expression.java", + "java/beans/MethodDescriptor.java", + "java/beans/PropertyChangeSupport.java", + "java/beans/PropertyChangeEvent.java", + "java/beans/DesignMode.java", + "java/beans/EventSetDescriptor.java", + "java/beans/IndexedPropertyDescriptor.java", + "java/beans/VetoableChangeListener.java", + "java/beans/ConstructorProperties.java", + "java/beans/IndexedPropertyChangeEvent.java", + "java/beans/PropertyEditorManager.java", + "java/beans/IntrospectionException.java", + "java/beans/PropertyChangeListener.java", + "java/beans/XMLEncoder.java", + "java/beans/Visibility.java", + "java/beans/VetoableChangeSupport.java", + "java/beans/ParameterDescriptor.java", + "java/beans/XMLDecoder.java", + "java/beans/PropertyChangeListenerProxy.java", + "java/beans/ExceptionListener.java", + "java/beans/VetoableChangeListenerProxy.java", + "java/beans/DefaultPersistenceDelegate.java", + "java/beans/EventHandler.java", + "java/beans/Statement.java", + "java/beans/PropertyEditor.java", + "java/beans/PropertyEditorSupport.java", + "java/beans/SimpleBeanInfo.java", + "java/beans/PersistenceDelegate.java", + "java/beans/Encoder.java", + "java/beans/beancontext/BeanContextChildSupport.java", + "java/beans/beancontext/BeanContextServicesSupport.java", + "java/beans/beancontext/BeanContextServiceRevokedEvent.java", + "java/beans/beancontext/BeanContextSupport.java", + "java/beans/beancontext/BeanContextServiceAvailableEvent.java", + "java/beans/beancontext/BeanContextServiceProvider.java", + "java/beans/beancontext/BeanContextProxy.java", + "java/beans/beancontext/BeanContextServiceProviderBeanInfo.java", + "java/beans/beancontext/BeanContextContainerProxy.java", + "java/beans/beancontext/BeanContextMembershipListener.java", + "java/beans/beancontext/BeanContextServices.java", + "java/beans/beancontext/BeanContextServiceRevokedListener.java", + "java/beans/beancontext/BeanContext.java", + "java/beans/beancontext/BeanContextChildComponentProxy.java", + "java/beans/beancontext/BeanContextMembershipEvent.java", + "java/beans/beancontext/BeanContextEvent.java", + "java/beans/beancontext/BeanContextServicesListener.java", + "java/beans/beancontext/BeanContextChild.java", + "java/net/ContentHandler.java", + "java/net/URL.java", + "java/net/FileNameMap.java", + "java/net/SocketOptions.java", + "java/net/DatagramSocketImplFactory.java", + "java/net/UnknownServiceException.java", + "java/net/SocketPermission.java", + "java/net/NoRouteToHostException.java", + "java/net/NetPermission.java", + "java/net/URI.java", + "java/net/DatagramSocket.java", + "java/net/DatagramPacket.java", + "java/net/BindException.java", + "java/net/SocketTimeoutException.java", + "java/net/ProxySelector.java", + "java/net/MalformedURLException.java", + "java/net/URLStreamHandlerFactory.java", + "java/net/InetAddress.java", + "java/net/PortUnreachableException.java", + "java/net/DatagramSocketImpl.java", + "java/net/UnknownHostException.java", + "java/net/ProtocolException.java", + "java/net/Proxy.java", + "java/net/PasswordAuthentication.java", + "java/net/SocketAddress.java", + "java/net/MulticastSocket.java", + "java/net/ServerSocket.java", + "java/net/JarURLConnection.java", + "java/net/Authenticator.java", + "java/net/URLStreamHandler.java", + "java/net/ConnectException.java", + "java/net/NetworkInterface.java", + "java/net/URLConnection.java", + "java/net/URLEncoder.java", + "java/net/InetSocketAddress.java", + "java/net/URISyntaxException.java", + "java/net/ResolverCache.java", + "java/net/Socket.java", + "java/net/Inet4Address.java", + "java/net/SocketException.java", + "java/net/SocketImplFactory.java", + "java/net/ContentHandlerFactory.java", + "java/net/HttpURLConnection.java", + "java/net/URLDecoder.java", + "java/net/SocketImpl.java", + "java/net/URLClassLoader.java", + "java/net/Inet6Address.java", + "java/net/MimeTypeMapper.java", + "java/math/MathContext.java", + "java/math/BigInteger.java", + "java/math/BigDecimal.java", + "java/math/RoundingMode.java", + "java/io/FileWriter.java", + "java/io/FilePermission.java", + "java/io/OutputStreamWriter.java", + "java/io/ObjectInput.java", + "java/io/BufferedOutputStream.java", + "java/io/IOError.java", + "java/io/LineNumberReader.java", + "java/io/StringReader.java", + "java/io/BufferedInputStream.java", + "java/io/CharArrayWriter.java", + "java/io/InputStreamReader.java", + "java/io/Console.java", + "java/io/FileOutputStream.java", + "java/io/StringBufferInputStream.java", + "java/io/DataOutput.java", + "java/io/UTFDataFormatException.java", + "java/io/ObjectStreamConstants.java", + "java/io/ObjectStreamException.java", + "java/io/BufferedReader.java", + "java/io/FilenameFilter.java", +}; +const int names_length = (sizeof (names)) / (sizeof (names[0])); + +int main() +{ + int hash_table_length = 512; + struct hash_table_entry entry[hash_table_length]; + struct hash_table_entry overflow[hash_table_length]; + int overflow_length = 0; + + hash_table_init(hash_table_length, + entry, + overflow); + + for (int i = 0; i < names_length; i++) { + hash_table_add(hash_table_length, + entry, + overflow, + &overflow_length, + (const uint8_t *)names[i], + strlen(names[i]), + (void *)(ptrdiff_t)(i * 2)); + } + + printf("overflow_length %d %d\n", overflow_length, max); + + for (int j = 0; j < names_length; j++) { + struct hash_table_entry * e = hash_table_find(hash_table_length, + entry, + overflow, + (const uint8_t *)names[j], + strlen(names[j])); + assert(e != nullptr); + printf("%s %d\n", e->key, (int)e->value); + } +} diff --git a/c/malloc.c b/c/malloc.c new file mode 100644 index 0000000..2ff6149 --- /dev/null +++ b/c/malloc.c @@ -0,0 +1,24 @@ +#include + +#include "malloc.h" + +struct arena { + uint8_t * mem; + uint32_t size; + uint32_t ix; +}; + +static uint8_t class_mem[0x100000]; + +struct arena class_arena = { + .mem = class_mem, + .size = (sizeof (class_mem)), + .ix = 0, +}; + +void * malloc_class_arena(uint32_t size) +{ + void * ptr = &class_arena.mem[class_arena.ix]; + class_arena.ix += size; + return ptr; +} diff --git a/c/malloc.h b/c/malloc.h new file mode 100644 index 0000000..fd07794 --- /dev/null +++ b/c/malloc.h @@ -0,0 +1,3 @@ +#pragma once + +void * malloc_class_arena(uint32_t size); diff --git a/c/memory_allocator.c b/c/memory_allocator.c new file mode 100644 index 0000000..0535fea --- /dev/null +++ b/c/memory_allocator.c @@ -0,0 +1,113 @@ +#include +#include + +#define block_power (5UL) +#define block_size (1UL << block_power) +//static uint8_t memory[0x100]; +static uint8_t memory[0x100000]; +#define free_list_length ((sizeof (memory)) / block_size) +static uint8_t free_list[free_list_length]; +static uint32_t free_ix; + +void memory_reset_free_list() +{ + for (int i = 0; i < (sizeof (free_list)); i++) { + free_list[i] = 0; + } + free_ix = 0; +} + +static inline uint32_t find_contiguous_blocks(uint32_t blocks, int * zero_crossing) +{ + if (free_ix + blocks > free_list_length) { + free_ix = 0; // non-contiguous + (*zero_crossing) += 1; + } + + for (uint32_t i = 0; i < blocks; i++) { + if (free_list[free_ix + i] != 0) + return i + 1; + } + return blocks; +} + +#include + +void * memory_allocate(uint32_t size) +{ + assert(size != 0); + + uint32_t blocks = ((size + (block_size - 1)) & ~(block_size - 1)) >> block_power; + int zero_crossings = 0; + + while (true) { + uint32_t ix_offset = find_contiguous_blocks(blocks, &zero_crossings); + if (zero_crossings > 1) + return nullptr; // memory allocation failed + if (ix_offset == blocks) + break; + free_ix = (free_ix + ix_offset) & (free_list_length - 1); + } + + for (int i = 0; i < (blocks - 1); i++) { + free_list[free_ix + i] = 2; + } + free_list[free_ix + (blocks - 1)] = 1; + + void * mem = &memory[free_ix << block_power]; + free_ix = (free_ix + blocks) & (free_list_length - 1); + return mem; +} + +void memory_free(void * p) +{ + assert(((uint8_t*)p) >= memory); + uint32_t offset = (((uint8_t*)p) - memory) >> block_power; + assert(free_list[offset] != 0); + + while (free_list[offset] == 2) { + free_list[offset] = 0; + offset += 1; + } + assert(free_list[offset] == 1); + free_list[offset] = 0; +} + +#if 0 +int main() +{ + memory_reset_free_list(); + printf("%p\n", memory); + + void * p1 = memory_allocate(32); + printf("p1 %p\n", p1); + void * p2 = memory_allocate(16); + printf("p2 %p\n", p2); + void * p3 = memory_allocate(256); + printf("p3 %p\n", p3); + void * p4 = memory_allocate(90); + printf("p4 %p\n", p4); + for (int i = 0; i < free_list_length; i++) { printf("%d ", free_list[i]); } + printf("\n"); + + memory_free(p2); + memory_free(p1); + void * p5 = memory_allocate(256); + printf("%p\n", p4); + + for (int i = 0; i < free_list_length; i++) { printf("%d ", free_list[i]); } + printf("\n"); + + void * p6 = memory_allocate(128); + printf("p5 %p\n", p5); + + memory_free(p4); + + void * p7 = memory_allocate(128); + printf("p6 %p\n", p6); + void * p8 = memory_allocate(128); + printf("p7 %p\n", p7); + void * p9 = memory_allocate(128); + printf("p8 %p\n", p8); +} +#endif diff --git a/c/memory_allocator.h b/c/memory_allocator.h new file mode 100644 index 0000000..2ace29e --- /dev/null +++ b/c/memory_allocator.h @@ -0,0 +1,5 @@ +#include + +void memory_reset_free_list(); +void * memory_allocate(uint32_t size); +void memory_free(void * p); diff --git a/c/print_class.c b/c/print_class.c new file mode 100644 index 0000000..edb6fd6 --- /dev/null +++ b/c/print_class.c @@ -0,0 +1,16 @@ +#include +#include + +#include "debug_class_file.h" +#include "file.h" + +int main(int argc, char * argv[]) +{ + assert(argc >= 2); + uint8_t * buf = file_read(argv[1]); + + struct class_file * class_file = class_file_parse(buf); + print_class_file(class_file); + + return 0; +} diff --git a/class_file.py b/class_file.py new file mode 100644 index 0000000..fbe8452 --- /dev/null +++ b/class_file.py @@ -0,0 +1,237 @@ +import struct +import sys +from binascii import hexlify + +def parse_row(s): + a, b, c, d = s.strip().split(',') + return int(a), c, int(d) + +def parse_opcode_table(buf): + rows = [parse_row(i) for i in buf.strip().split('\n')] + return {opcode: (name, args) for opcode, name, args in rows} + +with open('opcodes.csv', 'r') as f: + opcode_table = parse_opcode_table(f.read()) + +def size_to_format(size): + if size == 4: + return ">I" + elif size == 2: + return ">H" + elif size == 1: + return ">B" + else: + assert False, size + +def field(buf, size): + format = size_to_format(size) + value, = struct.unpack(format, buf[0:size]) + return buf[size:], value + +constant_lookup = { + 7: ("CONSTANT_Class", [("name_index", 2)]), + 9: ("CONSTANT_Fieldref", [("class_index", 2), ("name_and_type_index", 2)]), + 10: ("CONSTANT_Methodref", [("class_index", 2), ("name_and_type_index", 2)]), + 11: ("CONSTANT_InterfaceMethodref", [("class_index", 2), ("name_and_type_index", 2)]), + 8: ("CONSTANT_String", [("string_index", 2)]), + 3: ("CONSTANT_Integer", [("bytes", 4)]), + 4: ("CONSTANT_Float", [("bytes", 4)]), + 5: ("CONSTANT_Long", [("high_bytes", 4), ("low_bytes", 4)]), + 6: ("CONSTANT_Double", [("high_bytes", 4), ("low_bytes", 4)]), + 12: ("CONSTANT_NameAndType", [("name_index", 2), ("descriptor_index", 2)]), + 1: ("CONSTANT_Utf8", [("length", 2), ("bytes", 0)]), + 15: ("CONSTANT_MethodHandle", [("reference_kind", 2), ("reference_index", 2)]), + 16: ("CONSTANT_MethodType", [("descriptor_index", 2)]), + 18: ("CONSTANT_InvokeDynamic", [("bootstrap_method_attr_index", 2), ("name_and_type_index", 2)]), +} + + +def parse_cp_info(buf): + buf, tag = field(buf, 1) + assert tag in constant_lookup, tag + name, fields = constant_lookup[tag] + d = {} + last_value = None + for field_name, field_size in fields: + if field_size == 0: + value = bytes(buf[0:last_value]) + buf = buf[last_value:] + else: + buf, value = field(buf, field_size) + last_value = value + d[field_name] = value + return buf, (name, d) + +def parse_attribute_info(buf): + buf, attribute_name_index = field(buf, 2) + buf, attribute_length = field(buf, 4) + info = bytes(buf[0:attribute_length]) + buf = buf[attribute_length:] + return buf, (attribute_name_index, attribute_length, info) + +def parse_field_info(buf): + buf, access_flags = field(buf, 2) + buf, name_index = field(buf, 2) + buf, descriptor_index = field(buf, 2) + buf, attributes_count = field(buf, 2) + attributes = [] + for i in range(attributes_count): + buf, attribute = parse_attribute_info(buf) + attributes.append(attribute) + return buf, (access_flags, name_index, descriptor_index, attributes_count, attributes) + +def parse_exception_table(buf, indent): + exception_table = [ + ("start_pc", 2), + ("end_pc", 2), + ("handler_pc", 2), + ("catch_type", 2), + ] + for name, size in exception_table: + buf, value = field(buf, size) + print(indent, name, value) + return buf + +def dump_opcodes(buf, indent): + ix = 0 + while len(buf) > 0: + op = buf[0] + name, arg_length = opcode_table[op] + buf = buf[1:] + args = list(buf[0:arg_length]) + print(indent, f"{ix:> 3}", name, args) + ix += 1 + arg_length + buf = buf[arg_length:] + +def print_code_info(buf, indent, constant_pool): + code_attribute = [ + ("max_stack", 2), + ("max_locals", 2), + ("code_length", 4), + ("code", 0), + ("exception_table_length", 2), + ("exception_table", 0), + ("attributes_count", 2), + ("attributes", 0) + ] + last_value = None + for name, size in code_attribute: + if name == "code": + print(indent, "code:") + size = last_value + dump_opcodes(buf[0:last_value], indent + " ") + buf = buf[last_value:] + elif name == "exception_table": + print(indent, "exception_table:") + for i in range(last_value): + buf = parse_exception_table(buf, indent + " ") + elif name == "attributes": + print(indent, "attributes:") + for i in range(last_value): + buf, attribute_info = parse_attribute_info(buf) + print(indent + " ", f"attribute {i}:") + attribute_name_index, attribute_length, info = attribute_info + + constant_type, constant = constant_pool[attribute_name_index - 1] + assert constant_type == 'CONSTANT_Utf8', constant_type + attribute_name_bytes = constant["bytes"] + + print(indent + " ", "attribute_name_index", attribute_name_index, attribute_name_bytes) + print(indent + " ", "attribute_length", attribute_length) + print(indent + " ", "info", info) + else: + buf, value = field(buf, size) + last_value = value + print(indent, name, value) + assert len(buf) == 0 + +def parse_class(buf): + buf, magic = field(buf, 4) + buf, minor_version = field(buf, 2) + buf, major_version = field(buf, 2) + buf, constant_pool_count = field(buf, 2) + + print("magic", hex(magic)) + print("minor_version", minor_version) + print("major_version", major_version) + print("constant_pool_count", constant_pool_count) + + print("constant_pool:") + constant_pool = [] + for i in range(constant_pool_count - 1): + buf, cp_info = parse_cp_info(buf) + constant_pool.append(cp_info) + print(i + 1, cp_info) + + buf, access_flags = field(buf, 2) + buf, this_class = field(buf, 2) + buf, super_class = field(buf, 2) + buf, interfaces_count = field(buf, 2) + + print("access_flags", hex(access_flags)) + print("this_class", this_class) + print("super_class", super_class) + print("interfaces_count", interfaces_count) + + print("interfaces:") + for i in range(interfaces_count): + buf, interface = field(buf, 2) + print(i, interface) + + buf, fields_count = field(buf, 2) + print("fields_count", fields_count) + for i in range(fields_count): + buf, field_info = parse_field_info(buf) + print(i, field_info) + + buf, methods_count = field(buf, 2) + print("methods_count", methods_count) + print("methods:") + for i in range(methods_count): + buf, method_info = parse_field_info(buf) + print(f" method {i}:") + access_flags, name_index, descriptor_index, attributes_count, attributes = method_info + print(" access_flags", hex(access_flags)) + + constant_type, constant = constant_pool[name_index - 1] + assert constant_type == 'CONSTANT_Utf8', constant_type + name_bytes = constant["bytes"] + + print(" name_index", name_index, name_bytes) + + constant_type, constant = constant_pool[descriptor_index - 1] + assert constant_type == 'CONSTANT_Utf8', constant_type + descriptor_bytes = constant["bytes"] + + print(" descriptor_index", descriptor_index, descriptor_bytes) + print(" attributes_count", attributes_count) + print(" attributes:") + for j in range(attributes_count): + print(f" attribute {j}:") + attribute_name_index, attribute_length, info = attributes[j] + + constant_type, constant = constant_pool[attribute_name_index - 1] + assert constant_type == 'CONSTANT_Utf8', constant_type + attribute_name_bytes = constant["bytes"] + + print(" attribute_name_index", attribute_name_index, attribute_name_bytes) + print(" attribute_length", attribute_length) + #print(" info", info) + if attribute_name_bytes == b'Code': + print_code_info(info, " ", constant_pool) + + buf, attributes_count = field(buf, 2) + print("attributes_count", attributes_count) + print("attributes:") + for i in range(attributes_count): + buf, attribute_info = parse_attribute_info(buf) + print(i, attribute_info) + + assert len(buf) == 0, bytes(buf) + +filename = sys.argv[1] + +with open(filename, 'rb') as f: + buf = f.read() + +parse_class(memoryview(buf)) diff --git a/gen_decoder.py b/gen_decoder.py new file mode 100644 index 0000000..7f75395 --- /dev/null +++ b/gen_decoder.py @@ -0,0 +1,245 @@ +import io +import sys +from dataclasses import dataclass +import csv +from pprint import pprint + +@dataclass +class Argument: + signed: bool + size: int + name: str + +@dataclass +class Instruction: + code: int + mnemonic: str + arguments_size: int + arguments: list[Argument] + +def parse_arguments(types, arguments): + types = types.strip() + arguments = arguments.strip() + if not types: + assert not arguments + return 0, [] + + types = types.split(',') + arguments = arguments.split(',') + assert len(types) == len(arguments), (types, arguments) + + total_size = 0 + l = list(zip(types, arguments)) + args = [] + for i, (type, name) in enumerate(l): + signed = None + if type.startswith('v'): + assert i == (len(l) - 1), l + assert name == '_', name + total_size += int(type.removeprefix('v')) + continue + elif type.startswith('s'): + size = int(type.removeprefix('s')) + signed = True + elif type.startswith('u'): + size = int(type.removeprefix('u')) + signed = False + else: + assert False, (type, argument) + + assert size in {1, 2, 4} + assert signed is not None + if name in {"byte", "branch"}: + assert signed == True, name + else: + assert signed == False, name + + total_size += size + args.append(Argument( + signed=signed, + size=size, + name=name, + )) + + return total_size, args + +def parse_row(row): + code, _, mnemonic, types, arguments = row + + if types.strip() == '-1': + arguments_size = -1; + arguments = arguments.split(',') + else: + arguments_size, arguments = parse_arguments(types, arguments) + + yield Instruction( + code=int(code), + mnemonic=mnemonic, + arguments_size=arguments_size, + arguments=arguments + ) + +def parse_opcode_table(): + with open('opcodes.csv', 'r') as f: + reader = csv.reader(f, delimiter=",", quotechar='"') + instructions = [instruction for row in reader for instruction in parse_row(row)] + return instructions + +opcode_table = list(sorted(parse_opcode_table(), key=lambda i: i.code)) + +sign_type_table = { + (True, 4): "_s4", + (True, 2): "_s2", + (True, 1): "_s1", + (False, 4): "_u4", + (False, 2): "_u2", + (False, 1): "_u1", +} + +def generate_print_fixed_width_instruction(instruction): + offset = 1 + for argument in instruction.arguments: + c_type = "int32_t" if argument.signed else "uint32_t" + conversion = sign_type_table[(argument.signed, argument.size)] + yield f"{c_type} {argument.name} = {conversion}(&code[pc + {offset}]);" + offset += argument.size + + argument_format = ", ".join( + f"%{'d' if argument.signed else 'u'}" + for argument in instruction.arguments + ) + argument_values = ", ".join( + argument.name + for argument in instruction.arguments + ) + if argument_values: + argument_values = ", " + argument_values + mnemonic = instruction.mnemonic.ljust(13) + yield f'printf("%4d: {mnemonic} {argument_format}\\n", pc{argument_values});' + yield f"return pc + {1 + instruction.arguments_size};" + +def generate_print_variable_width_instruction(instruction): + mnemonic = instruction.mnemonic.ljust(13) + yield f"{instruction.mnemonic.upper()}_ARGS;" + yield f'printf("%4d: {mnemonic} {{\\n", pc);' + yield f"{instruction.mnemonic.upper()}_PRINT_ARGS();" + yield 'printf("}\\n");' + yield f"return {instruction.mnemonic.upper()}_NEXT_PC;" + +def generate_print_decoder(): + yield "uint32_t decode_print_instruction(const uint8_t * code, uint32_t pc)" + yield "{" + yield "switch (code[pc]) {" + for instruction in opcode_table: + yield f"case {instruction.code}: // {instruction.mnemonic}" + yield "{" + + if instruction.arguments_size == -1: + yield from generate_print_variable_width_instruction(instruction) + else: + yield from generate_print_fixed_width_instruction(instruction) + + yield "}" + + yield "default:" + yield "{" + yield "assert(false);" + yield "return pc;" + yield "}" + yield "}" + yield "}" + +def generate_execute_fixed_width_instruction(instruction): + offset = 1 + for argument in instruction.arguments: + c_type = "int32_t" if argument.signed else "uint32_t" + conversion = sign_type_table[(argument.signed, argument.size)] + yield f"{c_type} {argument.name} = {conversion}(&code[pc + {offset}]);" + offset += argument.size + argument_values = ", ".join( + argument.name + for argument in instruction.arguments + ) + if argument_values: + argument_values = ", " + argument_values + yield f"op_{instruction.mnemonic}(vm{argument_values});" + yield f"return pc + {1 + instruction.arguments_size};" + +def generate_execute_variable_width_instruction(instruction): + yield f"{instruction.mnemonic.upper()}_ARGS;" + argument_values = ", ".join( + argument + for argument in instruction.arguments + ) + if argument_values: + argument_values = ", " + argument_values + yield f"op_{instruction.mnemonic}(vm{argument_values});" + yield f"return {instruction.mnemonic.upper()}_NEXT_PC;" + +def generate_execute_decoder(): + yield "uint32_t decode_execute_instruction(struct vm * vm, const uint8_t * code, uint32_t pc)" + yield "{" + yield "switch (code[pc]) {" + for instruction in opcode_table: + yield f"case {instruction.code}: // {instruction.mnemonic}" + yield "{" + + if instruction.arguments_size == -1: + yield from generate_execute_variable_width_instruction(instruction) + else: + yield from generate_execute_fixed_width_instruction(instruction) + + yield "}" + yield "default:" + yield "{" + yield "assert(false);" + yield "return pc;" + yield "}" + yield "}" + yield "}" + +def should_autonewline(line): + return ( + "static_assert" not in line + and "extern" not in line + and (len(line.split()) < 2 or line.split()[1] != '=') # hacky; meh + ) + +def _render(out, lines): + indent = " " + level = 0 + namespace = 0 + for l in lines: + if l and (l[0] == "}" or l[0] == ")"): + level -= 2 + if level < 0: + assert namespace >= 0 + namespace -= 1 + level = 0 + + if len(l) == 0: + out.write("\n") + else: + out.write(indent * level + l + "\n") + + if l and (l[-1] == "{" or l[-1] == "("): + if l.startswith("namespace"): + namespace += 1 + else: + level += 2 + + if level == 0 and l and l[-1] == ";": + if should_autonewline(l): + out.write("\n") + return out + +def renderer(): + out = io.StringIO() + def render(lines): + return _render(out, lines) + return render, out + +render, out = renderer() +render(generate_print_decoder()) +render(generate_execute_decoder()) +sys.stdout.write(out.getvalue()) diff --git a/opcodes.ods b/opcodes.ods new file mode 100644 index 0000000..3d9760c Binary files /dev/null and b/opcodes.ods differ diff --git a/p/AdventDay1.java b/p/AdventDay1.java new file mode 100644 index 0000000..506a691 --- /dev/null +++ b/p/AdventDay1.java @@ -0,0 +1,63 @@ +package p; + +class AdventDay1 { + public static int part1() { + int[] input = {3, 4, + 4, 3, + 2, 5, + 1, 3, + 3, 9, + 3, 3}; + + int[] left = new int[input.length / 2]; + int[] right = new int[input.length / 2]; + + for (int i = 0; i < input.length / 2; i++) { + left[i] = input[i * 2]; + right[i] = input[i * 2 + 1]; + } + + // bubble sort left + while (true) { + boolean swapped = false; + for (int i = 1; i < left.length; i++) { + if (left[i - 1] > left[i]) { + int tmp = left[i - 1]; + left[i - 1] = left[i]; + left[i] = tmp; + swapped = true; + } + } + if (!swapped) + break; + } + + // bubble sort right + while (true) { + boolean swapped = false; + for (int i = 1; i < right.length; i++) { + if (right[i - 1] > right[i]) { + int tmp = right[i - 1]; + right[i - 1] = right[i]; + right[i] = tmp; + swapped = true; + } + } + if (!swapped) + break; + } + + int sum = 0; + for (int i = 0; i < left.length; i++) { + int dist = left[i] - right[i]; + if (dist < 0) + dist = -dist; + sum += dist; + } + return sum; + } + + public static void main(String[] args) { + System.out.println(part1()); + } +} diff --git a/p/AdventDay1_String.java b/p/AdventDay1_String.java new file mode 100644 index 0000000..76a4952 --- /dev/null +++ b/p/AdventDay1_String.java @@ -0,0 +1,84 @@ +package p; + +class AdventOfCode2024Day1 { + public static int part1() { + char[] string_input = { + '3', ' ', ' ', ' ', '4', '\n', + '4', ' ', ' ', ' ', '3', '\n', + '2', ' ', ' ', ' ', '5', '\n', + '1', ' ', ' ', ' ', '3', '\n', + '3', ' ', ' ', ' ', '9', '\n', + '3', ' ', ' ', ' ', '3', '\n', + }; + + int[] input = new int[100]; + int nums = 0; + for (int i = 0; i < string_input.length; i++) { + switch (string_input[i]) { + case '0': input[nums++] = 0; break; + case '1': input[nums++] = 1; break; + case '2': input[nums++] = 2; break; + case '3': input[nums++] = 3; break; + case '4': input[nums++] = 4; break; + case '5': input[nums++] = 5; break; + case '6': input[nums++] = 6; break; + case '7': input[nums++] = 7; break; + case '8': input[nums++] = 8; break; + case '9': input[nums++] = 9; break; + default: break; + } + } + + + int[] left = new int[nums / 2]; + int[] right = new int[nums / 2]; + + for (int i = 0; i < nums / 2; i++) { + left[i] = input[i * 2]; + right[i] = input[i * 2 + 1]; + } + + // bubble sort left + while (true) { + boolean swapped = false; + for (int i = 1; i < left.length; i++) { + if (left[i - 1] > left[i]) { + int tmp = left[i - 1]; + left[i - 1] = left[i]; + left[i] = tmp; + swapped = true; + } + } + if (!swapped) + break; + } + + // bubble sort right + while (true) { + boolean swapped = false; + for (int i = 1; i < right.length; i++) { + if (right[i - 1] > right[i]) { + int tmp = right[i - 1]; + right[i - 1] = right[i]; + right[i] = tmp; + swapped = true; + } + } + if (!swapped) + break; + } + + int sum = 0; + for (int i = 0; i < left.length; i++) { + int dist = left[i] - right[i]; + if (dist < 0) + dist = -dist; + sum += dist; + } + return sum; + } + + public static void main(String[] args) { + System.out.println(part1()); + } +} diff --git a/p/Data.java b/p/Data.java new file mode 100644 index 0000000..6f17bbb --- /dev/null +++ b/p/Data.java @@ -0,0 +1,5 @@ +package p; + +class Data { + static int[] num = {10, 20, 30, 40}; +} diff --git a/p/Java23.java b/p/Java23.java new file mode 100644 index 0000000..bb96899 --- /dev/null +++ b/p/Java23.java @@ -0,0 +1,9 @@ +package p; + +class Java23 { + +void main() { + java.io.IO.println("Hello world!"); +} + +} diff --git a/p/Main.java b/p/Main.java new file mode 100644 index 0000000..c3194c2 --- /dev/null +++ b/p/Main.java @@ -0,0 +1,29 @@ +package p; + +class Main { + public static int test2() { + int[] num = {10, 20, 30, 40}; + int sum = 0; + for (int i = 0; i < num.length; i++) { + sum += num[i]; + } + return sum + 1; + } + + public static int test1() { + int a = 6; + int b = 7; + int c = a * b; // 42 + int d = c << 4; // 672 + int e = d + 11; // 683 + int f = e - 3; // 680 + int g = f / 3; // 226 + int h = g ^ 0x0fffffff; // 268435229 + char i = (char)h; // 65309 + return i; + } + + public static void main(String[] args) { + System.out.println(test2()); + } +} diff --git a/p/Nest.java b/p/Nest.java new file mode 100644 index 0000000..20b5597 --- /dev/null +++ b/p/Nest.java @@ -0,0 +1,9 @@ +public class Nest { + private String secret = "Hidden message"; + public class InnerClass { + public void revealSecret() { + // Direct access to private member of OuterClass + System.out.println(secret); + } + } +} diff --git a/p/Rem.java b/p/Rem.java new file mode 100644 index 0000000..bcdbd4a --- /dev/null +++ b/p/Rem.java @@ -0,0 +1,7 @@ +package p; + +class Rem { + public static void main(String[] args) { + System.out.println(-42 % 9); + } +} diff --git a/p/Test.java b/p/Test.java new file mode 100644 index 0000000..a090da4 --- /dev/null +++ b/p/Test.java @@ -0,0 +1,36 @@ +package p; + +import java.util.ArrayList; + +public class Test { + public int foo(int a) { + return a * 2; + } + + public final String test = "asdf"; + public final int eggs = 1234; + public final float bacon = 12.34f; + + public int bar = foo(eggs); + + public static float mul(float a, float b) { + return a * b; + } + + public static int comp(int a, int b) { + if (a < b) { + return a * 2; + } else { + return a * 4; + } + } + + public static void main(String[] args) { + ArrayList numbers = new ArrayList(); + numbers.add(5); + numbers.add(9); + numbers.add(8); + numbers.add(1); + numbers.forEach( (n) -> { System.out.println(n); } ); + } +} diff --git a/p/Test2.java b/p/Test2.java new file mode 100644 index 0000000..f4d3551 --- /dev/null +++ b/p/Test2.java @@ -0,0 +1,9 @@ +package p; + +import p.Test; + +class Test2 { + public static float fmul(float a, float b, float c) { + return Test.mul(a, b) + c; + } +}