summaryrefslogtreecommitdiffstats
path: root/eval.c
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2024-03-01 23:15:26 -0800
committerKaz Kylheku <kaz@kylheku.com>2024-03-01 23:15:26 -0800
commit06bd10fd45dc008fe0ea4909254b2e951e715809 (patch)
tree596f442e02bf5f9cd1f4ca80248373902e4d552d /eval.c
parent1134089866fde0478fe869aa6fa13e105325ddcd (diff)
downloadtxr-06bd10fd45dc008fe0ea4909254b2e951e715809.tar.gz
txr-06bd10fd45dc008fe0ea4909254b2e951e715809.tar.bz2
txr-06bd10fd45dc008fe0ea4909254b2e951e715809.zip
mapcar: avoid alloca proportional to number of args.
* eval.c (MAP_ALLOCA_LIMIT): New preprocessor symbol. (map_common): If the number of args is greater than MAP_ALLOCA_LIMIT, then allocate the array of seq_iter_t structures from chk_malloc rather than alloca. In case an exception might be thrown during the execution of this function, we bind that memory to a buf object. If we return normally, we call the new function buf_free to release it. Otherwise we rely on the garbage collector. * buf.[ch] (buf_free): New function. * tests/012/seq.tl: Test case which hits this behavior.
Diffstat (limited to 'eval.c')
-rw-r--r--eval.c18
1 files changed, 16 insertions, 2 deletions
diff --git a/eval.c b/eval.c
index cd87c3a9..e6edb5a0 100644
--- a/eval.c
+++ b/eval.c
@@ -57,11 +57,18 @@
#include "filter.h"
#include "tree.h"
#include "vm.h"
+#include "buf.h"
#include "eval.h"
#define max(a, b) ((a) > (b) ? (a) : (b))
#define min(a, b) ((a) < (b) ? (a) : (b))
+#if CONFIG_SMALL_MEM
+#define MAP_ALLOCA_LIMIT 1024
+#else
+#define MAP_ALLOCA_LIMIT 4096
+#endif
+
typedef val (*opfun_t)(val, val);
struct c_var {
@@ -5776,9 +5783,13 @@ static val map_common(val self, val fun, varg lists,
return map_fn(fun, args_atz(lists, 0));
} else {
cnum i, idx, argc = args_count(lists, self);
+ int over_limit = (argc > MAP_ALLOCA_LIMIT);
val arg0 = args_at(lists, 0);
seq_iter_t *iter_array = coerce(seq_iter_t *,
- alloca(argc * sizeof *iter_array));
+ if3(over_limit,
+ chk_malloc(argc * sizeof *iter_array),
+ alloca(argc * sizeof *iter_array)));
+ val buf = if2(over_limit, make_owned_buf(one, coerce(mem_t *, iter_array)));
seq_build_t out = { 0 };
args_decl(args_fun, max(argc, ARGS_MIN));
@@ -5798,8 +5809,11 @@ static val map_common(val self, val fun, varg lists,
val elem;
seq_iter_t *iter = &iter_array[i];
- if (!seq_get(iter, &elem))
+ if (!seq_get(iter, &elem)) {
+ if (buf)
+ buf_free(buf);
return collect_fn != 0 ? seq_finish(&out) : nil;
+ }
args_fun->arg[i] = elem;
}