feat: optimize VM using dispatch table
This commit is contained in:
@@ -0,0 +1,223 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <vm/fzl_vm.h>
|
||||
#include <vm/internals/opcode.h>
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
// Allocate specified count of fields and create object
|
||||
int op_alloc_object(fzl_vm_t *vm)
|
||||
{
|
||||
uint64_t values_count = vm->ops[++vm->ip];
|
||||
fzl_vm_object_t *obj = malloc(sizeof(fzl_vm_object_t));
|
||||
|
||||
if (values_count > 0)
|
||||
obj->values = malloc(values_count * sizeof(fzl_value_t));
|
||||
obj->values_count = values_count;
|
||||
memset(obj->values, 0, values_count * sizeof(fzl_value_t));
|
||||
|
||||
fzl_vm_env_t *current_env = vm->estack[vm->etop - 1];
|
||||
if (current_env->owned_objects_remainder <= current_env->owned_objects_count)
|
||||
{
|
||||
current_env->owned_objects_remainder *= 2;
|
||||
current_env->owned_objects = realloc(current_env->owned_objects,
|
||||
current_env->owned_objects_remainder *
|
||||
sizeof(fzl_vm_object_t *));
|
||||
}
|
||||
|
||||
current_env->owned_objects[current_env->owned_objects_count++] = obj;
|
||||
vm->dstack[vm->dtop++] =
|
||||
(fzl_value_t){.type = FZL_TYPE_OBJECT, .as.obj = obj};
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Pop object from stack and push its field value
|
||||
int op_get_field(fzl_vm_t *vm)
|
||||
{
|
||||
if (vm->dtop < 1)
|
||||
{
|
||||
snprintf(last_err, sizeof(last_err),
|
||||
"runtime error - expected value in data stack");
|
||||
print_err_data(vm);
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint64_t field_slot = vm->ops[++vm->ip];
|
||||
fzl_value_t val = vm->dstack[--vm->dtop];
|
||||
if (val.type != FZL_TYPE_OBJECT)
|
||||
{
|
||||
snprintf(last_err, sizeof(last_err),
|
||||
"runtime error - cannot access field #%lu of non-object type",
|
||||
field_slot);
|
||||
print_err_data(vm);
|
||||
return -1;
|
||||
}
|
||||
|
||||
fzl_vm_object_t *obj = val.as.obj;
|
||||
if (obj->values_count <= field_slot)
|
||||
{
|
||||
snprintf(last_err, sizeof(last_err),
|
||||
"runtime error - cannot access field #%lu", field_slot);
|
||||
print_err_data(vm);
|
||||
return -1;
|
||||
}
|
||||
|
||||
vm->dstack[vm->dtop++] = obj->values[field_slot];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Pop object and write value from stack and write value into objects' field
|
||||
int op_set_field(fzl_vm_t *vm)
|
||||
{
|
||||
if (vm->dtop < 2)
|
||||
{
|
||||
snprintf(last_err, sizeof(last_err),
|
||||
"runtime error - expected two values in data stack");
|
||||
print_err_data(vm);
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint64_t field_slot = vm->ops[++vm->ip];
|
||||
fzl_value_t objval = vm->dstack[--vm->dtop];
|
||||
fzl_value_t wrval = vm->dstack[--vm->dtop];
|
||||
if (objval.type != FZL_TYPE_OBJECT)
|
||||
{
|
||||
snprintf(last_err, sizeof(last_err),
|
||||
"runtime error - cannot access field #%lu of non-object type",
|
||||
field_slot);
|
||||
print_err_data(vm);
|
||||
return -1;
|
||||
}
|
||||
|
||||
fzl_vm_object_t *obj = objval.as.obj;
|
||||
if (obj->values_count <= field_slot)
|
||||
{
|
||||
snprintf(last_err, sizeof(last_err),
|
||||
"runtime error - cannot access field #%lu", field_slot);
|
||||
print_err_data(vm);
|
||||
return -1;
|
||||
}
|
||||
|
||||
obj->values[field_slot] = wrval;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Escape object to the parent scope
|
||||
int op_escape_object(fzl_vm_t *vm)
|
||||
{
|
||||
if (vm->dtop < 1)
|
||||
{
|
||||
snprintf(last_err, sizeof(last_err),
|
||||
"runtime error - missing value in data stack");
|
||||
print_err_data(vm);
|
||||
return -1;
|
||||
}
|
||||
fzl_value_t obj = vm->dstack[--vm->dtop];
|
||||
if (obj.type != FZL_TYPE_OBJECT)
|
||||
{
|
||||
snprintf(last_err, sizeof(last_err),
|
||||
"runtime error - cannot escape non-object type");
|
||||
print_err_data(vm);
|
||||
return -1;
|
||||
}
|
||||
|
||||
fzl_vm_env_t *parent = vm->estack[vm->etop - 2];
|
||||
fzl_vm_env_t *current = vm->estack[vm->etop - 1];
|
||||
if (vm->etop < 2)
|
||||
{
|
||||
snprintf(last_err, sizeof(last_err),
|
||||
"runtime error - cannot escape object from global env");
|
||||
print_err_data(vm);
|
||||
return -1;
|
||||
}
|
||||
|
||||
escape_recursive(current, parent, obj.as.obj);
|
||||
vm->dstack[vm->dtop++] = obj;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Pop value from data stack and store dereferenced value
|
||||
int op_dereference(fzl_vm_t *vm)
|
||||
{
|
||||
if (vm->dtop < 1)
|
||||
{
|
||||
snprintf(last_err, sizeof(last_err),
|
||||
"runtime error - expected value in data stack");
|
||||
print_err_data(vm);
|
||||
return -1;
|
||||
}
|
||||
|
||||
fzl_value_t addr = vm->dstack[--vm->dtop];
|
||||
if (addr.type < FZL_TYPE_INT8)
|
||||
{
|
||||
snprintf(last_err, sizeof(last_err), "runtime error - expected address");
|
||||
print_err_data(vm);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (addr.as.u == 0)
|
||||
{
|
||||
vm->dstack[vm->dtop++] =
|
||||
(fzl_value_t){.type = FZL_TYPE_OBJECT, .as.obj = NULL};
|
||||
}
|
||||
else
|
||||
{
|
||||
vm->dstack[vm->dtop++] = (fzl_value_t){
|
||||
.type = FZL_TYPE_OBJECT, .as.obj = (fzl_vm_object_t *)addr.as.u};
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user