diff --git a/c/backtrace.c b/c/backtrace.c index 7aa73b8..57011e0 100644 --- a/c/backtrace.c +++ b/c/backtrace.c @@ -6,6 +6,7 @@ struct backtrace * backtrace_allocate(struct vm * vm) { + assert(false); // backtrace must become an objectref struct backtrace * backtrace = memory_allocate((sizeof (struct backtrace))); backtrace->num_entries = vm->frame_stack.ix; int backtrace_entries_size = (sizeof (struct backtrace_entry)) * backtrace->num_entries; diff --git a/c/class_resolver.c b/c/class_resolver.c index dea31a5..56b7322 100644 --- a/c/class_resolver.c +++ b/c/class_resolver.c @@ -151,6 +151,7 @@ static int32_t class_resolver_create_fields_hash_table(int class_hash_table_leng class_entry->fields.length = fields_hash_table_length; class_entry->fields.entry = fields_hash_table; class_entry->instance_fields_count = instance_index; + class_entry->static_fields_count = static_index; return static_index; } diff --git a/c/class_resolver.h b/c/class_resolver.h index 48c8e36..bd798e3 100644 --- a/c/class_resolver.h +++ b/c/class_resolver.h @@ -37,6 +37,7 @@ struct class_entry { struct class_file * class_file; enum initialization_state initialization_state; union attribute_entry * attribute_entry; + int32_t static_fields_count; int32_t * static_fields; int32_t instance_fields_count; diff --git a/c/gc.c b/c/gc.c new file mode 100644 index 0000000..86a65f9 --- /dev/null +++ b/c/gc.c @@ -0,0 +1,119 @@ +#include "frame.h" +#include "memory_allocator.h" + +static void walk_address(void * address); + +static void walk_object(struct objectref * objectref) +{ + if (arrayref->tag->mark != 0) + return; + objectref->tag->mark = 1; + + for (int i = 0; i < objectref->class_entry->instance_fields_count; i++) { + void * address = objectref->aref[i]; + walk_address(address); + } +} + +static void walk_ref_array(struct arrayref * arrayref) +{ + if (arrayref->tag->mark != 0) + return; + arrayref->tag->mark = 1; + + if (arrayref->class_entry == nullptr) { + // this is an array of arrayrefs + for (int i = 0; i < arrayref->length; i++) { + if (arrayref->aref[i] != nullptr) { + walk_ref_array(arrayref->aref[i]); + } + } + } else { + // this is an array of objectrefs + for (int i = 0; i < arrayref->length; i++) { + if (arrayref->oref[i] != nullptr) { + walk_object(arrayref->oref[i]); + } + } + } +} + +static void walk_address(void * address) +{ + if (address == nullptr) + return; + + if (!memory_is_allocated(address)) + return; + + struct tag * tag = (struct tag *)address; + if (tag->type == TAG_TYPE_OBJECT) { + walk_object((struct objectref *)address); + } + if (tag->type == TAG_TYPE_REF_ARRAY) { + walk_ref_array((struct arrayref *)address); + } +} + +static void walk_frame(struct frame * frame) +{ + int num_local_variables = frame->code_attribute->max_locals; + int num_stack_variables = frame->operand_stack_ix; + + for (int i = 0; i < num_local_variables; i++) { + void * address = frame->local_variable[i]; + walk_address(address); + } + + for (int i = 0; i < num_stack_variables; i++) { + void * address = frame->operand_stack[i]; + walk_address(address); + } +} + +static void walk_static_fields(struct class_entry * class_entry) +{ + for (int i = 0; i < class_entry->static_fields_count; i++) { + void * address = class_entry->static_fields[i]; + walk_address(address); + } +} + +static void walk_class_hash_table_entry(struct hash_table_entry * entry) +{ + if (entry->key == nullptr) + return; + + struct class_entry * class_entry = (struct class_entry *)e->value; + assert(class_entry != nullptr); + walk_static_fiends(class_entry); + + if (entry->next != nullptr) + walk_class_hash_table_entry(entry->next); +} + +static void walk_class_hash_table(int length, struct hash_table_entry * entry) +{ + for (int i = 0; i < length; i++) + walk_class_hash_table_entry(&entry[i]); +} + +static void walk_vm(struct vm * vm) +{ + walk_class_hash_table(vm->class_hash_table.length, + vm->class_hash_table.entry); + + for (int i = 0; i < vm->frame_stack->ix; i++) { + walk_frame(&vm->frame_stack->frame[i]); + } +} + +void gc_mark(struct vm * vm) +{ + walk_vm(vm); +} + +void gc_sweep() +{ + +} diff --git a/c/gc.h b/c/gc.h new file mode 100644 index 0000000..af070f6 --- /dev/null +++ b/c/gc.h @@ -0,0 +1,5 @@ +#pragma once + +#include "frame.h" + +void gc_mark(struct vm * vm); diff --git a/c/memory_allocator.c b/c/memory_allocator.c index ef34cf0..a37c6ae 100644 --- a/c/memory_allocator.c +++ b/c/memory_allocator.c @@ -72,6 +72,7 @@ void memory_free(void * p) assert(buf >= memory); uint32_t address_index = buf - memory; assert(address_index < (sizeof (memory))); + assert((address_index & (~(block_size - 1))) != address_index); uint32_t free_list_index = address_index >> block_power; assert((free_list[free_list_index] & START) != 0); diff --git a/c/memory_allocator.h b/c/memory_allocator.h index 2ace29e..de455df 100644 --- a/c/memory_allocator.h +++ b/c/memory_allocator.h @@ -1,5 +1,8 @@ +#pragma once + #include void memory_reset_free_list(); void * memory_allocate(uint32_t size); void memory_free(void * p); +bool memory_is_allocated(void * p); diff --git a/c/native_types.h b/c/native_types.h index 6a60e26..c7260ea 100644 --- a/c/native_types.h +++ b/c/native_types.h @@ -5,10 +5,22 @@ #include "class_resolver.h" -struct object_arrayref; +enum tag_type { + TAG_TYPE_OBJECT = -30741, + TAG_TYPE_REF_ARRAY = 23240, + TAG_TYPE_PRIM_ARRAY = -5251, +}; + +struct tag { + int8_t mark; + int8_t _res; + int16_t type; +}; + +static_assert((sizeof (struct tag)) == 4); struct objectref { - int32_t _res; + struct tag tag; struct class_entry * class_entry; union { struct objectref * oref[0]; @@ -17,11 +29,12 @@ struct objectref { }; }; -static_assert((sizeof (struct objectref)) == 8); +static_assert((sizeof (struct objectref)) == 12); struct arrayref { - int32_t length; // length position must match primitive_arrayref + struct tag tag; struct class_entry * class_entry; + int32_t length; union { // object array: struct objectref * oref[0]; @@ -34,7 +47,7 @@ struct arrayref { }; }; -static_assert((sizeof (struct arrayref)) == 8); +static_assert((sizeof (struct arrayref)) == 12); enum ARRAY_TYPE { T_BOOLEAN = 4, // 1 byte