2 Commits
Author SHA1 Message Date
samsonium dce64e8b4d fix+ref: small objects rework
- Add nested objects escape on ESCAPE opcode
- Stabilize objects work in heap
2026-10-18 17:38:49 +03:00
samsonium 0c8c206677 upd: update tests 2026-10-18 17:37:18 +03:00
6 changed files with 112 additions and 68 deletions
+8
View File
@@ -78,6 +78,10 @@ add_test(
NAME compile_borrow NAME compile_borrow
COMMAND fzc -o "${CMAKE_CURRENT_BINARY_DIR}/borrow.fzb" "${CMAKE_CURRENT_SOURCE_DIR}/exl/borrow.fzs" COMMAND fzc -o "${CMAKE_CURRENT_BINARY_DIR}/borrow.fzb" "${CMAKE_CURRENT_SOURCE_DIR}/exl/borrow.fzs"
) )
add_test(
NAME compile_hard_1
COMMAND fzc -o "${CMAKE_CURRENT_BINARY_DIR}/hard-1.fzb" "${CMAKE_CURRENT_SOURCE_DIR}/exl/hard-1.fzs"
)
set_tests_properties(compile_problematic_hw PROPERTIES WILL_FAIL TRUE) set_tests_properties(compile_problematic_hw PROPERTIES WILL_FAIL TRUE)
@@ -125,4 +129,8 @@ add_test(
NAME runtime_borrow NAME runtime_borrow
COMMAND fz "${CMAKE_CURRENT_BINARY_DIR}/borrow.fzb" COMMAND fz "${CMAKE_CURRENT_BINARY_DIR}/borrow.fzb"
) )
add_test(
NAME runtime_hard_1
COMMAND fz "${CMAKE_CURRENT_BINARY_DIR}/hard-1.fzb"
)
+1 -1
View File
@@ -32,6 +32,6 @@ printline(a);
a = doSome(a); a = doSome(a);
printline(a); printline(a);
b = doSomeNew(); A b = doSomeNew();
printline(b); printline(b);
+1
View File
@@ -51,6 +51,7 @@ printline("Elements:");
list.printList(); list.printList();
printline("===== Test 2: mutation & methods ====="); printline("===== Test 2: mutation & methods =====");
list = list.append(10);
int total = list.sum(); int total = list.sum();
printline("Sum of elements:"); printline("Sum of elements:");
printline(total); printline(total);
-3
View File
@@ -30,9 +30,6 @@ typedef struct
// Environment stack // Environment stack
fzl_vm_env_t *estack[256]; fzl_vm_env_t *estack[256];
size_t etop; size_t etop;
fzl_vm_object_t *objects[256];
size_t objects_count;
} fzl_vm_t; } fzl_vm_t;
// Allocate FZL VM // Allocate FZL VM
+74 -38
View File
@@ -33,12 +33,10 @@ fzl_vm_t *fzl_mkvm(const char *filepath)
vm->dtop = 0; vm->dtop = 0;
vm->ctop = 0; vm->ctop = 0;
vm->etop = 0; vm->etop = 0;
vm->objects_count = 0;
memset(vm->dstack, 0, sizeof(vm->dstack)); memset(vm->dstack, 0, sizeof(vm->dstack));
memset(vm->cstack, 0, sizeof(vm->cstack)); memset(vm->cstack, 0, sizeof(vm->cstack));
memset(vm->estack, 0, sizeof(vm->estack)); memset(vm->estack, 0, sizeof(vm->estack));
memset(vm->objects, 0, sizeof(vm->objects));
FILE *fd = fopen(filepath, "rb"); FILE *fd = fopen(filepath, "rb");
if (!fd) if (!fd)
@@ -110,6 +108,57 @@ fzl_vm_t *fzl_mkvm(const char *filepath)
return vm; 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) void print_object(fzl_vm_object_t *obj)
{ {
if (!obj) if (!obj)
@@ -153,6 +202,8 @@ void print_err_data(fzl_vm_t *vm)
printf("> Caused on IP: %zu\n", vm->ip); printf("> Caused on IP: %zu\n", vm->ip);
printf("\n> Data stack:\n"); printf("\n> Data stack:\n");
if (vm->dtop > 0)
{
for (ssize_t i = vm->dtop - 1; i >= 0; i--) for (ssize_t i = vm->dtop - 1; i >= 0; i--)
{ {
printf("\t> [%d] ", vm->dstack[i].type); printf("\t> [%d] ", vm->dstack[i].type);
@@ -172,6 +223,11 @@ void print_err_data(fzl_vm_t *vm)
break; break;
} }
} }
}
else
{
printf("\tEmpty\n");
}
printf("\n> Environments:\n"); printf("\n> Environments:\n");
for (ssize_t i = vm->etop - 1; i >= 0; i--) 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); printf("\t\t> Local entries (%zu/%zu):\n", env->size, env->remainder);
for (size_t j = 0; j < env->size; j++) for (size_t j = 0; j < env->size; j++)
{
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, printf("\t\t\t> [%d] %s = %lu\n", env->table[j].value.type,
env->table[j].name, env->table[j].value.as.u); env->table[j].name, env->table[j].value.as.u);
break;
}
}
} }
printf("\n> Call stack:\n"); 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]; fzl_value_t right = vm->dstack[--vm->dtop];
vm->dstack[vm->dtop++] = (fzl_value_t){ 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; break;
} }
@@ -277,11 +345,10 @@ int fzl_vm_run(fzl_vm_t *vm)
fzl_value_t right = vm->dstack[--vm->dtop]; fzl_value_t right = vm->dstack[--vm->dtop];
vm->dstack[vm->dtop++] = (fzl_value_t){ 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; break;
} }
// NOTE: make recursive owning transfer for nested objects!
case FZL_OPCODE_ESCAPE_OBJECT: case FZL_OPCODE_ESCAPE_OBJECT:
{ {
if (vm->dtop < 1) 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 *parent = vm->estack[vm->etop - 2];
fzl_vm_env_t *current = vm->estack[vm->etop - 1]; 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), snprintf(last_err, sizeof(last_err),
"runtime error - cannot escape object from global env"); "runtime error - cannot escape object from global env");
@@ -310,32 +377,7 @@ int fzl_vm_run(fzl_vm_t *vm)
return -1; return -1;
} }
bool found = false; escape_recursive(current, parent, obj.as.obj);
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;
}
vm->dstack[vm->dtop++] = obj; vm->dstack[vm->dtop++] = obj;
break; break;
@@ -900,12 +942,6 @@ void fzl_freevm(fzl_vm_t *vm)
free((void *)vm->consts[i].as.string.chars); 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->consts);
free(vm->ops); free(vm->ops);
free(vm); free(vm);
+2
View File
@@ -109,7 +109,9 @@ void fzl_freeenv(fzl_vm_env_t *env)
if (!env->owned_objects[i]) if (!env->owned_objects[i])
continue; continue;
if (env->owned_objects[i]->values)
free(env->owned_objects[i]->values); free(env->owned_objects[i]->values);
free(env->owned_objects[i]); free(env->owned_objects[i]);
} }