From 932a7c82aa2318a56425e53d629f7aa644d14844 Mon Sep 17 00:00:00 2001 From: Zack Buhman Date: Mon, 23 Dec 2024 23:25:45 -0600 Subject: [PATCH] add class_resolver Implement the getfield and invokestatic opcodes. --- Makefile | 6 +- c/a.out | Bin 17740 -> 19772 bytes c/class_resolver.c | 163 ++++++++++++++++++++++++++++++++++ c/class_resolver.h | 42 +++++++++ c/debug_class_file.c | 13 ++- c/debug_class_file.h | 1 + c/execute.c | 77 ++++++++++++++++- c/frame.c | 101 +++++++++++++++++----- c/frame.h | 10 ++- c/hash_table.c | 202 ++----------------------------------------- c/hash_table.h | 24 +++++ c/malloc.c | 2 - c/malloc.h | 2 + c/string.h | 21 +++++ c/test_hash_table.c | 175 +++++++++++++++++++++++++++++++++++++ p/DataTest.java | 13 +++ 16 files changed, 620 insertions(+), 232 deletions(-) create mode 100644 c/class_resolver.c create mode 100644 c/class_resolver.h create mode 100644 c/hash_table.h create mode 100644 c/string.h create mode 100644 c/test_hash_table.c create mode 100644 p/DataTest.java diff --git a/Makefile b/Makefile index fb05457..6cac559 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,9 @@ OBJ = \ c/malloc.o \ c/file.o \ c/execute.o \ - c/memory_allocator.o + c/memory_allocator.o \ + c/class_resolver.o \ + c/hash_table.o MAIN_OBJ = \ $(OBJ) \ @@ -24,7 +26,7 @@ PRINT_CLASS_OBJ = \ CC ?= gcc ARCH = -m32 CFLAGS ?= -Wall -Werror -Wfatal-errors -Wno-error=unused-variable -std=c2x -DDEBUG -g -OPT ?= -Og +OPT ?= -O0 DEPFLAGS = -MMD -MP %.o: %.c diff --git a/c/a.out b/c/a.out index ef552a8838471abfd64363e38fe282f793afcb23..82903c4cc8e27f43af91ef18585110381b224d7c 100755 GIT binary patch literal 19772 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 literal 17740 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 JQcCC)`M;uPB1QlJ diff --git a/c/class_resolver.c b/c/class_resolver.c new file mode 100644 index 0000000..e4ee467 --- /dev/null +++ b/c/class_resolver.c @@ -0,0 +1,163 @@ +#include +#include +#include +#include + +#include "class_file.h" +#include "file.h" +#include "hash_table.h" +#include "malloc.h" +#include "class_resolver.h" +#include "string.h" +#include "debug_class_file.h" + +struct hash_table_entry * class_resolver_load_from_filenames(const char * filenames[], int length, int * hash_table_length) +{ + int class_hash_table_length = length * 2; + uint32_t class_hash_table_size = (sizeof (struct hash_table_entry)) * class_hash_table_length; + struct hash_table_entry * class_hash_table = malloc_class_arena(class_hash_table_size); + uint32_t class_entry_size = (sizeof (struct class_entry)) * length; + struct class_entry * class_entry = malloc_class_arena(class_entry_size); + + for (int i = 0; i < length; i++) { + uint32_t filename_length = string_length(filenames[i]); + const char * suffix = ".class"; + uint32_t suffix_length = string_length(suffix); + const char * filename_suffix = &filenames[i][filename_length - suffix_length]; + if (filename_length <= suffix_length || !string_equal(suffix, filename_suffix)) { + printf("invalid class filename: %s\n", filenames[i]); + continue; + } + uint32_t class_name_length = filename_length - suffix_length; + + printf("load class: %s\n", filenames[i]); + + uint8_t * buf = file_read(filenames[i]); + struct class_file * class_file = class_file_parse(buf); + free(buf); + + assert(class_file->magic == 0xcafebabe); + + class_entry[i].class_file = class_file; + + hash_table_add(class_hash_table_length, + class_hash_table, + (const uint8_t *)filenames[i], + class_name_length, + &class_entry[i]); + + // make hash table for interfaces + /* + if (class_file->interfaces_count != 0) { + uint32_t interfaces_hash_table_size = (sizeof (struct hash_table_entry)) * class_file->interfaces_count * 3 / 2; + struct hash_table_entry * interfaces_hash_table = malloc_class_arena(interfaces_hash_table_size); + for (int i = 0; i < class_file->interfaces_count; i++) { + + } + } + */ + // make hash table for fields + if (class_file->fields_count != 0) { + int fields_hash_table_length = class_file->fields_count * 2; + uint32_t fields_hash_table_size = (sizeof (struct hash_table_entry)) * fields_hash_table_length; + struct hash_table_entry * fields_hash_table = malloc_class_arena(fields_hash_table_size); + uint32_t field_entry_size = (sizeof (struct field_entry)) * length; + struct field_entry * field_entry = malloc_class_arena(field_entry_size); + for (int i = 0; i < class_file->fields_count; i++) { + u2 name_index = class_file->fields[i].name_index; + struct constant * name_constant = &class_file->constant_pool[name_index - 1]; + assert(name_constant->tag == CONSTANT_Utf8); + printf("hash table entry for field: "); + print_utf8_string(name_constant); + printf("\n"); + + field_entry[i].field_info = &class_file->fields[i]; + field_entry[i].value = 0; + + hash_table_add(fields_hash_table_length, + fields_hash_table, + name_constant->utf8.bytes, + name_constant->utf8.length, + (void *)&field_entry[i]); + } + + class_entry[i].fields.length = fields_hash_table_length; + class_entry[i].fields.entry = fields_hash_table; + } + + // make hash table for methods + if (class_file->methods_count != 0) { + int methods_hash_table_length = class_file->methods_count * 2; + uint32_t methods_hash_table_size = (sizeof (struct hash_table_entry)) * methods_hash_table_length; + struct hash_table_entry * methods_hash_table = malloc_class_arena(methods_hash_table_size); + for (int i = 0; i < class_file->methods_count; i++) { + u2 name_index = class_file->methods[i].name_index; + struct constant * name_constant = &class_file->constant_pool[name_index - 1]; + assert(name_constant->tag == CONSTANT_Utf8); + printf("hash table entry for method: "); + print_utf8_string(name_constant); + printf("\n"); + + hash_table_add(methods_hash_table_length, + methods_hash_table, + name_constant->utf8.bytes, + name_constant->utf8.length, + (void *)&class_file->methods[i]); + } + + class_entry[i].methods.length = methods_hash_table_length; + class_entry[i].methods.entry = methods_hash_table; + } + }; + + *hash_table_length = class_hash_table_length; + + return class_hash_table; +} + +struct class_entry * class_resolver_lookup_class(int class_hash_table_length, + struct hash_table_entry * class_hash_table, + const uint8_t * class_name, + int class_name_length) +{ + struct hash_table_entry * e = hash_table_find(class_hash_table_length, + class_hash_table, + class_name, + class_name_length); + assert(e != nullptr); + + return (struct class_entry *)e->value; +} + + +struct field_entry * class_resolver_lookup_field(struct class_entry * class_entry, + const uint8_t * field_name, + int field_name_length) +{ + int fields_hash_table_length = class_entry->fields.length; + struct hash_table_entry * fields_hash_table = class_entry->fields.entry; + + struct hash_table_entry * e = hash_table_find(fields_hash_table_length, + fields_hash_table, + field_name, + field_name_length); + assert(e != nullptr); + + return (struct field_entry *)e->value; +} + +struct method_info * class_resolver_lookup_method(struct class_entry * class_entry, + const uint8_t * method_name, + int method_name_length) +{ + int methods_hash_table_length = class_entry->methods.length; + struct hash_table_entry * methods_hash_table = class_entry->methods.entry; + + struct hash_table_entry * e = hash_table_find(methods_hash_table_length, + methods_hash_table, + method_name, + method_name_length); + assert(e != nullptr); + + return (struct method_info *)e->value; +} diff --git a/c/class_resolver.h b/c/class_resolver.h new file mode 100644 index 0000000..90805c7 --- /dev/null +++ b/c/class_resolver.h @@ -0,0 +1,42 @@ +#pragma once + +#include + +#include "class_file.h" +#include "hash_table.h" + +struct field_entry { + struct field_info * field_info; + uint32_t value; +}; + +struct class_entry { + struct class_file * class_file; + + struct { + int length; + struct hash_table_entry * entry; + } interfaces; + + struct { + int length; + struct hash_table_entry * entry; + } fields; + + struct { + int length; + struct hash_table_entry * entry; + } methods; +}; + +struct hash_table_entry * class_resolver_load_from_filenames(const char * filenames[], int length, int * hash_table_length); +struct class_entry * class_resolver_lookup_class(int class_hash_table_length, + struct hash_table_entry * class_hash_table, + const uint8_t * class_name, + int class_name_length); +struct method_info * class_resolver_lookup_method(struct class_entry * class_entry, + const uint8_t * method_name, + int method_name_length); +struct field_entry * class_resolver_lookup_field(struct class_entry * class_entry, + const uint8_t * field_name, + int field_name_length); diff --git a/c/debug_class_file.c b/c/debug_class_file.c index 21c1dfa..2f4eb2d 100644 --- a/c/debug_class_file.c +++ b/c/debug_class_file.c @@ -8,6 +8,13 @@ #include "decode.h" #include "debug_class_file.h" +void print_utf8_string(struct constant * constant) +{ + for (int i = 0; i < constant->utf8.length; i++) { + fputc(constant->utf8.bytes[i], stdout); + } +} + void print_constant(struct constant * constant) { switch (constant->tag) { @@ -60,10 +67,8 @@ void print_constant(struct constant * constant) 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); + print_utf8_string(constant); + printf("\n"); break; case CONSTANT_MethodHandle: printf("CONSTANT_MethodHandle reference_kind=%d reference_index=%d\n", diff --git a/c/debug_class_file.h b/c/debug_class_file.h index 895039d..4a543d7 100644 --- a/c/debug_class_file.h +++ b/c/debug_class_file.h @@ -2,6 +2,7 @@ #include "class_file.h" +void print_utf8_string(struct constant * constant); 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/execute.c b/c/execute.c index 8628d91..3d5bcee 100644 --- a/c/execute.c +++ b/c/execute.c @@ -3,6 +3,7 @@ #include "execute.h" #include "memory_allocator.h" #include "bswap.h" +#include "class_resolver.h" void op_aaload(struct vm * vm) { @@ -449,7 +450,40 @@ void op_getfield(struct vm * vm, uint32_t index) void op_getstatic(struct vm * vm, uint32_t index) { - assert(!"op_getstatic"); + struct constant * fieldref_constant = &vm->current_thread.current_class->constant_pool[index - 1]; + #ifdef DEBUG + assert(fieldref_constant->tag == CONSTANT_Fieldref); + #endif + struct constant * class_constant = &vm->current_thread.current_class->constant_pool[fieldref_constant->fieldref.class_index - 1]; + #ifdef DEBUG + assert(class_constant->tag == CONSTANT_Class); + #endif + struct constant * nameandtype_constant = &vm->current_thread.current_class->constant_pool[fieldref_constant->fieldref.name_and_type_index - 1]; + #ifdef DEBUG + assert(nameandtype_constant->tag == CONSTANT_NameAndType); + #endif + struct constant * class_name_constant = &vm->current_thread.current_class->constant_pool[class_constant->class.name_index - 1]; + #ifdef DEBUG + assert(class_name_constant->tag == CONSTANT_Utf8); + #endif + struct constant * field_name_constant = &vm->current_thread.current_class->constant_pool[nameandtype_constant->nameandtype.name_index - 1]; + #ifdef DEBUG + assert(field_name_constant->tag == CONSTANT_Utf8); + #endif + + struct class_entry * class_entry = class_resolver_lookup_class(vm->class_hash_table.length, + vm->class_hash_table.entry, + class_name_constant->utf8.bytes, + class_name_constant->utf8.length); + assert(class_entry != nullptr); + + struct field_entry * field_entry = class_resolver_lookup_field(class_entry, + field_name_constant->utf8.bytes, + field_name_constant->utf8.length); + assert(field_entry != nullptr); + + uint32_t value = field_entry->value; + operand_stack_push_u32(vm->current_frame, value); } void op_goto(struct vm * vm, int32_t branch) @@ -789,7 +823,39 @@ void op_invokespecial(struct vm * vm, uint32_t index) void op_invokestatic(struct vm * vm, uint32_t index) { - assert(!"op_invokestatic"); + struct constant * methodref_constant = &vm->current_thread.current_class->constant_pool[index - 1]; + #ifdef DEBUG + assert(methodref_constant->tag == CONSTANT_Methodref); + #endif + struct constant * class_constant = &vm->current_thread.current_class->constant_pool[methodref_constant->methodref.class_index - 1]; + #ifdef DEBUG + assert(class_constant->tag == CONSTANT_Class); + #endif + struct constant * nameandtype_constant = &vm->current_thread.current_class->constant_pool[methodref_constant->methodref.name_and_type_index - 1]; + #ifdef DEBUG + assert(nameandtype_constant->tag == CONSTANT_NameAndType); + #endif + struct constant * class_name_constant = &vm->current_thread.current_class->constant_pool[class_constant->class.name_index - 1]; + #ifdef DEBUG + assert(class_name_constant->tag == CONSTANT_Utf8); + #endif + struct constant * method_name_constant = &vm->current_thread.current_class->constant_pool[nameandtype_constant->nameandtype.name_index - 1]; + #ifdef DEBUG + assert(method_name_constant->tag == CONSTANT_Utf8); + #endif + + struct class_entry * class_entry = class_resolver_lookup_class(vm->class_hash_table.length, + vm->class_hash_table.entry, + class_name_constant->utf8.bytes, + class_name_constant->utf8.length); + assert(class_entry != nullptr); + + struct method_info * method_info = class_resolver_lookup_method(class_entry, + method_name_constant->utf8.bytes, + method_name_constant->utf8.length); + assert(method_info != nullptr); + + vm_static_method_call(vm, class_entry->class_file, method_info); } void op_invokevirtual(struct vm * vm, uint32_t index) @@ -815,6 +881,13 @@ void op_irem(struct vm * vm) void op_ireturn(struct vm * vm) { + /* Prior to pushing value onto the operand stack of the frame of the invoker, + it may have to be converted. If the return type of the invoked method was + byte, char, or short, then value is converted from int to the return type + as if by execution of i2b, i2c, or i2s, respectively. If the return type + of the invoked method was boolean, then value is narrowed from int to + boolean by taking the bitwise AND of value and 1. */ + uint32_t value = operand_stack_pop_u32(vm->current_frame); printf("return %d\n", value); } diff --git a/c/frame.c b/c/frame.c index 8fbf809..03e2eda 100644 --- a/c/frame.c +++ b/c/frame.c @@ -3,12 +3,13 @@ #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" +#include "class_resolver.h" +#include "string.h" struct frame * stack_push_frame(struct stack * stack, int num_frames) { @@ -66,28 +67,70 @@ int find_code_name_index(struct class_file * class_file) return 0; } -void vm_execute(struct vm * vm) +static int descriptor_nargs(struct constant * descriptor_constant) { - 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]); + assert(descriptor_constant->tag == CONSTANT_Utf8); + assert(descriptor_constant->utf8.length >= 2); + assert(descriptor_constant->utf8.bytes[0] == '('); - int code_name_index = find_code_name_index(vm->current_thread.current_class); + int i = 1; + int nargs = 0; + while (i < descriptor_constant->utf8.length) { + if (descriptor_constant->utf8.bytes[i] == ')') + break; + nargs += 1; + i += 1; + } + assert(i + 2 == descriptor_constant->utf8.length); + + return nargs; +} + +void vm_static_method_call(struct vm * vm, struct class_file * class_file, struct method_info * method_info) +{ + /* If the method is not native, the nargs argument values are popped from the + operand stack. A new frame is created on the Java Virtual Machine stack for + the method being invoked. The nargs argument values are consecutively made + the values of local variables of the new frame, with arg1 in local variable + 0 (or, if arg1 is of type long or double, in local variables 0 and 1) and + so on. The new frame is then made current, and the Java Virtual Machine pc + is set to the opcode of the first instruction of the method to be + invoked. Execution continues with the first instruction of the method. + */ + + int code_name_index = find_code_name_index(class_file); 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); + method_info->attributes_count, + method_info->attributes); assert(code != nullptr); + struct frame * old_frame = vm->current_frame; + vm->current_frame = stack_push_frame(&vm->frame_stack, 1); + vm->current_frame->code = code; 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; + struct constant * descriptor_constant = &class_file->constant_pool[method_info->descriptor_index - 1]; + int nargs = descriptor_nargs(descriptor_constant); + printf("nargs %d\n", nargs); + for (int i = 0; i < nargs; i++) { + uint32_t value = operand_stack_pop_u32(old_frame); + vm->current_frame->local_variable[nargs - i - 1] = value; + } + vm->current_thread.pc = 0; + vm->current_thread.current_class = class_file; + vm->current_thread.current_method = method_info; +} + +void vm_execute(struct vm * vm) +{ + printf("execute:\n"); + while (true) { printf("[ "); for (int i = 5; i > 0; i--) { @@ -102,34 +145,47 @@ void vm_execute(struct vm * vm) printf("%10d ", value); } printf("]\n"); - decode_print_instruction(code->code, vm->current_thread.pc); + decode_print_instruction(vm->current_frame->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); + uint32_t next_pc = decode_execute_instruction(vm, vm->current_frame->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) { + if (vm->current_thread.pc >= vm->current_frame->code->code_length) { printf("terminate\n"); break; } } } -int main(int argc, char * argv[]) +int main(int argc, const char * argv[]) { - assert(argc >= 2); - uint8_t * buf = file_read(argv[1]); - struct class_file * class_file = class_file_parse(buf); + assert(argc >= 3); - assert(class_file->magic == 0xcafebabe); - assert(class_file->methods_count >= 1); + const char * main_class = argv[1]; + + const char ** class_filenames = &argv[2]; + int num_class_filenames = argc - 2; + + int class_hash_table_length; + struct hash_table_entry * class_hash_table = class_resolver_load_from_filenames(class_filenames, num_class_filenames, &class_hash_table_length); + + struct class_entry * class_entry = class_resolver_lookup_class(class_hash_table_length, + class_hash_table, + (const uint8_t *)main_class, + string_length(main_class)); + + const char * method_name = "test"; + int method_name_length = string_length(method_name); + struct method_info * method_info = class_resolver_lookup_method(class_entry, + (const uint8_t *)method_name, + method_name_length); 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.class_hash_table.entry = class_hash_table; + vm.class_hash_table.length = class_hash_table_length; vm.frame_stack.ix = 0; vm.frame_stack.capacity = 1024; @@ -141,5 +197,6 @@ int main(int argc, char * argv[]) uint32_t data[vm.data_stack.capacity]; vm.data_stack.data = data; + vm_static_method_call(&vm, class_entry->class_file, method_info); vm_execute(&vm); } diff --git a/c/frame.h b/c/frame.h index 8f2dc56..92ebf83 100644 --- a/c/frame.h +++ b/c/frame.h @@ -5,12 +5,10 @@ #include "class_file.h" struct frame { + struct Code_attribute * code; uint32_t * local_variable; uint32_t * operand_stack; uint16_t operand_stack_ix; - #ifdef DEBUG - uint32_t operand_stack_capacity; - #endif }; struct thread { @@ -33,6 +31,10 @@ struct vm { struct stack data_stack; struct thread current_thread; struct frame * current_frame; + struct { + int length; + struct hash_table_entry * entry; + } class_hash_table; }; static inline void operand_stack_push_u32(struct frame * frame, uint32_t value) @@ -55,3 +57,5 @@ static inline void operand_stack_dup_u32(struct frame * frame) frame->operand_stack[frame->operand_stack_ix] = value; frame->operand_stack_ix++; } + +void vm_static_method_call(struct vm * vm, struct class_file * class_file, struct method_info * method_info); diff --git a/c/hash_table.c b/c/hash_table.c index 3f77d0c..9c871df 100644 --- a/c/hash_table.c +++ b/c/hash_table.c @@ -1,4 +1,5 @@ -#include +#include "malloc.h" +#include "hash_table.h" static uint32_t fnv_1(const uint8_t * buf, int length) { @@ -15,31 +16,17 @@ static uint32_t fnv_1(const uint8_t * buf, int length) 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) + struct hash_table_entry * entry) { 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) @@ -51,12 +38,9 @@ void hash_table_add(int hash_table_length, 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->next = malloc_class_arena((sizeof (struct hash_table_entry))); e = e->next; } @@ -74,195 +58,19 @@ static inline bool key_equal(const uint8_t * a, const uint8_t * b, int length) 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) { + while (e != nullptr && 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/hash_table.h b/c/hash_table.h new file mode 100644 index 0000000..e316a4e --- /dev/null +++ b/c/hash_table.h @@ -0,0 +1,24 @@ +#pragma once + +#include + +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); + +void hash_table_add(int hash_table_length, + struct hash_table_entry * entry, + const uint8_t * key, + int key_length, + void * value); + +struct hash_table_entry * hash_table_find(int hash_table_length, + struct hash_table_entry * entry, + const uint8_t * key, + int key_length); diff --git a/c/malloc.c b/c/malloc.c index 2ff6149..cafd2c5 100644 --- a/c/malloc.c +++ b/c/malloc.c @@ -1,5 +1,3 @@ -#include - #include "malloc.h" struct arena { diff --git a/c/malloc.h b/c/malloc.h index fd07794..c947ec3 100644 --- a/c/malloc.h +++ b/c/malloc.h @@ -1,3 +1,5 @@ #pragma once +#include + void * malloc_class_arena(uint32_t size); diff --git a/c/string.h b/c/string.h new file mode 100644 index 0000000..2da8d26 --- /dev/null +++ b/c/string.h @@ -0,0 +1,21 @@ +#pragma once + +static inline int string_length(const char * s) +{ + const char * si = s; + while (*si != 0) { + si++; + } + return si - s; +} + +static inline bool string_equal(const char * a, const char * b) +{ + int i = 0; + while (a[i] != 0) { + if (a[i] != b[i]) + return false; + i += 1; + } + return b[i] == 0; +} diff --git a/c/test_hash_table.c b/c/test_hash_table.c new file mode 100644 index 0000000..e22bba9 --- /dev/null +++ b/c/test_hash_table.c @@ -0,0 +1,175 @@ +#include +#include +#include + +#include "hash_table.h" + +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])); + +static uint32_t _strlen(const char * s) +{ + const char * si = s; + while (*si != 0) { + si++; + } + return si - s; +} + +int main() +{ + int hash_table_length = 128 * 2; + struct hash_table_entry entry[hash_table_length]; + + hash_table_init(hash_table_length, + entry); + + for (int i = 0; i < names_length; i++) { + hash_table_add(hash_table_length, + entry, + (const uint8_t *)names[i], + _strlen(names[i]), + (void *)(ptrdiff_t)(i * 2)); + } + + for (int j = 0; j < names_length; j++) { + struct hash_table_entry * e = hash_table_find(hash_table_length, + entry, + (const uint8_t *)names[j], + _strlen(names[j])); + if (e < entry || e >= entry + hash_table_length) { + printf("collision %s\n", e->key); + } + assert(e != nullptr); + printf("%s %d\n", e->key, (int)e->value); + } +} diff --git a/p/DataTest.java b/p/DataTest.java new file mode 100644 index 0000000..d1a893a --- /dev/null +++ b/p/DataTest.java @@ -0,0 +1,13 @@ +package p; + +import p.Data; + +class DataTest { + static int test() { + return test2(6, 3) * 5; + } + + static int test2(int a, int b) { + return a - b; + } +}