shithub: femtolisp

Download patch

ref: 57c066fcdfd6058cf51154ae00e24d6a74f3a192
parent: 642d1e1bd4dadfade218128bcf3eb6980fe7d501
author: JeffBezanson <jeff.bezanson@gmail.com>
date: Mon Jul 20 00:57:17 EDT 2009

simplifying code by eliminating the hybrid stack/heap calling convention
other misc. cleanup


--- a/femtolisp/bootstrap.sh
+++ b/femtolisp/bootstrap.sh
@@ -3,7 +3,7 @@
 cp flisp.boot flisp.boot.bak
 
 echo "Creating stage 0 boot file..."
-#../../branches/interpreter/femtolisp/flisp mkboot0.lsp system.lsp compiler.lsp > flisp.boot
+#../../branches/interpreter/femtolisp/flisp mkboot0.lsp system.lsp compiler.lsp > flisp.boot.new
 ./flisp mkboot0.lsp system.lsp compiler.lsp > flisp.boot.new
 mv flisp.boot.new flisp.boot
 
--- a/femtolisp/builtins.c
+++ b/femtolisp/builtins.c
@@ -35,15 +35,8 @@
     cons_t *c;
     uint32_t i=0;
     while (1) {
-        if (i >= MAX_ARGS) {
-            lst = car_(args[MAX_ARGS]);
-            args[MAX_ARGS] = cdr_(args[MAX_ARGS]);
-            if (!iscons(args[MAX_ARGS])) break;
-        }
-        else {
-            lst = args[i++];
-            if (i >= nargs) break;
-        }
+        lst = args[i++];
+        if (i >= nargs) break;
         if (iscons(lst)) {
             *pcdr = lst;
             c = (cons_t*)ptr(lst);
--- a/femtolisp/compiler.lsp
+++ b/femtolisp/compiler.lsp
@@ -209,6 +209,8 @@
 ; number of non-nulls
 (define (nnn e) (count (lambda (x) (not (null? x))) e))
 
+(define (printable? x) (not (iostream? x)))
+
 (define (compile-sym g env s Is)
   (let ((loc (lookup-sym s env 0 #t)))
     (case (car loc)
@@ -216,7 +218,11 @@
       (closed  (emit g (aref Is 1) (cadr loc) (caddr loc))
 	       ; update index of most distant captured frame
 	       (bcode:cdepth g (- (nnn (cdr env)) 1 (cadr loc))))
-      (else    (emit g (aref Is 2) s)))))
+      (else
+       (if (and (constant? s)
+		(printable? (top-level-value s)))
+	   (emit g :loadv (top-level-value s))
+	   (emit g (aref Is 2) s))))))
 
 (define (compile-if g env tail? x)
   (let ((elsel (make-label g))
@@ -300,8 +306,6 @@
 (define (compile-or g env tail? forms)
   (compile-short-circuit g env tail? forms #f :brt))
 
-(define MAX_ARGS 127)
-
 (define (list-partition l n)
   (define (list-part- l n  i subl acc)
     (cond ((atom? l) (if (> i 0)
@@ -313,24 +317,17 @@
       (error "list-partition: invalid count")
       (reverse! (list-part- l n 0 () ()))))
 
-(define (just-compile-args g lst env)
+(define (make-nested-arglist args n)
+  (cons nconc
+	(map (lambda (l) (cons list l))
+	     (list-partition args n))))
+
+(define (compile-arglist g env lst)
   (for-each (lambda (a)
 	      (compile-in g env #f a))
-	    lst))
+	    lst)
+  (length lst))
 
-(define (compile-arglist g env lst)
-  (let ((argtail (length> lst MAX_ARGS)))
-    (if argtail
-	(begin (just-compile-args g (list-head lst MAX_ARGS) env)
-	       (let ((rest
-		      (cons nconc
-			    (map (lambda (l) (cons list l))
-				 (list-partition argtail MAX_ARGS)))))
-		 (compile-in g env #f rest))
-	       (+ MAX_ARGS 1))
-	(begin (just-compile-args g lst env)
-	       (length lst)))))
-
 (define (argc-error head count)
   (error (string "compile error: " head " expects " count
 		 (if (= count 1)
@@ -342,7 +339,7 @@
     (if (and (pair? head)
 	     (eq? (car head) 'lambda)
 	     (list? (cadr head))
-	     (not (length> (cadr head) MAX_ARGS)))
+	     (not (length> (cadr head) 255)))
 	(compile-let  g env tail? x)
 	(compile-call g env tail? x))))
 
@@ -375,6 +372,33 @@
     (lambda (b)
       (get b2i b #f))))
 
+(define (compile-builtin-call g env tail? x head b nargs)
+  (let ((count (get arg-counts b #f)))
+    (if (and count
+	     (not (length= (cdr x) count)))
+	(argc-error head count))
+    (case b  ; handle special cases of vararg builtins
+      (:list (if (= nargs 0) (emit g :loadnil) (emit g b nargs)))
+      (:+    (cond ((= nargs 0) (emit g :load0))
+		   ((= nargs 2) (emit g :add2))
+		   (else (emit g b nargs))))
+      (:-    (cond ((= nargs 0) (argc-error head 1))
+		   ((= nargs 1) (emit g :neg))
+		   ((= nargs 2) (emit g :sub2))
+		   (else (emit g b nargs))))
+      (:*    (if (= nargs 0) (emit g :load1)
+		 (emit g b nargs)))
+      (:/    (if (= nargs 0)
+		 (argc-error head 1)
+		 (emit g b nargs)))
+      (:vector   (if (= nargs 0)
+		     (emit g :loadv [])
+		     (emit g b nargs)))
+      (:apply    (if (< nargs 2)
+		     (argc-error head 2)
+		     (emit g (if tail? :tapply :apply) nargs)))
+      (else      (emit g b)))))
+
 (define (compile-call g env tail? x)
   (let ((head  (car x)))
     (let ((head
@@ -385,38 +409,19 @@
 		    (builtin? (top-level-value head)))
 	       (top-level-value head)
 	       head)))
-      (let ((b (and (builtin? head)
-		    (builtin->instruction head))))
-	(if (not b)
-	    (compile-in g env #f head))
-	(let ((nargs (compile-arglist g env (cdr x))))
-	  (if b
-	      (let ((count (get arg-counts b #f)))
-		(if (and count
-			 (not (length= (cdr x) count)))
-		    (argc-error head count))
-		(case b  ; handle special cases of vararg builtins
-		  (:list (if (= nargs 0) (emit g :loadnil) (emit g b nargs)))
-		  (:+    (cond ((= nargs 0) (emit g :load0))
-			       ((= nargs 2) (emit g :add2))
-			       (else (emit g b nargs))))
-		  (:-    (cond ((= nargs 0) (argc-error head 1))
-			       ((= nargs 1) (emit g :neg))
-			       ((= nargs 2) (emit g :sub2))
-			       (else (emit g b nargs))))
-		  (:*    (if (= nargs 0) (emit g :load1)
-			     (emit g b nargs)))
-		  (:/    (if (= nargs 0)
-			     (argc-error head 1)
-			     (emit g b nargs)))
-		  (:vector   (if (= nargs 0)
-				 (emit g :loadv [])
-				 (emit g b nargs)))
-		  (:apply    (if (< nargs 2)
-				 (argc-error head 2)
-				 (emit g (if tail? :tapply :apply) nargs)))
-		  (else      (emit g b))))
-	      (emit g (if tail? :tcall :call) nargs)))))))
+      (if (length> (cdr x) 255)
+	  ; argument count is a uint8, so for more than 255 arguments
+	  ; we use apply on a list built from sublists that fit the limit
+	  (compile-in g env tail?
+		      `(#.apply ,head ,(make-nested-arglist (cdr x) 255)))
+	  (let ((b (and (builtin? head)
+			(builtin->instruction head))))
+	    (if (not b)
+		(compile-in g env #f head))
+	    (let ((nargs (compile-arglist g env (cdr x))))
+	      (if b
+		  (compile-builtin-call g env tail? x head b nargs)
+		  (emit g (if tail? :tcall :call) nargs))))))))
 
 (define (expand-define form body)
   (if (symbol? form)
@@ -514,7 +519,7 @@
 		      'lambda
 		      (lastcdr f))))
 	(cond ((not (null? let?))      (emit g :let))
-	      ((length> args MAX_ARGS) (emit g (if (null? (lastcdr args))
+	      ((length> args 255)      (emit g (if (null? (lastcdr args))
 						   :largc :lvargc)
 					     (length args)))
 	      ((null? (lastcdr args))  (emit g :argc  (length args)))
--- a/femtolisp/cvalues.c
+++ b/femtolisp/cvalues.c
@@ -464,8 +464,6 @@
         argcount("array", nargs, 1);
 
     cnt = nargs - 1;
-    if (nargs > MAX_ARGS)
-        cnt += (llength(args[MAX_ARGS])-1);
     fltype_t *type = get_array_type(args[0]);
     elsize = type->elsz;
     sz = elsize * cnt;
--- a/femtolisp/flisp.boot
+++ b/femtolisp/flisp.boot
@@ -1,1 +1,1 @@
-(zero? #function("7000r1~`W;" [] zero?) vector.map #function("8000r2c0e1\x7f31u42;" [#function("8000vc0e1~31u42;" [#function(":000v`\x80azc0qw2~;" [#function(":000r1\x80~i20i21~[31\\;" [])]) vector.alloc]) length] vector.map) vector->list #function("9000r1c0e1~31_u43;" [#function(":000va~c0qw2\x7f;" [#function("8000r1i10\x80~z[\x81Ko01;" [])]) length] vector->list) values #function("9000s0~F16602~NA650~M;\x80~K;" [] #5=[(*values*) ()]) untrace #function("8000r1c0e1~31u42;" [#function("9000ve0~316@0e1\x80e2~31b2[42;^;" [traced? set-top-level-value! function:vals]) top-level-value] untrace) traced? #function("8000r1e0~31e0\x8031>;" [function:code] [#function("\xb9000s0e0c1~K312c2~x2;" [println x #.apply]) ()]) trace #function("8000r1c0e1~31u322c2;" [#function("8000vc0e130u42;" [#function("?000ve0\x8031@6a0e1i10e2c3~c4c5c6c7i10L2~L3L2c8c7\x80L2~L3L3L33142;^;" [traced? set-top-level-value! eval lambda begin println cons quote apply]) gensym]) top-level-value ok] trace) to-proper #function("8000r1~A640~;~?660~L1;~Me0~N31K;" [to-proper] to-proper) table.values #function("9000r1e0c1_~43;" [table.foldl #function("7000r3\x7fg2K;" [])] table.values) table.pairs #function("9000r1e0c1_~43;" [table.foldl #function("7000r3~\x7fKg2K;" [])] table.pairs) table.keys #function("9000r1e0c1_~43;" [table.foldl #function("7000r3~g2K;" [])] table.keys) table.invert #function("8000r1c0e130u42;" [#function("9000ve0c1q_\x80332~;" [table.foldl #function("9000r3e0\x80\x7f~43;" [put!])]) table] table.invert) table.foreach #function("9000r2e0c1q_\x7f43;" [table.foldl #function("8000r3\x80~\x7f322];" [])] table.foreach) table.clone #function("8000r1c0e130u42;" [#function("9000ve0c1q_\x80332~;" [table.foldl #function("9000r3e0\x80~\x7f43;" [put!])]) table] table.clone) symbol-syntax #function("9000r1e0e1~^43;" [get *syntax-environment*] symbol-syntax) string.trim #function("9000r3c0^^u43;" [#function("8000vc0qm02c1qm12c2e3\x8031u42;" [#function(";000r4g2g3X16?02e0\x7fe1~g232326A0\x80~\x7fe2~g232g344;g2;" [string.find string.char string.inc] trim-start) #function("<000r3e0g2`3216D02e1\x7fe2~e3~g23232326?0\x81~\x7fe3~g23243;g2;" [> string.find string.char string.dec] trim-end) #function("<000ve0i10\x80i10i11`~34\x81i10i12~3343;" [string.sub]) length])] string.trim) string.tail #function(";000r2e0~e1~`\x7f3342;" [string.sub string.inc] string.tail) string.rpad #function("<000r3e0~e1g2\x7fe2~31z3242;" [string string.rep string.count] string.rpad) string.rep #function(";000r2\x7fb4X6`0e0\x7f`32650c1;\x7faW680e2~41;\x7fb2W690e2~~42;e2~~~43;e3\x7f316@0e2~e4~\x7faz3242;e4e2~~32\x7fb2U242;" [<= "" string odd? string.rep] string.rep) string.map #function("9000r2c0e130e2\x7f31u43;" [#function("8000vc0`u322e1~41;" [#function(";000v^~\x81X6S02e0\x80i10e1i11~3231322e2i11~32m05\x0b/;" [io.putc string.char string.inc]) io.tostring!]) buffer length] string.map) string.lpad #function(";000r3e0e1g2\x7fe2~31z32~42;" [string string.rep string.count] string.lpad) string.join #function("8000r2~A650c0;c1e230u42;" ["" #function("8000ve0~\x80M322e1c2q\x80N322e3~41;" [io.write for-each #function("8000r1e0\x80i11322e0\x80~42;" [io.write]) io.tostring!]) buffer] string.join) simple-sort #function("8000r1~A17602~NA640~;c0~Mu42;" [#function("9000vc0e1c2q\x80N32u42;" [#function(":000ve0e1~M31\x80L1e1~N3143;" [nconc simple-sort]) separate #function("7000r1~\x80X;" [])])] simple-sort) set-syntax! #function("9000r2e0e1~\x7f43;" [put! *syntax-environment*] set-syntax!) separate #function(":000r2\x80~\x7f__44;" [] #0=[#function(";000r4\x7fA680g2g3K;~\x7fM316@0\x80~\x7fN\x7fMg2Kg344;\x80~\x7fNg2\x7fMg3K44;" [] #0#) ()]) self-evaluating? #function("8000r1~?16602~C@17K02e0~3116A02~C16:02~e1~31<;" [constant? top-level-value] self-evaluating?) reverse! #function("8000r1c0_u42;" [#function("9000v^\x80F6C02\x80N\x80~\x80m02P2o005\x1c/2~;" [])] reverse!) reverse #function("9000r1e0e1_~43;" [foldl cons] reverse) revappend #function("8000r2e0e1~31\x7f42;" [nconc reverse] revappend) repl #function("9000r0c0^^u43;" [#function("6000vc0m02c1qm12\x7f302e240;" [#function("8000r0e0c1312e2e3312c4c5c6tu42;"
\ No newline at end of file
+(zero? #function("7000r1~`W;" [] zero?) vector.map #function("8000r2c0e1\x7f31u42;" [#function("8000vc0e1~31u42;" [#function(":000v`\x80azc0qw2~;" [#function(":000r1\x80~i20i21~[31\\;" [])]) vector.alloc]) length] vector.map) vector->list #function("9000r1c0e1~31_u43;" [#function(":000va~c0qw2\x7f;" [#function("8000r1i10\x80~z[\x81Ko01;" [])]) length] vector->list) values #function("9000s0~F16602~NA650~M;\x80~K;" [] #5=[(*values*) ()]) untrace #function("8000r1c0e1~31u42;" [#function("9000ve0~316@0e1\x80e2~31b2[42;^;" [traced? set-top-level-value! function:vals]) top-level-value] untrace) traced? #function("8000r1e0~31e0\x8031>;" [function:code] [#function(":000s0e0c1~K312c2~x2;" [println x #.apply]) ()]) trace #function("8000r1c0e1~31u322c2;" [#function("8000vc0e130u42;" [#function("?000ve0\x8031@6a0e1i10e2c3~c4c5c6c7i10L2~L3L2c8c7\x80L2~L3L3L33142;^;" [traced? set-top-level-value! eval lambda begin println cons quote apply]) gensym]) top-level-value ok] trace) to-proper #function("8000r1~A640~;~?660~L1;~Me0~N31K;" [to-proper] to-proper) table.values #function("9000r1e0c1_~43;" [table.foldl #function("7000r3\x7fg2K;" [])] table.values) table.pairs #function("9000r1e0c1_~43;" [table.foldl #function("7000r3~\x7fKg2K;" [])] table.pairs) table.keys #function("9000r1e0c1_~43;" [table.foldl #function("7000r3~g2K;" [])] table.keys) table.invert #function("8000r1c0e130u42;" [#function("9000ve0c1q_\x80332~;" [table.foldl #function("9000r3e0\x80\x7f~43;" [put!])]) table] table.invert) table.foreach #function("9000r2e0c1q_\x7f43;" [table.foldl #function("8000r3\x80~\x7f322];" [])] table.foreach) table.clone #function("8000r1c0e130u42;" [#function("9000ve0c1q_\x80332~;" [table.foldl #function("9000r3e0\x80~\x7f43;" [put!])]) table] table.clone) symbol-syntax #function("9000r1e0e1~^43;" [get *syntax-environment*] symbol-syntax) string.trim #function("9000r3c0^^u43;" [#function("8000vc0qm02c1qm12c2e3\x8031u42;" [#function(";000r4g2g3X16?02e0\x7fe1~g232326A0\x80~\x7fe2~g232g344;g2;" [string.find string.char string.inc] trim-start) #function("<000r3e0g2`3216D02e1\x7fe2~e3~g23232326?0\x81~\x7fe3~g23243;g2;" [> string.find string.char string.dec] trim-end) #function("<000ve0i10\x80i10i11`~34\x81i10i12~3343;" [string.sub]) length])] string.trim) string.tail #function(";000r2e0~e1~`\x7f3342;" [string.sub string.inc] string.tail) string.rpad #function("<000r3e0~e1g2\x7fe2~31z3242;" [string string.rep string.count] string.rpad) string.rep #function(";000r2\x7fb4X6`0e0\x7f`32650c1;\x7faW680e2~41;\x7fb2W690e2~~42;e2~~~43;e3\x7f316@0e2~e4~\x7faz3242;e4e2~~32\x7fb2U242;" [<= "" string odd? string.rep] string.rep) string.map #function("9000r2c0e130e2\x7f31u43;" [#function("8000vc0`u322e1~41;" [#function(";000v^~\x81X6S02e0\x80i10e1i11~3231322e2i11~32m05\x0b/;" [io.putc string.char string.inc]) io.tostring!]) buffer length] string.map) string.lpad #function(";000r3e0e1g2\x7fe2~31z32~42;" [string string.rep string.count] string.lpad) string.join #function("8000r2~A650c0;c1e230u42;" ["" #function("8000ve0~\x80M322e1c2q\x80N322e3~41;" [io.write for-each #function("8000r1e0\x80i11322e0\x80~42;" [io.write]) io.tostring!]) buffer] string.join) simple-sort #function("8000r1~A17602~NA640~;c0~Mu42;" [#function("9000vc0e1c2q\x80N32u42;" [#function(":000ve0e1~M31\x80L1e1~N3143;" [nconc simple-sort]) separate #function("7000r1~\x80X;" [])])] simple-sort) set-syntax! #function("9000r2e0e1~\x7f43;" [put! *syntax-environment*] set-syntax!) separate #function(":000r2\x80~\x7f__44;" [] #0=[#function(";000r4\x7fA680g2g3K;~\x7fM316@0\x80~\x7fN\x7fMg2Kg344;\x80~\x7fNg2\x7fMg3K44;" [] #0#) ()]) self-evaluating? #function("8000r1~?16602~C@17K02e0~3116A02~C16:02~e1~31<;" [constant? top-level-value] self-evaluating?) reverse! #function("8000r1c0_u42;" [#function("9000v^\x80F6C02\x80N\x80~\x80m02P2o005\x1c/2~;" [])] reverse!) reverse #function("9000r1e0c1_~43;" [foldl #.cons] reverse) revappend #function("8000r2e0e1~31\x7f42;" [nconc reverse] revappend) repl #function("9000r0c0^^u43;" [#function("6000vc0m02c1qm12\x7f302e240;" [#function("8000r0e0c1312e2e3312c4c5c6tu42;" 
\ No newline at end of file
--- a/femtolisp/flisp.c
+++ b/femtolisp/flisp.c
@@ -578,12 +578,21 @@
         gc(0);
 }
 
+static void grow_stack()
+{
+    size_t newsz = N_STACK + (N_STACK>>1);
+    value_t *ns = realloc(Stack, newsz*sizeof(value_t));
+    if (ns == NULL)
+        lerror(MemoryError, "stack overflow");
+    Stack = ns;
+    N_STACK = newsz;
+}
+
 // utils ----------------------------------------------------------------------
 
 // apply function with n args on the stack
 static value_t _applyn(uint32_t n)
 {
-    assert(n <= MAX_ARGS+1);
     value_t f = Stack[SP-n-1];
     uint32_t saveSP = SP;
     value_t v;
@@ -607,10 +616,8 @@
 
     PUSH(f);
     while (iscons(v)) {
-        if ((SP-n-1) == MAX_ARGS) {
-            PUSH(v);
-            break;
-        }
+        if (SP >= N_STACK)
+            grow_stack();
         PUSH(car_(v));
         v = cdr_(v);
     }
@@ -622,12 +629,13 @@
 
 value_t applyn(uint32_t n, value_t f, ...)
 {
-    assert(n <= MAX_ARGS);
     va_list ap;
     va_start(ap, f);
     size_t i;
 
     PUSH(f);
+    while (SP+n > N_STACK)
+        grow_stack();
     for(i=0; i < n; i++) {
         value_t a = va_arg(ap, value_t);
         PUSH(a);
@@ -644,6 +652,8 @@
     uint32_t si = SP;
     size_t i;
 
+    while (SP+n > N_STACK)
+        grow_stack();
     for(i=0; i < n; i++) {
         value_t a = va_arg(ap, value_t);
         PUSH(a);
@@ -715,7 +725,7 @@
         c->cdr = tagptr(c+1, TAG_CONS);
         c++;
     }
-    if (star || nargs > MAX_ARGS)
+    if (star)
         (c-2)->cdr = (c-1)->car;
     else
         (c-1)->cdr = NIL;
@@ -805,18 +815,8 @@
 #define DISPATCH goto dispatch
 #endif
 
-static void grow_stack()
-{
-    size_t newsz = N_STACK + (N_STACK>>1);
-    value_t *ns = realloc(Stack, newsz*sizeof(value_t));
-    if (ns == NULL)
-        lerror(MemoryError, "stack overflow");
-    Stack = ns;
-    N_STACK = newsz;
-}
-
 /*
-  stack on entry: <func>  <up to MAX_ARGS args...>  <arglist if nargs>MAX_ARGS>
+  stack on entry: <func>  <nargs args...>
   caller's responsibility:
   - put the stack in this state
   - provide arg count
@@ -886,18 +886,10 @@
             NEXT_OP;
         OP(OP_VARGC)
             i = *ip++;
+        do_vargc:
             s = (fixnum_t)nargs - (fixnum_t)i;
             if (s > 0) {
                 v = list(&Stack[bp+i], s);
-                if (nargs > MAX_ARGS) {
-                    if (s == 1) {
-                        v = car_(v);
-                    }
-                    else {
-                        c = (cons_t*)curheap;
-                        (c-2)->cdr = (c-1)->car;
-                    }
-                }
                 Stack[bp+i] = v;
                 if (s > 1) {
                     Stack[bp+i+1] = Stack[bp+nargs+0];
@@ -923,39 +915,17 @@
             nargs = i+1;
             NEXT_OP;
         OP(OP_LARGC)
-        OP(OP_LVARGC)
-            // move extra arguments from list to stack
-            i = GET_INT32(ip); ip+=4;
-            e = Stack[curr_frame-5];  // cloenv
-            n = Stack[curr_frame-4];  // prev curr_frame
-            POPN(5);
-            if (nargs > MAX_ARGS) {
-                v = POP();  // list of rest args
-                nargs--;
-            }
-            else v = NIL;
-            while (nargs < i) {
-                if (!iscons(v))
+            n = GET_INT32(ip); ip+=4;
+            if (nargs != n) {
+                if (nargs > n)
+                    lerror(ArgError, "apply: too many arguments");
+                else
                     lerror(ArgError, "apply: too few arguments");
-                PUSH(car_(v));
-                nargs++;
-                v = cdr_(v);
             }
-            if (ip[-5] == OP_LVARGC) {
-                PUSH(v);
-                nargs++;
-            }
-            else {
-                if (iscons(v))
-                    lerror(ArgError, "apply: too many arguments");
-            }
-            PUSH(e);
-            PUSH(n);
-            PUSH(nargs);
-            SP++;//PUSH(0);
-            PUSH(0);
-            curr_frame = SP;
             NEXT_OP;
+        OP(OP_LVARGC)
+            i = GET_INT32(ip); ip+=4;
+            goto do_vargc;
         OP(OP_LET)
             // last arg is closure environment to use
             nargs--;
@@ -1166,15 +1136,10 @@
             n = *ip++;
         apply_apply:
             v = POP();     // arglist
-            if (n > MAX_ARGS) {
-                v = apply_liststar(v, 1);
-            }
             n = SP-(n-2);  // n-2 == # leading arguments not in the list
             while (iscons(v)) {
-                if (SP-n == MAX_ARGS) {
-                    PUSH(v);
-                    break;
-                }
+                if (SP >= N_STACK)
+                    grow_stack();
                 PUSH(car_(v));
                 v = cdr_(v);
             }
@@ -1187,7 +1152,6 @@
         apply_add:
             s = 0;
             i = SP-n;
-            if (n > MAX_ARGS) goto add_ovf;
             for (; i < SP; i++) {
                 if (isfixnum(Stack[i])) {
                     s += numval(Stack[i]);
@@ -1265,13 +1229,11 @@
         apply_mul:
             accum = 1;
             i = SP-n;
-            if (n > MAX_ARGS) goto mul_ovf;
             for (; i < SP; i++) {
                 if (isfixnum(Stack[i])) {
                     accum *= numval(Stack[i]);
                 }
                 else {
-                mul_ovf:
                     v = fl_mul_any(&Stack[i], SP-i, accum);
                     break;
                 }
@@ -1343,24 +1305,11 @@
         OP(OP_VECTOR)
             n = *ip++;
         apply_vector:
-            if (n > MAX_ARGS) {
-                i = llength(Stack[SP-1])-1;
-            }
-            else i = 0;
-            v = alloc_vector(n+i, 0);
+            v = alloc_vector(n, 0);
             if (n) {
                 memcpy(&vector_elt(v,0), &Stack[SP-n], n*sizeof(value_t));
-                e = POP();
-                POPN(n-1);
+                POPN(n);
             }
-            if (n > MAX_ARGS) {
-                i = n-1;
-                while (iscons(e)) {
-                    vector_elt(v,i) = car_(e);
-                    i++;
-                    e = cdr_(e);
-                }
-            }
             PUSH(v);
             NEXT_OP;
 
@@ -1684,7 +1633,6 @@
             break;
 
         case OP_TAPPLY: case OP_APPLY:
-            if (sp+MAX_ARGS+1 > maxsp) maxsp = sp+MAX_ARGS+1;
             n = *ip++;
             sp -= (n-1);
             break;
@@ -1860,15 +1808,8 @@
     fl_gc_handle(&lastcons);
     uint32_t i=0;
     while (1) {
-        if (i >= MAX_ARGS) {
-            lst = car_(args[MAX_ARGS]);
-            args[MAX_ARGS] = cdr_(args[MAX_ARGS]);
-            if (!iscons(args[MAX_ARGS])) break;
-        }
-        else {
-            lst = args[i++];
-            if (i >= nargs) break;
-        }
+        lst = args[i++];
+        if (i >= nargs) break;
         if (iscons(lst)) {
             lst = FL_COPYLIST(lst);
             if (first == NIL)
@@ -1893,10 +1834,6 @@
 {
     if (nargs == 1) return args[0];
     else if (nargs == 0) argcount("list*", nargs, 1);
-    if (nargs > MAX_ARGS) {
-        args[MAX_ARGS] = apply_liststar(args[MAX_ARGS], 1);
-        return list(args, nargs);
-    }
     return _list(args, nargs, 1);
 }
 
--- a/femtolisp/flisp.h
+++ b/femtolisp/flisp.h
@@ -102,22 +102,13 @@
 void fl_gc_handle(value_t *pv);
 void fl_free_gc_handles(int n);
 
-// maximum number of explicit arguments. the 128th arg is a list of rest args.
-// the largest value nargs can have is MAX_ARGS+1
-#define MAX_ARGS 127
-
 #include "opcodes.h"
 
 // utility for iterating over all arguments in a builtin
 // i=index, i0=start index, arg = var for each arg, args = arg array
 // assumes "nargs" is the argument count
-// modifies args[MAX_ARGS] when nargs==MAX_ARGS+1
-#define FOR_ARGS(i, i0, arg, args)                                      \
-    for(i=i0; (((size_t)i<nargs ||                                      \
-                (i>MAX_ARGS && iscons(args[MAX_ARGS]))) &&              \
-               ((i>=MAX_ARGS?(arg=car_(args[MAX_ARGS]),                 \
-                              args[MAX_ARGS]=cdr_(args[MAX_ARGS])) :    \
-                 (arg = args[i])) || 1)); i++)
+#define FOR_ARGS(i, i0, arg, args)     \
+    for(i=i0; ((size_t)i)<nargs && ((arg=args[i]) || 1); i++)
 
 #define N_BUILTINS ((int)N_OPCODES)
 
--- a/femtolisp/iostream.c
+++ b/femtolisp/iostream.c
@@ -171,7 +171,7 @@
 
 static void do_ioprint(value_t *args, u_int32_t nargs, char *fname)
 {
-    if (nargs < 2 || nargs > MAX_ARGS)
+    if (nargs < 2)
         argcount(fname, nargs, 2);
     ios_t *s = toiostream(args[0], fname);
     unsigned i;
--- a/femtolisp/system.lsp
+++ b/femtolisp/system.lsp
@@ -309,6 +309,11 @@
     (or (and (pair? x) (or (eq (car x) '*comma-at*)
 			   (eq (car x) '*comma-dot*)))
 	(eq x '*comma*)))
+  ; bracket without splicing
+  (define (bq-bracket1 x)
+    (if (and (pair? x) (eq (car x) '*comma*))
+	(cadr x)
+	(bq-process x)))
   (cond ((self-evaluating? x)
          (if (vector? x)
              (let ((body (bq-process (vector->list x))))
@@ -344,12 +349,6 @@
         ((eq (car x) '*comma-at*)   (list 'copy-list (cadr x)))
         ((eq (car x) '*comma-dot*)  (cadr x))
         (#t                         (list list (bq-process x)))))
-
-; bracket without splicing
-(define (bq-bracket1 x)
-  (if (and (pair? x) (eq (car x) '*comma*))
-      (cadr x)
-      (bq-process x)))
 
 ; standard macros -------------------------------------------------------------
 
--- a/femtolisp/table.c
+++ b/femtolisp/table.c
@@ -84,8 +84,6 @@
 value_t fl_table(value_t *args, uint32_t nargs)
 {
     size_t cnt = (size_t)nargs;
-    if (nargs > MAX_ARGS)
-        cnt += (llength(args[MAX_ARGS])-1);
     if (cnt & 1)
         lerror(ArgError, "table: arguments must come in pairs");
     value_t nt;
--- a/femtolisp/todo
+++ b/femtolisp/todo
@@ -1042,7 +1042,8 @@
   * stack traces and better debugging support
   - make maxstack calculation robust against invalid bytecode
 * improve internal define
-- try removing MAX_ARGS trickery
+* try removing MAX_ARGS trickery
+- apply optimization, avoid redundant list copying calling vararg fns
 - let eversion
 * lambda lifting
 * let optimization
--- a/femtolisp/unittest.lsp
+++ b/femtolisp/unittest.lsp
@@ -98,6 +98,8 @@
 ; long argument lists
 (assert (= (apply + (iota 100000)) 4999950000))
 
+(define MAX_ARGS 255)
+
 (define as (apply list* (map-int (lambda (x) (gensym)) (+ MAX_ARGS 1))))
 (define f (compile `(lambda ,as ,(lastcdr as))))
 (assert (equal? (apply f (iota (+ MAX_ARGS 0))) `()))