From 39f53e8ee416a489afb8c2d0d37da0b3dcd70d99 Mon Sep 17 00:00:00 2001 From: Zack Buhman Date: Mon, 23 Dec 2024 14:41:20 -0600 Subject: [PATCH] initial --- .gitignore | 8 + Makefile | 51 + c/a.out | Bin 0 -> 17740 bytes c/bswap.h | 7 + c/bytes.h | 80 ++ c/class_file.c | 225 ++++ c/class_file.h | 271 +++++ c/constant.h | 0 c/debug_class_file.c | 278 +++++ c/debug_class_file.h | 7 + c/decode.c | 97 ++ c/decode.h | 6 + c/decode.inc.c | 2192 ++++++++++++++++++++++++++++++++++++++ c/execute.c | 1217 +++++++++++++++++++++ c/execute.h | 211 ++++ c/file.c | 25 + c/file.h | 5 + c/frame.c | 145 +++ c/frame.h | 57 + c/hash_table.c | 268 +++++ c/malloc.c | 24 + c/malloc.h | 3 + c/memory_allocator.c | 113 ++ c/memory_allocator.h | 5 + c/print_class.c | 16 + class_file.py | 237 +++++ gen_decoder.py | 245 +++++ opcodes.ods | Bin 0 -> 32992 bytes p/AdventDay1.java | 63 ++ p/AdventDay1_String.java | 84 ++ p/Data.java | 5 + p/Java23.java | 9 + p/Main.java | 29 + p/Nest.java | 9 + p/Rem.java | 7 + p/Test.java | 36 + p/Test2.java | 9 + 37 files changed, 6044 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100755 c/a.out create mode 100644 c/bswap.h create mode 100644 c/bytes.h create mode 100644 c/class_file.c create mode 100644 c/class_file.h create mode 100644 c/constant.h create mode 100644 c/debug_class_file.c create mode 100644 c/debug_class_file.h create mode 100644 c/decode.c create mode 100644 c/decode.h create mode 100644 c/decode.inc.c create mode 100644 c/execute.c create mode 100644 c/execute.h create mode 100644 c/file.c create mode 100644 c/file.h create mode 100644 c/frame.c create mode 100644 c/frame.h create mode 100644 c/hash_table.c create mode 100644 c/malloc.c create mode 100644 c/malloc.h create mode 100644 c/memory_allocator.c create mode 100644 c/memory_allocator.h create mode 100644 c/print_class.c create mode 100644 class_file.py create mode 100644 gen_decoder.py create mode 100644 opcodes.ods create mode 100644 p/AdventDay1.java create mode 100644 p/AdventDay1_String.java create mode 100644 p/Data.java create mode 100644 p/Java23.java create mode 100644 p/Main.java create mode 100644 p/Nest.java create mode 100644 p/Rem.java create mode 100644 p/Test.java create mode 100644 p/Test2.java 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 0000000000000000000000000000000000000000..ef552a8838471abfd64363e38fe282f793afcb23 GIT binary patch literal 17740 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 JQcCC)`M;uPB1QlJ literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..3d9760cfd8006d3bdc90ba8f5f15c9085cbb754b GIT binary patch literal 32992 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 literal 0 HcmV?d00001 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; + } +}