~ chicken-core (chicken-5) da39e738821488c545d17ca2d89db0ad6f65769f
commit da39e738821488c545d17ca2d89db0ad6f65769f Author: Peter Bex <peter@more-magic.net> AuthorDate: Wed Sep 16 13:02:46 2020 +0200 Commit: felix <felix@call-with-current-continuation.org> CommitDate: Wed Sep 16 13:26:43 2020 +0200 Don't re-use argvector when the CPS call's arguments use rest-ops (#1703) Code using restops can be compiled to C code essentially like this: av2 = av; av2[0]=*((C_word*)lf[0]+1); av2[1]=t1; av2[2]=t2; av2[3]=C_get_rest_arg(c,2,av,2,t0); tp(4,av2); But this means the get_rest_arg is taking the newly-written value from av2 instead of from the original av. It would be better if we could assign the argument to a temporary instead so that it precedes the call, but that would require a restructure of the CPS call itself, which is quite complicated. For now this workaround should be fine, as the situation is relatively rare anyway. Signed-off-by: felix <felix@call-with-current-continuation.org> diff --git a/NEWS b/NEWS index 7164df42..87587eeb 100644 --- a/NEWS +++ b/NEWS @@ -34,6 +34,10 @@ - At program cleanup, finalizers are only forced when the live finalizer count is non-zero +- Compiler + - Avoid re-using argvector when inline rest operations are being + used in CPS calls (#1703, thanks to Jakob L. Keuze). + - Build system - Auto-configure at build time on most platforms. Cross-compilation still requires PLATFORM to be set, and it can still be provided diff --git a/c-backend.scm b/c-backend.scm index 1753fea5..67f83691 100644 --- a/c-backend.scm +++ b/c-backend.scm @@ -553,6 +553,16 @@ (expr (car xs) i) (loop (cdr xs))))) + (define (contains-restop? args) + (let loop ((args args)) + (if (null? args) + #f + (let ((node (car args))) + ;; Only rest-car accesses av + (or (eq? (node-class node) '##core#rest-car) + (contains-restop? (node-subexpressions node)) + (loop (cdr args))))))) + (define (push-args args i selfarg) (let* ((n (length args)) (avl (+ n (if selfarg 1 0))) @@ -567,7 +577,8 @@ (cond ((or (not caller-has-av?) ; Argvec missing or (and (< caller-argcount avl) ; known to be too small? - (eq? caller-rest-mode 'none))) + (eq? caller-rest-mode 'none)) + (contains-restop? args)) ; Restops work on original av (gen #t "C_word av2[" avl "];")) ((>= caller-argcount avl) ; Argvec known to be re-usable? (gen #t "C_word *av2=av;")) ; Re-use our own argvector diff --git a/tests/compiler-tests.scm b/tests/compiler-tests.scm index 53275a62..9cda75ef 100644 --- a/tests/compiler-tests.scm +++ b/tests/compiler-tests.scm @@ -461,4 +461,11 @@ (append-map (lambda (a b) (assert (and (= a 3) (= b 4)))) x y)) (outer 3 4) - + +; #1703: argvector re-use interfered with rest-arg optimization +(define reduce (lambda (_l ini) (+ ini 1))) + +(print ((lambda xs (reduce xs (car xs))) 1 2 3)) ;; prints 2 + +(define fold- (lambda xs (reduce xs (car xs)))) +(print (fold- 1 2 3))Trap