fix+ref: small objects rework

- Add nested objects escape on ESCAPE opcode
- Stabilize objects work in heap
This commit is contained in:
samsonium
2026-10-18 17:38:49 +03:00
parent 0c8c206677
commit dce64e8b4d
3 changed files with 102 additions and 67 deletions
-3
View File
@@ -30,9 +30,6 @@ typedef struct
// Environment stack
fzl_vm_env_t *estack[256];
size_t etop;
fzl_vm_object_t *objects[256];
size_t objects_count;
} fzl_vm_t;
// Allocate FZL VM
+99 -63
View File
@@ -25,20 +25,18 @@ fzl_vm_t *fzl_mkvm(const char *filepath)
return NULL;
}
vm->consts = NULL;
vm->consts_count = 0;
vm->ops = NULL;
vm->ops_count = 0;
vm->ip = 0;
vm->dtop = 0;
vm->ctop = 0;
vm->etop = 0;
vm->objects_count = 0;
vm->consts = NULL;
vm->consts_count = 0;
vm->ops = NULL;
vm->ops_count = 0;
vm->ip = 0;
vm->dtop = 0;
vm->ctop = 0;
vm->etop = 0;
memset(vm->dstack, 0, sizeof(vm->dstack));
memset(vm->cstack, 0, sizeof(vm->cstack));
memset(vm->estack, 0, sizeof(vm->estack));
memset(vm->objects, 0, sizeof(vm->objects));
FILE *fd = fopen(filepath, "rb");
if (!fd)
@@ -110,6 +108,57 @@ fzl_vm_t *fzl_mkvm(const char *filepath)
return vm;
}
// Escape objects with nested objects check
static void escape_recursive(fzl_vm_env_t *current, fzl_vm_env_t *parent,
fzl_vm_object_t *obj)
{
if (!current || !parent || !obj)
return;
bool found_in_current = false;
for (size_t i = 0; i < current->owned_objects_count; i++)
{
if (current->owned_objects[i] == obj)
{
current->owned_objects[i] = NULL;
found_in_current = true;
break;
}
}
if (found_in_current)
{
bool found_in_parent = false;
for (size_t i = 0; i < parent->owned_objects_count; i++)
{
if (parent->owned_objects[i] == obj)
{
found_in_parent = true;
break;
}
}
if (!found_in_parent)
{
if (parent->owned_objects_remainder <= parent->owned_objects_count)
{
parent->owned_objects_remainder *= 2;
parent->owned_objects =
realloc(parent->owned_objects, parent->owned_objects_remainder *
sizeof(fzl_vm_object_t *));
}
parent->owned_objects[parent->owned_objects_count++] = obj;
}
}
for (size_t i = 0; i < obj->values_count; i++)
{
if (obj->values[i].type == FZL_TYPE_OBJECT && obj->values[i].as.obj != NULL)
escape_recursive(current, parent, obj->values[i].as.obj);
}
}
void print_object(fzl_vm_object_t *obj)
{
if (!obj)
@@ -153,25 +202,32 @@ void print_err_data(fzl_vm_t *vm)
printf("> Caused on IP: %zu\n", vm->ip);
printf("\n> Data stack:\n");
for (ssize_t i = vm->dtop - 1; i >= 0; i--)
if (vm->dtop > 0)
{
printf("\t> [%d] ", vm->dstack[i].type);
switch (vm->dstack[i].type)
for (ssize_t i = vm->dtop - 1; i >= 0; i--)
{
case FZL_TYPE_OBJECT:
printf("ref: %p\n", vm->dstack[i].as.obj);
break;
case FZL_TYPE_STRING:
printf("str: '%s'\n", vm->dstack[i].as.s.value);
break;
case FZL_TYPE_NULL:
printf("<null>\n");
break;
default:
printf("%lu\n", vm->dstack[i].as.u);
break;
printf("\t> [%d] ", vm->dstack[i].type);
switch (vm->dstack[i].type)
{
case FZL_TYPE_OBJECT:
printf("ref: %p\n", vm->dstack[i].as.obj);
break;
case FZL_TYPE_STRING:
printf("str: '%s'\n", vm->dstack[i].as.s.value);
break;
case FZL_TYPE_NULL:
printf("<null>\n");
break;
default:
printf("%lu\n", vm->dstack[i].as.u);
break;
}
}
}
else
{
printf("\tEmpty\n");
}
printf("\n> Environments:\n");
for (ssize_t i = vm->etop - 1; i >= 0; i--)
@@ -187,8 +243,20 @@ void print_err_data(fzl_vm_t *vm)
printf("\t\t> Local entries (%zu/%zu):\n", env->size, env->remainder);
for (size_t j = 0; j < env->size; j++)
printf("\t\t\t> [%d] %s = %lu\n", env->table[j].value.type,
env->table[j].name, env->table[j].value.as.u);
{
switch (env->table[j].value.type)
{
case FZL_TYPE_OBJECT:
printf("\t\t\t> [%d] %s = ref %p\n", env->table[j].value.type,
env->table[j].name, env->table[j].value.as.obj);
break;
default:
printf("\t\t\t> [%d] %s = %lu\n", env->table[j].value.type,
env->table[j].name, env->table[j].value.as.u);
break;
}
}
}
printf("\n> Call stack:\n");
@@ -260,7 +328,7 @@ int fzl_vm_run(fzl_vm_t *vm)
fzl_value_t right = vm->dstack[--vm->dtop];
vm->dstack[vm->dtop++] = (fzl_value_t){
.type = FZL_TYPE_BOOL, .as.b = &left.as.obj == &right.as.obj};
.type = FZL_TYPE_BOOL, .as.b = left.as.obj == right.as.obj};
break;
}
@@ -277,11 +345,10 @@ int fzl_vm_run(fzl_vm_t *vm)
fzl_value_t right = vm->dstack[--vm->dtop];
vm->dstack[vm->dtop++] = (fzl_value_t){
.type = FZL_TYPE_BOOL, .as.b = &left.as.obj != &right.as.obj};
.type = FZL_TYPE_BOOL, .as.b = left.as.obj != right.as.obj};
break;
}
// NOTE: make recursive owning transfer for nested objects!
case FZL_OPCODE_ESCAPE_OBJECT:
{
if (vm->dtop < 1)
@@ -302,7 +369,7 @@ int fzl_vm_run(fzl_vm_t *vm)
fzl_vm_env_t *parent = vm->estack[vm->etop - 2];
fzl_vm_env_t *current = vm->estack[vm->etop - 1];
if (!parent || vm->etop < 2)
if (vm->etop < 2)
{
snprintf(last_err, sizeof(last_err),
"runtime error - cannot escape object from global env");
@@ -310,32 +377,7 @@ int fzl_vm_run(fzl_vm_t *vm)
return -1;
}
bool found = false;
if (obj.as.u != 0)
{
for (size_t i = 0; i < current->owned_objects_count; i++)
{
if (obj.as.obj == current->owned_objects[i])
{
found = true;
current->owned_objects[i] = NULL;
break;
}
}
}
if (found)
{
if (parent->owned_objects_remainder <= parent->owned_objects_count)
{
parent->owned_objects_remainder *= 2;
parent->owned_objects =
realloc(parent->owned_objects, parent->owned_objects_remainder *
sizeof(fzl_vm_object_t *));
}
parent->owned_objects[parent->owned_objects_count++] = obj.as.obj;
}
escape_recursive(current, parent, obj.as.obj);
vm->dstack[vm->dtop++] = obj;
break;
@@ -900,12 +942,6 @@ void fzl_freevm(fzl_vm_t *vm)
free((void *)vm->consts[i].as.string.chars);
}
for (size_t i = 0; i < vm->objects_count; i++)
{
free(vm->objects[i]->values);
free(vm->objects[i]);
}
free(vm->consts);
free(vm->ops);
free(vm);
+3 -1
View File
@@ -109,7 +109,9 @@ void fzl_freeenv(fzl_vm_env_t *env)
if (!env->owned_objects[i])
continue;
free(env->owned_objects[i]->values);
if (env->owned_objects[i]->values)
free(env->owned_objects[i]->values);
free(env->owned_objects[i]);
}