summaryrefslogtreecommitdiffhomepage
path: root/vm.c
diff options
context:
space:
mode:
authorJo-Philipp Wich <jo@mein.io>2022-08-12 00:19:50 +0200
committerJo-Philipp Wich <jo@mein.io>2022-08-12 01:03:00 +0200
commit47528f02e7376f1fbb205c5cf69d17d55619fcb1 (patch)
tree4a6255f3c741cbcbb33b42605177e200122e1ff2 /vm.c
parent381cc7508f797e5158bbd1620d6154ef4a11b76c (diff)
vm: support automatic periodic GC runs
Introduce two new VM api functions uc_vm_gc_start() and uc_vm_gc_stop() which allow starting and stopping automatic periodic garbage collection of cyclic objects in the VM context. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
Diffstat (limited to 'vm.c')
-rw-r--r--vm.c59
1 files changed, 59 insertions, 0 deletions
diff --git a/vm.c b/vm.c
index c08f9ce..d8f0074 100644
--- a/vm.c
+++ b/vm.c
@@ -2508,6 +2508,35 @@ uc_vm_insn_dynload(uc_vm_t *vm, uc_vm_insn_t insn)
}
}
+static void
+uc_vm_gc_step(uc_vm_t *vm)
+{
+ size_t curr_count = 0, prev_count = 0;
+ uc_weakref_t *ref;
+
+ if (!(vm->gc_flags & GC_ENABLED))
+ return;
+
+ if (vm->alloc_refs >= vm->gc_interval) {
+ if (vm->trace) {
+ for (ref = vm->values.next; ref != &vm->values; ref = ref->next)
+ prev_count++;
+
+ ucv_gc(vm);
+
+ for (ref = vm->values.next; ref != &vm->values; ref = ref->next)
+ curr_count++;
+
+ fprintf(stderr, "! GC reclaimed %zu object(s)\n", prev_count - curr_count);
+ }
+ else {
+ ucv_gc(vm);
+ }
+
+ vm->alloc_refs = 0;
+ }
+}
+
static uc_value_t *
uc_vm_callframe_pop(uc_vm_t *vm)
{
@@ -2755,6 +2784,7 @@ uc_vm_execute_chunk(uc_vm_t *vm)
case I_POP:
ucv_put(uc_vm_stack_pop(vm));
+ uc_vm_gc_step(vm);
break;
case I_CUPV:
@@ -3028,3 +3058,32 @@ uc_vm_registry_delete(uc_vm_t *vm, const char *key)
{
return ucv_object_delete(vm->registry, key);
}
+
+bool
+uc_vm_gc_start(uc_vm_t *vm, uint16_t interval)
+{
+ bool changed = false;
+
+ if (vm->gc_interval != interval) {
+ vm->gc_interval = interval;
+ changed = true;
+ }
+
+ if (!(vm->gc_flags & GC_ENABLED)) {
+ vm->gc_flags |= GC_ENABLED;
+ changed = true;
+ }
+
+ return changed;
+}
+
+bool
+uc_vm_gc_stop(uc_vm_t *vm)
+{
+ if (!(vm->gc_flags & GC_ENABLED))
+ return false;
+
+ vm->gc_flags &= ~GC_ENABLED;
+
+ return true;
+}