summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2018-03-09 06:12:38 -0800
committerKaz Kylheku <kaz@kylheku.com>2018-03-09 06:12:38 -0800
commit5f8cc479f8d1724f07ad6673371ff1ebf0d79f4b (patch)
tree4f3004c9015a310a1b3a08b8e7adfe782891b549
parent313c7f915f0011efda24361bc310ad149fedeb3e (diff)
downloadtxr-5f8cc479f8d1724f07ad6673371ff1ebf0d79f4b.tar.gz
txr-5f8cc479f8d1724f07ad6673371ff1ebf0d79f4b.tar.bz2
txr-5f8cc479f8d1724f07ad6673371ff1ebf0d79f4b.zip
args: overhaul for clarity and reduced consing.
* args.c (args_normalize): Renamed to args_normalize_exact, because this tries to split the arguments between an exact array fill quantity and trailing list. Not all places using this function actually need an exact fill, which causes unnecessary consing when args->fill is reduced in order to move items to args->list. (args_normalize_least): New function. Variant of args_normalize that can be used by functions which only require a minimum fill. (args_normalize_fill): Use args_normalize_least rather than args_normalize_exact. This reduces consing in generic_funcall, in handling variadic calls where arrayed arguments have been supplied for trailing parameters. * args.h (args_normalize): Renamed to args_normalize_exact. (args_normalize_least): Declared. (args_get_list, args_get_rest): Use args_normalize_exact. (args_clear): Inline function removed. Was used only in one place in generic_funcall and is no longer. * eval.c (gather_free_refs): Use args_normalize_least. (prod_common): Use args_normalize_exact. * ffi.c (ffi_call_wrap): Use args_normalize_least. * lib.c (generic_funcall): Use args_normalize_least in switch statement that handles various callable non-function objects. When copying args, ensure that there are ARGS_MIN. A different strategy is used for producing the trailing args for variadic calls, further reducing consing. Rather than normalize the args to the fixed number, and then set args->fill to zero so that args contains just the list, we use args_cat_zap_from to create a copy of the args in which the fixed ones are trimmed out. The resulting args is not renormalized to be purely a list so no consing or list traversal takes place. If the rebalancing is needed, the called function will have to do it. (dwim_set): Streamline the code that handles hashes assigned via two or three args. * struct.c (method_args_fun, umethod_args_fun): Use args_normalize_exact.
-rw-r--r--args.c12
-rw-r--r--args.h12
-rw-r--r--eval.c4
-rw-r--r--ffi.c2
-rw-r--r--lib.c39
-rw-r--r--struct.c4
6 files changed, 39 insertions, 34 deletions
diff --git a/args.c b/args.c
index 4fe46f67..aa2139a7 100644
--- a/args.c
+++ b/args.c
@@ -46,7 +46,7 @@ val args_add_checked(val name, struct args *args, val arg)
return args_add(args, arg);
}
-void args_normalize(struct args *args, cnum fill)
+void args_normalize_exact(struct args *args, cnum fill)
{
bug_unless (fill <= args->argc);
@@ -58,9 +58,17 @@ void args_normalize(struct args *args, cnum fill)
}
+void args_normalize_least(struct args *args, cnum minfill)
+{
+ bug_unless (args->fill <= args->argc);
+
+ while (args->fill < minfill && args->list)
+ args_add(args, pop(&args->list));
+}
+
void args_normalize_fill(struct args *args, cnum minfill, cnum maxfill)
{
- args_normalize(args, maxfill);
+ args_normalize_least(args, maxfill);
if (args->fill >= minfill)
while (args->fill < maxfill)
diff --git a/args.h b/args.h
index 3ea94186..76aa10a1 100644
--- a/args.h
+++ b/args.h
@@ -134,14 +134,15 @@ INLINE int args_two_more(struct args *args, cnum index)
cdr(args->list);
}
-void args_normalize(struct args *args, cnum fill);
+void args_normalize_exact(struct args *args, cnum fill);
+void args_normalize_least(struct args *args, cnum fill);
void args_normalize_fill(struct args *args, cnum minfill, cnum maxfill);
INLINE val args_get_list(struct args *args)
{
if (args->fill == 0)
return z(args->list);
- args_normalize(args, 0);
+ args_normalize_exact(args, 0);
return z(args->list);
}
@@ -149,7 +150,7 @@ INLINE val args_get_rest(struct args *args, cnum index)
{
if (args->fill == index)
return z(args->list);
- args_normalize(args, index);
+ args_normalize_exact(args, index);
return z(args->list);
}
@@ -176,11 +177,6 @@ INLINE val args_get(struct args *args, cnum *arg_index)
return pop(&args->list);
}
-INLINE void args_clear(struct args *args)
-{
- args->fill = 0;
-}
-
INLINE cnum args_count(struct args *args)
{
return args->fill + c_num(length_list(args->list));
diff --git a/eval.c b/eval.c
index ac023eef..1d70f953 100644
--- a/eval.c
+++ b/eval.c
@@ -4535,7 +4535,7 @@ static val gather_free_refs(val info_cons, val exc, struct args *args)
{
(void) exc;
- args_normalize(args, 2);
+ args_normalize_least(args, 2);
if (args_count(args) == 2) {
val tag = args_at(args, 1);
@@ -4931,7 +4931,7 @@ static val prod_common(val fun, struct args *lists,
args_decl(args_reset, max(argc, ARGS_MIN));
args_decl(args_work, max(argc, ARGS_MIN));
args_copy(args_reset, lists);
- args_normalize(args_reset, argc);
+ args_normalize_exact(args_reset, argc);
args_copy(args_work, args_reset);
list_collect_decl (out, ptail);
diff --git a/ffi.c b/ffi.c
index 329291ea..70d4bb6d 100644
--- a/ffi.c
+++ b/ffi.c
@@ -4173,7 +4173,7 @@ val ffi_call_wrap(val fptr, val ffi_call_desc, struct args *args)
args = args_copy;
}
- args_normalize(args, n);
+ args_normalize_least(args, n);
if (args->fill < n || args->list)
uw_throwf(error_s, lit("~a: ~s requires ~s arguments"),
diff --git a/lib.c b/lib.c
index c1329346..881df208 100644
--- a/lib.c
+++ b/lib.c
@@ -6064,7 +6064,7 @@ val generic_funcall(val fun, struct args *args_in)
case BUF:
carray:
bug_unless (args->argc >= ARGS_MIN);
- args_normalize(args, 3);
+ args_normalize_least(args, 3);
switch (args->fill) {
case 0:
@@ -6097,7 +6097,7 @@ val generic_funcall(val fun, struct args *args_in)
case COBJ:
if (fun->co.cls == hash_s) {
bug_unless (args->argc >= ARGS_MIN);
- args_normalize(args, 3);
+ args_normalize_least(args, 3);
switch (args->fill) {
case 0:
@@ -6111,7 +6111,7 @@ val generic_funcall(val fun, struct args *args_in)
}
} else if (fun->co.cls == regex_s) {
bug_unless (args->argc >= ARGS_MIN);
- args_normalize(args, 3);
+ args_normalize_least(args, 3);
switch (args->fill) {
case 0:
@@ -6144,7 +6144,7 @@ val generic_funcall(val fun, struct args *args_in)
val *arg = 0;
if (args->argc < fixparam) {
- args_decl(args_copy, fixparam);
+ args_decl(args_copy, max(fixparam, ARGS_MIN));
args_copy_zap(args_copy, args_in);
args = args_copy;
}
@@ -6195,9 +6195,8 @@ val generic_funcall(val fun, struct args *args_in)
val *arg = 0;
if (args->argc < fixparam) {
- args_decl(args_copy, fixparam);
- args_copy_zap(args_copy, args_in);
- args = args_copy;
+ args_decl(args_copy, max(fixparam, ARGS_MIN));
+ args = args_copy_zap(args_copy, args_in);
}
arg = args->arg;
@@ -6207,7 +6206,10 @@ val generic_funcall(val fun, struct args *args_in)
if (args->fill < reqargs)
callerror(fun, lit("missing required arguments"));
- args_clear(args);
+ {
+ args_decl(args_copy, max(args->fill - fixparam, ARGS_MIN));
+ args = args_cat_zap_from(args_copy, args, fixparam);
+ }
switch (fun->f.functype) {
case FINTERP:
@@ -9950,20 +9952,19 @@ val dwim_set(val place_p, val seq, varg vargs)
case COBJ:
if (type(seq) == COBJ) {
if (seq->co.cls == hash_s) {
- cnum nva = args_count(vargs);
-
- if (nva < 2)
- goto fewargs;
+ args_normalize_least(vargs, 3);
- if (nva > 3)
- goto excargs;
-
- if (nva == 2) {
- args_normalize(vargs, 2);
+ switch (vargs->fill) {
+ case 2:
(void) sethash(seq, vargs->arg[0], vargs->arg[1]);
- } else {
- args_normalize(vargs, 3);
+ break;
+ case 3:
+ if (vargs->list)
+ goto excargs;
(void) sethash(seq, vargs->arg[0], vargs->arg[2]);
+ break;
+ default:
+ goto fewargs;
}
return seq;
diff --git a/struct.c b/struct.c
index 35af3136..8c104d08 100644
--- a/struct.c
+++ b/struct.c
@@ -1297,7 +1297,7 @@ static val method_args_fun(val env, varg args)
args_decl(args_call, max(args->fill + 1 + ca_len, ARGS_MIN));
args_add(args_call, strct);
args_add_list(args_call, curried_args);
- args_normalize(args_call, ca_len + 1);
+ args_normalize_exact(args_call, ca_len + 1);
args_cat_zap(args_call, args);
return generic_funcall(fun, args_call);
}
@@ -1379,7 +1379,7 @@ static val umethod_args_fun(val env, struct args *args)
args_decl(args_call, max(args->fill + ca_len, ARGS_MIN));
args_add(args_call, strct);
args_add_list(args_call, curried_args);
- args_normalize(args_call, ca_len + 1);
+ args_normalize_exact(args_call, ca_len + 1);
args_cat_zap_from(args_call, args, index);
struct struct_inst *si = struct_handle(strct, self);