summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorJo-Philipp Wich <jo@mein.io>2022-08-12 00:22:26 +0200
committerJo-Philipp Wich <jo@mein.io>2022-08-12 01:23:27 +0200
commit85d7885e226ed79dc071e0cef73ccc918144a8f5 (patch)
tree0e56769cd7fbe473c18a656b1f63d256a7856547
parent47528f02e7376f1fbb205c5cf69d17d55619fcb1 (diff)
lib: implement gc()
Introduce a new stdlib function `gc()` which allows controlling the periodic garbage collector from ucode. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
-rw-r--r--lib.c44
-rw-r--r--tests/custom/03_stdlib/60_gc107
2 files changed, 151 insertions, 0 deletions
diff --git a/lib.c b/lib.c
index 7a04cdd..1cbde6d 100644
--- a/lib.c
+++ b/lib.c
@@ -3519,6 +3519,49 @@ uc_hexdec(uc_vm_t *vm, size_t nargs)
return ucv_stringbuf_finish(buf);
}
+static uc_value_t *
+uc_gc(uc_vm_t *vm, size_t nargs)
+{
+ uc_value_t *operation = uc_fn_arg(0);
+ uc_value_t *argument = uc_fn_arg(1);
+ const char *op = NULL;
+ uc_weakref_t *ref;
+ int64_t n;
+
+ if (operation != NULL && ucv_type(operation) != UC_STRING)
+ return NULL;
+
+ op = ucv_string_get(operation);
+
+ if (!op || !strcmp(op, "collect")) {
+ ucv_gc(vm);
+
+ return ucv_boolean_new(true);
+ }
+ else if (!strcmp(op, "start")) {
+ n = argument ? ucv_int64_get(argument) : 0;
+
+ if (errno || n < 0 || n > 0xFFFF)
+ return NULL;
+
+ if (n == 0)
+ n = GC_DEFAULT_INTERVAL;
+
+ return ucv_boolean_new(uc_vm_gc_start(vm, n));
+ }
+ else if (!strcmp(op, "stop")) {
+ return ucv_boolean_new(uc_vm_gc_stop(vm));
+ }
+ else if (!strcmp(op, "count")) {
+ for (n = 0, ref = vm->values.next; ref != &vm->values; ref = ref->next)
+ n++;
+
+ return ucv_uint64_new(n);
+ }
+
+ return NULL;
+}
+
const uc_function_list_t uc_stdlib_functions[] = {
{ "chr", uc_chr },
@@ -3586,6 +3629,7 @@ const uc_function_list_t uc_stdlib_functions[] = {
{ "clock", uc_clock },
{ "hexdec", uc_hexdec },
{ "hexenc", uc_hexenc },
+ { "gc", uc_gc }
};
diff --git a/tests/custom/03_stdlib/60_gc b/tests/custom/03_stdlib/60_gc
new file mode 100644
index 0000000..44e5d9e
--- /dev/null
+++ b/tests/custom/03_stdlib/60_gc
@@ -0,0 +1,107 @@
+The `gc()` function allows controlling the garbage collector of the VM.
+It takes the requested operation as first argument and an optional,
+operation specific second argument.
+
+Returns `null` if the given operation is invalid or if the operation
+specific argument is invalid.
+
+Returns `false` if the requested operation would not result in any
+changes.
+
+Returns `true` if the requested oepration succeeded (e.g. starting
+the GC when it was previously stopped).
+
+Returns an object count if the given operation is `count`.
+
+-- Testcase --
+{%
+ printf("Count #1: %d\n", gc("count"));
+
+ // create an unreachable cyclic structure
+ let o = {};
+ o.cycle = o;
+ o = null;
+
+ printf("Count #2: %d\n", gc("count"));
+
+ // invoking gc without any argument defaults to "collect"
+ gc();
+
+ printf("Count #3: %d\n", gc("count"));
+
+
+ // create another unreachable cyclic structure
+ o = {};
+ o.cycle = o;
+ o = null;
+
+ printf("Count #4: %d\n", gc("count"));
+
+ // invoking gc with explicit collect argument
+ gc("collect");
+
+ printf("Count #5: %d\n", gc("count"));
+%}
+-- End --
+
+-- Expect stdout --
+Count #1: 5
+Count #2: 6
+Count #3: 5
+Count #4: 6
+Count #5: 5
+-- End --
+
+
+Testing enabling the automatic collector.
+
+-- Testcase --
+{%
+ // start GC, trigger every 10 object allocations
+ gc("start", 10);
+
+ for (let i = 0; i < 100; i++) {
+ let o = {};
+ o.cyle = o;
+ o = null;
+
+ if ((i % 10) == 0)
+ printf("Count #%d: %d\n", (i / 10) + 1, gc("count"));
+ }
+
+ // stop GC
+ gc("stop");
+
+ for (let i = 100; i < 200; i++) {
+ let o = {};
+ o.cyle = o;
+ o = null;
+
+ if ((i % 10) == 0)
+ printf("Count #%d: %d\n", (i / 10) + 1, gc("count"));
+ }
+%}
+-- End --
+
+-- Expect stdout --
+Count #1: 6
+Count #2: 12
+Count #3: 12
+Count #4: 12
+Count #5: 12
+Count #6: 12
+Count #7: 12
+Count #8: 12
+Count #9: 12
+Count #10: 12
+Count #11: 12
+Count #12: 22
+Count #13: 32
+Count #14: 42
+Count #15: 52
+Count #16: 62
+Count #17: 72
+Count #18: 82
+Count #19: 92
+Count #20: 102
+-- End --