gc: automatically run garbage collection if memory allocation fails

This commit is contained in:
Zack Buhman 2025-01-09 20:12:36 -06:00
parent dd4795c46b
commit fb63ad066c
12 changed files with 159 additions and 131 deletions

View File

@ -3,30 +3,35 @@
#include "debug.h"
#include "find_attribute.h"
#include "memory_allocator.h"
#include "native_types_allocate.h"
struct backtrace * backtrace_allocate(struct vm * vm)
struct objectref * backtrace_allocate(struct vm * vm)
{
struct class_entry * object_class_entry = class_resolver_lookup_class(vm->class_hash_table.length,
vm->class_hash_table.entry,
(const uint8_t *)"java/lang/Object",
16);
debugf("object class entry: %p\n", object_class_entry);
struct class_entry * class_entry = class_resolver_lookup_class(vm->class_hash_table.length,
vm->class_hash_table.entry,
(const uint8_t *)"java/lang/Backtrace",
19);
debugf("backtrace class entry: %p\n", class_entry);
int num_fields = (sizeof (struct backtrace)) / (sizeof (void *));
struct objectref * objectref = obj_allocate(num_fields);
objectref->class_entry = object_class_entry;
struct backtrace * backtrace = (struct backtrace *)&objectref->aref[0];
backtrace->num_entries = vm->frame_stack.ix;
int backtrace_entries_size = (sizeof (struct backtrace_entry)) * backtrace->num_entries;
backtrace->entry = memory_allocate(backtrace_entries_size);
assert(class_entry->instance_fields_count >= 1);
struct objectref * objectref = obj_allocate(vm, class_entry->instance_fields_count);
objectref->class_entry = class_entry;
for (int i = (vm->frame_stack.ix - 1); i >= 0; i--) {
int num_entries = vm->frame_stack.ix;
struct arrayref * arrayref = prim_array_allocate(vm, (sizeof (struct backtrace_entry)), num_entries);
arrayref->length = num_entries;
arrayref->class_entry = nullptr;
struct backtrace_entry * backtrace_entry = (struct backtrace_entry *)&arrayref->u32[0];
objectref->aref[0] = arrayref;
for (int i = (num_entries - 1); i >= 0; i--) {
struct frame * frame = &vm->frame_stack.frame[i];
backtrace->entry[i].class_file = frame->class_entry->class_file;
backtrace->entry[i].method_info = frame->method_info;
backtrace->entry[i].pc = frame->pc;
backtrace_entry[i].class_file = frame->class_entry->class_file;
backtrace_entry[i].method_info = frame->method_info;
backtrace_entry[i].pc = frame->pc;
}
return backtrace;
return objectref;
}
static int get_line_number(struct class_file * class_file, struct method_info * method_info, int pc)
@ -57,20 +62,25 @@ static int get_line_number(struct class_file * class_file, struct method_info *
return line_number;
}
void backtrace_print(struct backtrace * backtrace)
void backtrace_print(struct objectref * objectref)
{
debugf("backtrace objectref class entry: %p\n", objectref->class_entry);
struct arrayref * arrayref = objectref->aref[0];
struct backtrace_entry * backtrace_entry = (struct backtrace_entry *)&arrayref->u32[0];
prints("backtrace:\n");
for (int i = (backtrace->num_entries - 1); i >= 0; i--) {
struct backtrace_entry * backtrace_entry = &backtrace->entry[i];
for (int i = (arrayref->length - 1); i >= 0; i--) {
struct backtrace_entry * entry = &backtrace_entry[i];
prints(" class: ");
print__class_file__class_name(backtrace_entry->class_file);
print__class_file__class_name(entry->class_file);
prints(" method: ");
print__method_info__method_name(backtrace_entry->class_file, backtrace_entry->method_info);
print__method_info__method_name(entry->class_file, entry->method_info);
printc('\n');
printf(" pc: %3d ", backtrace_entry->pc);
int line_number = get_line_number(backtrace_entry->class_file,
backtrace_entry->method_info,
backtrace_entry->pc);
printf(" pc: %3d ", entry->pc);
int line_number = get_line_number(entry->class_file,
entry->method_info,
entry->pc);
printf(" line_number: %3d\n", line_number);
}
}

View File

@ -8,11 +8,6 @@ struct backtrace_entry {
int pc;
};
struct backtrace {
int num_entries;
struct backtrace_entry * entry;
};
struct objectref * backtrace_allocate(struct vm * vm);
struct backtrace * backtrace_allocate(struct vm * vm);
void backtrace_print(struct backtrace * backtrace);
void backtrace_print(struct objectref * objectref);

View File

@ -13,6 +13,8 @@
#include "fatal.h"
#include "parse_type.h"
#include "find_attribute.h"
#include "frame.h"
#include "native_types_allocate.h"
static int field_info_field_size(struct class_file * class_file, struct field_info * field_info)
{
@ -587,54 +589,6 @@ struct method_entry class_resolver_lookup_method_from_method_name_method_descrip
}
}
struct objectref * class_resolver_lookup_string(int class_hash_table_length,
struct hash_table_entry * class_hash_table,
struct class_entry * class_entry,
const int string_index)
{
debugf("class_resolver_lookup_string: %d\n", string_index);
if (class_entry->attribute_entry[string_index - 1].string_objectref != nullptr) {
debugf("class_resolver_lookup_string: [cached]\n");
return class_entry->attribute_entry[string_index - 1].string_objectref;
}
struct constant * string_constant = &class_entry->class_file->constant_pool[string_index - 1];
assert(string_constant->tag == CONSTANT_String);
struct constant * utf8_constant = &class_entry->class_file->constant_pool[string_constant->string.string_index - 1];
assert(utf8_constant->tag == CONSTANT_Utf8);
struct class_entry * string_class_entry = class_resolver_lookup_class(class_hash_table_length,
class_hash_table,
(const uint8_t *)"java/lang/String",
16);
debugf("string class entry: %p\n", string_class_entry);
int32_t count = utf8_constant->utf8.length;
struct arrayref * arrayref = prim_array_allocate(1, count);
assert(arrayref != nullptr);
arrayref->class_entry = nullptr; // byte[]
arrayref->length = utf8_constant->utf8.length;
for (int i = 0; i < utf8_constant->utf8.length; i++) {
arrayref->u8[i] = utf8_constant->utf8.bytes[i];
}
assert(string_class_entry != nullptr);
int fields_count = string_class_entry->instance_fields_count;
struct objectref * objectref = obj_allocate(fields_count);
assert(objectref != nullptr);
objectref->class_entry = string_class_entry;
for (int i = 0; i < fields_count; i++) {
objectref->oref[i] = nullptr;
}
objectref->aref[0] = arrayref;
// cache the result
class_entry->attribute_entry[string_index - 1].string_objectref = objectref;
return objectref;
}
bool class_resolver_instanceof(int class_hash_table_length,
struct hash_table_entry * class_hash_table,
struct class_entry * origin_class_entry,

View File

@ -86,11 +86,6 @@ struct field_entry * class_resolver_lookup_field_from_fieldref_index(int fields_
struct class_entry * class_entry,
int fieldref_index);
struct objectref * class_resolver_lookup_string(int class_hash_table_length,
struct hash_table_entry * class_hash_table,
struct class_entry * class_entry,
const int string_index);
bool class_resolver_instanceof(int class_hash_table_length,
struct hash_table_entry * class_hash_table,
struct class_entry * origin_class_entry,

View File

@ -2,12 +2,13 @@
#include "memory_allocator.h"
#include "bswap.h"
#include "class_resolver.h"
#include "execute_helper.h"
#include "printf.h"
#include "field_size.h"
#include "debug.h"
#include "native_types.h"
#include "native_types_allocate.h"
#include "parse_type.h"
#include "execute_helper.h"
void op_aaload(struct vm * vm)
{
@ -71,7 +72,7 @@ void op_anewarray(struct vm * vm, uint32_t index)
index);
int32_t count = operand_stack_pop_u32(vm->current_frame);
struct arrayref * arrayref = ref_array_allocate(count);
struct arrayref * arrayref = ref_array_allocate(vm, count);
assert(arrayref != nullptr);
arrayref->length = count;
arrayref->class_entry = class_entry;
@ -1424,8 +1425,7 @@ void op_ldc(struct vm * vm, uint32_t index)
int32_t value = constant->integer.bytes;
operand_stack_push_u32(vm->current_frame, value);
} else if (constant->tag == CONSTANT_String) {
struct objectref * objectref = class_resolver_lookup_string(vm->class_hash_table.length,
vm->class_hash_table.entry,
struct objectref * objectref = class_resolver_lookup_string(vm,
vm->current_frame->class_entry,
index);
operand_stack_push_ref(vm->current_frame, objectref);
@ -1451,8 +1451,7 @@ void op_ldc_w(struct vm * vm, uint32_t index)
int32_t value = constant->integer.bytes;
operand_stack_push_u32(vm->current_frame, value);
} else if (constant->tag == CONSTANT_String) {
struct objectref * objectref = class_resolver_lookup_string(vm->class_hash_table.length,
vm->class_hash_table.entry,
struct objectref * objectref = class_resolver_lookup_string(vm,
vm->current_frame->class_entry,
index);
operand_stack_push_ref(vm->current_frame, objectref);
@ -1660,10 +1659,10 @@ static struct arrayref * _multiarray(struct vm * vm, int32_t * dims, int num_dim
int32_t element_size;
if (*type == 'L' || *type == '[') {
element_size = (sizeof (void *));
arrayref = ref_array_allocate(count);
arrayref = ref_array_allocate(vm, count);
} else {
element_size = field_size_array(*type);
arrayref = prim_array_allocate(element_size, count);
arrayref = prim_array_allocate(vm, element_size, count);
}
assert(arrayref != nullptr);
arrayref->length = count;
@ -1733,7 +1732,7 @@ void op_new(struct vm * vm, uint32_t index)
reference to the instance, is pushed onto the operand stack. */
int fields_count = class_entry->instance_fields_count;
struct objectref * objectref = obj_allocate(fields_count);
struct objectref * objectref = obj_allocate(vm, fields_count);
assert(objectref != nullptr);
objectref->class_entry = class_entry;
for (int i = 0; i < fields_count; i++) {
@ -1748,7 +1747,7 @@ void op_newarray(struct vm * vm, uint32_t atype)
{
int32_t count = operand_stack_pop_u32(vm->current_frame);
int32_t element_size = array_element_size(atype);
struct arrayref * arrayref = prim_array_allocate(element_size, count);
struct arrayref * arrayref = prim_array_allocate(vm, element_size, count);
assert(arrayref != nullptr);
arrayref->length = count;
arrayref->class_entry = nullptr;

View File

@ -1,3 +1,50 @@
struct objectref * class_resolver_lookup_string(struct vm * vm,
struct class_entry * class_entry,
const int string_index)
{
debugf("class_resolver_lookup_string: %d\n", string_index);
if (class_entry->attribute_entry[string_index - 1].string_objectref != nullptr) {
debugf("class_resolver_lookup_string: [cached]\n");
return class_entry->attribute_entry[string_index - 1].string_objectref;
}
struct constant * string_constant = &class_entry->class_file->constant_pool[string_index - 1];
assert(string_constant->tag == CONSTANT_String);
struct constant * utf8_constant = &class_entry->class_file->constant_pool[string_constant->string.string_index - 1];
assert(utf8_constant->tag == CONSTANT_Utf8);
struct class_entry * string_class_entry = class_resolver_lookup_class(vm->class_hash_table.length,
vm->class_hash_table.entry,
(const uint8_t *)"java/lang/String",
16);
debugf("string class entry: %p\n", string_class_entry);
int32_t count = utf8_constant->utf8.length;
struct arrayref * arrayref = prim_array_allocate(vm, 1, count);
assert(arrayref != nullptr);
arrayref->class_entry = nullptr; // byte[]
arrayref->length = utf8_constant->utf8.length;
for (int i = 0; i < utf8_constant->utf8.length; i++) {
arrayref->u8[i] = utf8_constant->utf8.bytes[i];
}
assert(string_class_entry != nullptr);
int fields_count = string_class_entry->instance_fields_count;
struct objectref * objectref = obj_allocate(vm, fields_count);
assert(objectref != nullptr);
objectref->class_entry = string_class_entry;
for (int i = 0; i < fields_count; i++) {
objectref->oref[i] = nullptr;
}
objectref->aref[0] = arrayref;
// cache the result
class_entry->attribute_entry[string_index - 1].string_objectref = objectref;
return objectref;
}
static inline void class_entry_field_entry_from_constant_index(struct vm * vm,
int32_t index,
struct class_entry ** class_entry,

View File

@ -548,7 +548,7 @@ void vm_exception(struct vm * vm, struct objectref * objectref)
}
}
assert(objectref->oref[0] != 0);
backtrace_print((struct backtrace *)objectref->oref[0]);
backtrace_print(objectref->oref[0]);
}
static void print_vm_stack(struct vm * vm)

6
c/gc.c
View File

@ -157,3 +157,9 @@ void gc_sweep()
{
memory_iterate_allocated(sweep_address);
}
void gc_run(struct vm * vm)
{
gc_mark(vm);
gc_sweep();
}

1
c/gc.h
View File

@ -4,3 +4,4 @@
void gc_mark(struct vm * vm);
void gc_sweep();
void gc_run(struct vm * vm);

View File

@ -85,36 +85,3 @@ static inline int array_element_size(int atype)
break;
}
}
static inline struct arrayref * prim_array_allocate(int element_size, int count)
{
int32_t size = count * element_size + (sizeof (struct arrayref));
struct arrayref * arrayref = memory_allocate(size);
if (arrayref != nullptr) {
arrayref->tag.type = TAG_TYPE_PRIM_ARRAY;
arrayref->tag.mark = 0;
}
return arrayref;
}
static inline struct arrayref * ref_array_allocate(int count)
{
int32_t size = count * (sizeof (void *)) + (sizeof (struct arrayref));
struct arrayref * arrayref = memory_allocate(size);
if (arrayref != nullptr) {
arrayref->tag.type = TAG_TYPE_REF_ARRAY;
arrayref->tag.mark = 0;
}
return arrayref;
}
static inline struct objectref * obj_allocate(int num_fields)
{
int32_t size = num_fields * (sizeof (void *)) + (sizeof (struct objectref));
struct objectref * objectref = memory_allocate(size);
if (objectref != nullptr) {
objectref->tag.type = TAG_TYPE_OBJECT;
objectref->tag.mark = 0;
}
return objectref;
}

48
c/native_types_allocate.h Normal file
View File

@ -0,0 +1,48 @@
#pragma once
#include "native_types.h"
#include "frame.h"
#include "gc.h"
static inline void * gc_memory_allocate(struct vm * vm, int size)
{
void * mem = memory_allocate(size);
if (mem == nullptr) {
gc_run(vm);
mem = memory_allocate(size);
}
return mem;
}
static inline struct arrayref * prim_array_allocate(struct vm * vm, int element_size, int count)
{
int32_t size = count * element_size + (sizeof (struct arrayref));
struct arrayref * arrayref = gc_memory_allocate(vm, size);
if (arrayref != nullptr) {
arrayref->tag.type = TAG_TYPE_PRIM_ARRAY;
arrayref->tag.mark = 0;
}
return arrayref;
}
static inline struct arrayref * ref_array_allocate(struct vm * vm, int count)
{
int32_t size = count * (sizeof (void *)) + (sizeof (struct arrayref));
struct arrayref * arrayref = gc_memory_allocate(vm, size);
if (arrayref != nullptr) {
arrayref->tag.type = TAG_TYPE_REF_ARRAY;
arrayref->tag.mark = 0;
}
return arrayref;
}
static inline struct objectref * obj_allocate(struct vm * vm, int num_fields)
{
int32_t size = num_fields * (sizeof (void *)) + (sizeof (struct objectref));
struct objectref * objectref = gc_memory_allocate(vm, size);
if (objectref != nullptr) {
objectref->tag.type = TAG_TYPE_OBJECT;
objectref->tag.mark = 0;
}
return objectref;
}

View File

@ -0,0 +1,6 @@
class Backtrace {
int[] backtrace_entry; // is actually (struct backtrace_entry)
private Backtrace() {
}
}