reachability analysis implemented

This commit is contained in:
Thakee Nathees 2021-05-01 15:43:39 +05:30
parent 8f52c6d54e
commit d901b7fc7e
6 changed files with 190 additions and 35 deletions

View File

@ -1804,11 +1804,11 @@ Script* compileSource(MSVM* vm, const char* path) {
void compilerMarkObjects(Compiler* compiler, MSVM* vm) {
// Mark the script which is currently being compiled.
markObject(&compiler->script->_super, vm);
grayObject(&compiler->script->_super, vm);
// Mark the string literals (they haven't added to the script's literal
// buffer yet).
markValue(compiler->parser.current.value, vm);
markValue(compiler->parser.previous.value, vm);
markValue(compiler->parser.next.value, vm);
grayValue(compiler->parser.current.value, vm);
grayValue(compiler->parser.previous.value, vm);
grayValue(compiler->parser.next.value, vm);
}

View File

@ -273,7 +273,7 @@ void initializeCore(MSVM* vm) {
void markCoreObjects(MSVM* vm) {
for (int i = 0; i < builtins_count; i++) {
markObject(&builtins[i].fn->_super, vm);
grayObject(&builtins[i].fn->_super, vm);
}
}

151
src/var.c
View File

@ -45,26 +45,155 @@ void varInitObject(Object* self, MSVM* vm, ObjectType type) {
vm->first = self;
}
void markObject(Object* self, MSVM* vm) {
void grayObject(Object* self, MSVM* vm) {
if (self == NULL || self->is_marked) return;
self->is_marked = true;
// Add the object to the VM's gray_list so that we can recursively mark
// it's referenced objects later.
if (vm->marked_list_count >= vm->marked_list_capacity) {
vm->marked_list_capacity *= 2;
vm->marked_list = (Object**)vm->config.realloc_fn(
vm->marked_list,
vm->marked_list_capacity * sizeof(Object*),
if (vm->gray_list_count >= vm->gray_list_capacity) {
vm->gray_list_capacity *= 2;
vm->gray_list = (Object**)vm->config.realloc_fn(
vm->gray_list,
vm->gray_list_capacity * sizeof(Object*),
vm->config.user_data);
}
vm->marked_list[vm->marked_list_count++] = self;
vm->gray_list[vm->gray_list_count++] = self;
}
void markValue(Var self, MSVM* vm) {
void grayValue(Var self, MSVM* vm) {
if (!IS_OBJ(self)) return;
markObject(AS_OBJ(self), vm);
grayObject(AS_OBJ(self), vm);
}
void grayVarBuffer(VarBuffer* self, MSVM* vm) {
for (int i = 0; i < self->count; i++) {
grayValue(self->data[i], vm);
}
}
void grayStringBuffer(StringBuffer* self, MSVM* vm) {
for (int i = 0; i < self->count; i++) {
grayObject((Object*)self->data[i], vm);
}
}
void grayFunctionBuffer(FunctionBuffer* self, MSVM* vm) {
for (int i = 0; i < self->count; i++) {
grayObject((Object*)self->data[i], vm);
}
}
void grayNameTable(NameTable* self, MSVM* vm) {
for (int i = 0; i < self->count; i++) {
grayObject((Object*)self->data[i], vm);
}
}
static void blackenObject(Object* obj, MSVM* vm) {
// TODO: trace here.
switch (obj->type) {
case OBJ_STRING: {
vm->bytes_allocated += sizeof(String);
vm->bytes_allocated += (size_t)(((String*)obj)->length + 1);
} break;
case OBJ_LIST: {
List* list = (List*)obj;
grayVarBuffer(&list->elements, vm);
vm->bytes_allocated += sizeof(List);
vm->bytes_allocated += sizeof(Var) * list->elements.capacity;
} break;
case OBJ_MAP: {
TODO;
} break;
case OBJ_RANGE: {
vm->bytes_allocated += sizeof(Range);
} break;
case OBJ_SCRIPT:
{
Script* script = (Script*)obj;
vm->bytes_allocated += sizeof(Script);
const int NT_ELEM_SIZE = sizeof(*script->global_names.data);
grayVarBuffer(&script->globals, vm);
vm->bytes_allocated += sizeof(Var) * script->globals.capacity;
grayNameTable(&script->global_names, vm);
vm->bytes_allocated += NT_ELEM_SIZE * script->global_names.capacity;
grayVarBuffer(&script->literals, vm);
vm->bytes_allocated += sizeof(Var) * script->literals.capacity;
grayFunctionBuffer(&script->functions, vm);
vm->bytes_allocated += sizeof(Function*) * script->functions.capacity;
grayNameTable(&script->function_names, vm);
vm->bytes_allocated += NT_ELEM_SIZE * script->function_names.capacity;
grayStringBuffer(&script->names, vm);
vm->bytes_allocated += sizeof(String*) * script->names.capacity;
grayObject((Object*)script->body, vm);
} break;
case OBJ_FUNC:
{
Function* func = (Function*)obj;
vm->bytes_allocated += sizeof(Function);
grayObject((Object*)func->owner, vm);
if (!func->is_native) {
Fn* fn = func->fn;
vm->bytes_allocated += sizeof(uint8_t)* fn->opcodes.capacity;
vm->bytes_allocated += sizeof(int) * fn->oplines.capacity;
}
} break;
case OBJ_FIBER:
{
Fiber* fiber = (Fiber*)obj;
vm->bytes_allocated += sizeof(Fiber);
grayObject((Object*)fiber->func, vm);
// Blacken the stack.
for (Var* local = fiber->stack; local < fiber->sp; local++) {
grayValue(*local, vm);
}
vm->bytes_allocated += sizeof(Var) * fiber->stack_size;
// Blacken call frames.
for (int i = 0; i < fiber->frame_count; i++) {
grayObject((Object*)fiber->frames[i].fn, vm);
grayObject((Object*)fiber->frames[i].fn->owner, vm);
}
vm->bytes_allocated += sizeof(CallFrame) * fiber->frame_capacity;
grayObject((Object*)fiber->error, vm);
} break;
case OBJ_USER:
TODO;
break;
}
}
void blackenObjects(MSVM* vm) {
while (vm->gray_list_count > 0) {
// Pop the gray object from the list.
Object* gray = vm->gray_list[--vm->gray_list_count];
blackenObject(gray, vm);
}
}
#if VAR_NAN_TAGGING
@ -99,7 +228,7 @@ double varToDouble(Var value) {
static String* allocateString(MSVM* vm, size_t length) {
String* string = ALLOCATE_DYNAMIC(vm, String, length + 1, char);
varInitObject(&string->_super, vm, OBJ_STRING);
string->length = length;
string->length = (uint32_t)length;
string->data[length] = '\0';
return string;
}
@ -138,7 +267,7 @@ Script* newScript(MSVM* vm) {
varInitObject(&script->_super, vm, OBJ_SCRIPT);
script->name = NULL;
script->path = NULL;
// TODO: script->path = NULL;
varBufferInit(&script->globals);
nameTableInit(&script->global_names);

View File

@ -195,6 +195,7 @@ typedef enum /* ObjectType */ {
OBJ_FIBER,
// TODO: remove OBJ_USER and implement handlers for that.
OBJ_USER,
} ObjectType;
@ -245,10 +246,13 @@ struct Script {
// One of the below is null and other one is not. Since "std" script names
// are hardcoded and user script names are constructed.
const char* name; //< Std script's name. Null for user script.
String* path; //< Absolute path of the script. Null for std scripts.
ID imports[MAX_IMPORT_SCRIPTS]; //< Imported script IDs.
int import_count; //< Number of import in imports.
// TODO:
// String* path; //< Absolute path of the script. Null for std scripts.
// TODO: maybe imported scripts are stored in var buffer and not here.
// ID imports[MAX_IMPORT_SCRIPTS]; //< Imported script IDs.
// int import_count; //< Number of import in imports.
VarBuffer globals; //< Script level global variables.
NameTable global_names; //< Name map to index in globals.
@ -328,11 +332,31 @@ void varInitObject(Object* self, MSVM* vm, ObjectType type);
// Mark the reachable objects at the mark-and-sweep phase of the garbage
// collection.
void markObject(Object* self, MSVM* vm);
void grayObject(Object* self, MSVM* vm);
// Mark the reachable values at the mark-and-sweep phase of the garbage
// collection.
void markValue(Var self, MSVM* vm);
void grayValue(Var self, MSVM* vm);
// Mark the elements of the buffer as reachable at the mark-and-sweep pahse of
// the garbage collection.
void grayVarBuffer(VarBuffer* self, MSVM* vm);
// Mark the elements of the buffer as reachable at the mark-and-sweep pahse of
// the garbage collection.
void grayStringBuffer(StringBuffer* self, MSVM* vm);
// Mark the elements of the buffer as reachable at the mark-and-sweep pahse of
// the garbage collection.
void grayFunctionBuffer(FunctionBuffer* self, MSVM* vm);
// Mark the elements of the name table as reachable at the mark-and-sweep pahse
// of the garbage collection.
void grayNameTable(NameTable* self, MSVM* vm);
// Pop objects from the gray list and add it's referenced objects to the
// working list to traverse and update the vm's [bytes_allocated] value.
void blackenObjects(MSVM* vm);
// Instead use VAR_NUM(value) and AS_NUM(value)
Var doubleToVar(double value);

View File

@ -74,8 +74,8 @@ void msFreeVM(MSVM* self) {
obj = next;
}
self->marked_list = (Object**)self->config.realloc_fn(
self->marked_list, 0, self->config.user_data);
self->gray_list = (Object**)self->config.realloc_fn(
self->gray_list, 0, self->config.user_data);
self->config.realloc_fn(self, 0, self->config.user_data);
}
@ -83,10 +83,10 @@ void vmInit(MSVM* self, MSConfiguration* config) {
memset(self, 0, sizeof(MSVM));
self->config = *config;
self->marked_list_count = 0;
self->marked_list_capacity = 8; // TODO: refactor the magic '8' here.
self->marked_list = (Object**)self->config.realloc_fn(
NULL, sizeof(Object*) * self->marked_list_capacity, NULL);
self->gray_list_count = 0;
self->gray_list_capacity = 8; // TODO: refactor the magic '8' here.
self->gray_list = (Object**)self->config.realloc_fn(
NULL, sizeof(Object*) * self->gray_list_capacity, NULL);
self->next_gc = 1024 * 1024 * 10; // TODO:
// TODO: no need to initialize if already done by another vm.
@ -116,12 +116,12 @@ void vmCollectGarbage(MSVM* self) {
// Mark all the 'std' scripts.
for (int i = 0; i < self->std_count; i++) {
markObject(&(self->std_scripts[i]->_super), self);
grayObject(&(self->std_scripts[i]->_super), self);
}
// Mark temp references.
for (int i = 0; i < self->temp_reference_count; i++) {
markObject(self->temp_reference[i], self);
grayObject(self->temp_reference[i], self);
}
// Garbage collection triggered at the middle of a compilation.
@ -131,14 +131,16 @@ void vmCollectGarbage(MSVM* self) {
// Garbage collection triggered at the middle of runtime.
if (self->script != NULL) {
markObject(&self->script->_super, self);
grayObject(&self->script->_super, self);
}
if (self->fiber != NULL) {
markObject(&self->fiber->_super, self);
grayObject(&self->fiber->_super, self);
}
TODO;
blackenObjects(self);
TODO; // Sweep.
}
void vmAddStdScript(MSVM* self, Script* script) {

View File

@ -36,9 +36,9 @@ struct MSVM {
// In the tri coloring scheme gray is the working list. We recursively pop
// from the list color it balck and add it's referenced objects to gray_list.
Object** marked_list;
int marked_list_count;
int marked_list_capacity;
Object** gray_list;
int gray_list_count;
int gray_list_capacity;
// A stack of temporary object references to ensure that the object
// doesn't garbage collected.