From 6ec69f537598e81cbb678ba5387c55c9274249e5 Mon Sep 17 00:00:00 2001 From: JeffBezanson Date: Thu, 11 Jun 2009 00:34:50 +0000 Subject: [PATCH] optimizations to map and case several optimizations to the compiler itself, mostly involving emit and encode-byte-code experimental, very basic profiling utility --- femtolisp/compiler.lsp | 137 +++++++++++++++++++++-------------------- femtolisp/flisp.boot | 16 ++--- femtolisp/flisp.c | 9 +-- femtolisp/system.lsp | 14 ++++- femtolisp/test.lsp | 32 ++++++++++ femtolisp/torture.scm | 15 +++-- 6 files changed, 138 insertions(+), 85 deletions(-) diff --git a/femtolisp/compiler.lsp b/femtolisp/compiler.lsp index e083669..44dde00 100644 --- a/femtolisp/compiler.lsp +++ b/femtolisp/compiler.lsp @@ -60,35 +60,38 @@ (prog1 nconst (aset! b 2 (+ nconst 1))))))) (define (emit e inst . args) - (if (memq inst '(:loadv :loadg :setg)) - (set! args (list (bcode:indexfor e (car args))))) - (let ((longform - (assq inst '((:loadv :loadv.l) (:loadg :loadg.l) (:setg :setg.l) - (:loada :loada.l) (:seta :seta.l))))) - (if (and longform - (> (car args) 255)) - (set! inst (cadr longform)))) - (let ((longform - (assq inst '((:loadc :loadc.l) (:setc :setc.l))))) - (if (and longform - (or (> (car args) 255) - (> (cadr args) 255))) - (set! inst (cadr longform)))) - (if (eq? inst :loada) - (cond ((equal? args '(0)) - (set! inst :loada0) - (set! args ())) - ((equal? args '(1)) - (set! inst :loada1) - (set! args ())))) - (if (eq? inst :loadc) - (cond ((equal? args '(0 0)) - (set! inst :loadc00) - (set! args ())) - ((equal? args '(0 1)) - (set! inst :loadc01) - (set! args ())))) - (aset! e 0 (nreconc (cons inst args) (aref e 0))) + (if (null? args) + (aset! e 0 (cons inst (aref e 0))) + (begin + (if (memq inst '(:loadv :loadg :setg)) + (set! args (list (bcode:indexfor e (car args))))) + (let ((longform + (assq inst '((:loadv :loadv.l) (:loadg :loadg.l) (:setg :setg.l) + (:loada :loada.l) (:seta :seta.l))))) + (if (and longform + (> (car args) 255)) + (set! inst (cadr longform)))) + (let ((longform + (assq inst '((:loadc :loadc.l) (:setc :setc.l))))) + (if (and longform + (or (> (car args) 255) + (> (cadr args) 255))) + (set! inst (cadr longform)))) + (if (eq? inst :loada) + (cond ((equal? args '(0)) + (set! inst :loada0) + (set! args ())) + ((equal? args '(1)) + (set! inst :loada1) + (set! args ())))) + (if (eq? inst :loadc) + (cond ((equal? args '(0 0)) + (set! inst :loadc00) + (set! args ())) + ((equal? args '(0 1)) + (set! inst :loadc01) + (set! args ())))) + (aset! e 0 (nreconc (cons inst args) (aref e 0))))) e) (define (make-label e) (gensym)) @@ -99,8 +102,11 @@ (define (encode-byte-code e) (let* ((cl (reverse! e)) (v (list->vector cl)) - (long? (>= (+ (length v) - (* 3 (count (lambda (i) + (long? (>= (+ (length v) ; 1 byte for each entry, plus... + ; at most half the entries in this vector can be + ; instructions accepting 32-bit arguments + (* 3 (div0 (length v) 2)) + #;(* 3 (count (lambda (i) (memq i '(:loadv.l :loadg.l :setg.l :loada.l :seta.l :loadc.l :setc.l :jmp :brt :brf @@ -112,7 +118,8 @@ (label-to-loc (table)) (fixup-to-label (table)) (bcode (buffer)) - (vi #f)) + (vi #f) + (nxt #f)) (while (< i n) (begin (set! vi (aref v i)) @@ -123,46 +130,44 @@ (io.write bcode (byte (get Instructions - (if (and long? - (memq vi '(:jmp :brt :brf))) + (if long? (case vi (:jmp :jmp.l) (:brt :brt.l) - (:brf :brf.l)) + (:brf :brf.l) + (else vi)) vi)))) (set! i (+ i 1)) - (if (< i n) - (let ((nxt (aref v i))) - (case vi - ((:loadv.l :loadg.l :setg.l :loada.l :seta.l :largc - :lvargc) - (io.write bcode (uint32 nxt)) - (set! i (+ i 1))) - - ((:loada :seta :call :tcall :loadv :loadg :setg - :list :+ :- :* :/ :vector :argc :vargc :loadi8 - :apply :tapply) - (io.write bcode (uint8 nxt)) - (set! i (+ i 1))) - - ((:loadc :setc) ; 2 uint8 args - (io.write bcode (uint8 nxt)) - (set! i (+ i 1)) - (io.write bcode (uint8 (aref v i))) - (set! i (+ i 1))) + (set! nxt (if (< i n) (aref v i) #f)) + (cond ((memq vi '(:jmp :brf :brt)) + (put! fixup-to-label (sizeof bcode) nxt) + (io.write bcode ((if long? uint32 uint16) 0)) + (set! i (+ i 1))) + ((number? nxt) + (case vi + ((:loadv.l :loadg.l :setg.l :loada.l :seta.l + :largc :lvargc) + (io.write bcode (uint32 nxt)) + (set! i (+ i 1))) + + ((:loadc :setc) ; 2 uint8 args + (io.write bcode (uint8 nxt)) + (set! i (+ i 1)) + (io.write bcode (uint8 (aref v i))) + (set! i (+ i 1))) + + ((:loadc.l :setc.l) ; 2 uint32 args + (io.write bcode (uint32 nxt)) + (set! i (+ i 1)) + (io.write bcode (uint32 (aref v i))) + (set! i (+ i 1))) + + (else + ; other number arguments are always uint8 + (io.write bcode (uint8 nxt)) + (set! i (+ i 1))))) + (else #f)))))) - ((:loadc.l :setc.l) ; 2 uint32 args - (io.write bcode (uint32 nxt)) - (set! i (+ i 1)) - (io.write bcode (uint32 (aref v i))) - (set! i (+ i 1))) - - ((:jmp :brf :brt) - (put! fixup-to-label (sizeof bcode) nxt) - (io.write bcode ((if long? uint32 uint16) 0)) - (set! i (+ i 1))) - - (else #f)))))))) (table.foreach (lambda (addr labl) (begin (io.seek bcode addr) diff --git a/femtolisp/flisp.boot b/femtolisp/flisp.boot index b720587..20a2d2d 100644 --- a/femtolisp/flisp.boot +++ b/femtolisp/flisp.boot @@ -105,7 +105,7 @@ map-int map! #function("r2\x7f^\x7fF6I02\x7f~\x7fM31O2\x7fNm15402;" []) map -#function("r2\x7f?690\x7f;~\x7fM31e0~\x7fN32K;" [map]) +#function("r2c0__L1u43;" [#function("v\x7fm02^\x81F6Q02\x7f\x80\x81M31_KPNm12\x81No015602~N;" [])]) make-system-image #function("r1c0e1~e2e3e434c5e6u44;" [#function("v^k02c1c2qu42;" [*print-pretty* #function("vc0qc1qt~302;" [#function("r0e0c1qe2e3e430313142;" [for-each #function("r1~E16h02e0~31@16h02e1~31G@16h02e2~i1132@16h02e3e1~3131@6\x950e4i10~322e5i10c6322e4i10e1~31322e5i10c642;^;" [constant? top-level-value memq iostream? io.print io.write "\n"]) reverse! simple-sort environment]) #function("r1\x80302e0~41;" [raise])]) #function("r0e0\x80312i02k1;" [io.close *print-pretty*])]) file :write :create :truncate (*linefeed* *directory-separator* *argv* that *print-pretty* *print-width* *print-readably*) *print-pretty*]) make-label @@ -181,15 +181,15 @@ eval error #function("s0e0c1~K41;" [raise error]) encode-byte-code -#function("r1c0e1~31u42;" [#function("vc0e1~31u42;" [#function("vc0e1e2~31b3e3c4q\x8032T2yc532u42;" [#function("vc0e1\x8031`e230e230e330^u47;" [#function("v^\x7f~X6\xb102i10\x7f[m52g5e0<6f0e1g2i10\x7fay[e2g431332\x7fb2ym15\xae0e3g4e4e5e6\x8016~02e7g5c8326\x8b0c9g5u325\x8d0g53231322\x7faym12\x7f~X6\xad0c:i10\x7f[u325\xae0^5202e;c= length count #function("r1e0~c142;" [memq (:loadv.l :loadg.l :setg.l :loada.l :seta.l :loadc.l :setc.l :jmp :brt :brf :largc :lvargc)]) 65536]) list->vector]) reverse!]) +#function("r1c0e1~31u42;" [#function("vc0e1~31u42;" [#function("vc0e1e2~31b3e2~31b2VT2yc332u42;" [#function("vc0e1\x8031`e230e230e330^^u48;" [#function("v^\x7f~X6\xea02i10\x7f[m52g5e0<6f0e1g2i10\x7fay[e2g431332\x7fb2ym15\xe70e3g4e4e5e6\x806~0c7g5u325\x800g53231322\x7faym12\x7f~X6\x9b0i10\x7f[5\x9c0^m62e8g5c9326\xd60e1g3e2g431g6332e3g4\x806\xc60e:5\xc80e;`31322\x7faym15\xe70g6D6\xe60cqg3322e?g441;" [:label put! sizeof io.write byte get Instructions #function("v~e0<6;0e1;~e2<6E0e3;~e4<6O0e5;i05;" [:jmp :jmp.l :brt :brt.l :brf :brf.l]) memq (:jmp :brf :brt) uint32 uint16 #function("ve0~c1326Q0e2i04e3i0631322\x81ayo01;e0~c4326\x890e2i04e5i0631322\x81ayo012e2i04e5i20\x81[31322\x81ayo01;e0~c6326\xc10e2i04e3i0631322\x81ayo012e2i04e3i20\x81[31322\x81ayo01;e2i04e5i0631322\x81ayo01;" [memq (:loadv.l :loadg.l :setg.l :loada.l :seta.l :largc :lvargc) io.write uint32 (:loadc :setc) uint8 (:loadc.l :setc.l)]) table.foreach #function("r2e0i04~322e1i04i106K0e25M0e3e4i02\x7f323142;" [io.seek io.write uint32 uint16 get]) io.tostring!]) length table buffer]) >= length 65536]) list->vector]) reverse!]) emit -#function("s2e0\x7fc1326K0e2~g2M32L1m25L0^2c3e4\x7fc532u322c6e4\x7fc732u322\x7fe8<6\x980g2c9>6\x810e:m12_m25\x950g2c;>6\x940e>6\xb40e?m12_m25\xc80g2c@>6\xc70eAm12_m25\xc80^5\xcc0^2~`eB\x7fg2K~`[32\\2~;" [memq (:loadv :loadg :setg) bcode:indexfor #function("v~16A02e0i02Mc1326M0e2~31o01;^;" [> 255 cadr]) assq ((:loadv :loadv.l) (:loadg :loadg.l) (:setg :setg.l) (:loada :loada.l) (:seta :seta.l)) #function("v~16S02e0i02Mc13217S02e0e2i0231c1326_0e2~31o01;^;" [> 255 cadr]) ((:loadc :loadc.l) (:setc :setc.l)) :loada (0) :loada0 (1) :loada1 :loadc (0 0) :loadc00 (0 1) :loadc01 nreconc]) +#function("s2g2A6C0~`\x7f~`[K\\5\xec0e0\x7fc1326\\0e2~g2M32L1m25]0^2c3e4\x7fc532u322c6e4\x7fc732u322\x7fe8<6\xa90g2c9>6\x920e:m12_m25\xa60g2c;>6\xa50e>6\xc50e?m12_m25\xd90g2c@>6\xd80eAm12_m25\xd90^5\xdd0^2~`eB\x7fg2K~`[32\\2~;" [memq (:loadv :loadg :setg) bcode:indexfor #function("v~16A02e0i02Mc1326M0e2~31o01;^;" [> 255 cadr]) assq ((:loadv :loadv.l) (:loadg :loadg.l) (:setg :setg.l) (:loada :loada.l) (:seta :seta.l)) #function("v~16S02e0i02Mc13217S02e0e2i0231c1326_0e2~31o01;^;" [> 255 cadr]) ((:loadc :loadc.l) (:setc :setc.l)) :loada (0) :loada0 (1) :loada1 :loadc (0 0) :loadc00 (0 1) :loadc01 nreconc]) div #function("r2~\x7fV~`X16M02\x7f`X16F02a17M02b/17S02`y;" []) display #function("r1e0~312];" [princ]) disassemble -#function("s1\x7fA6H0e0~`322e1302];5I0^2c2\x7fMe3~31e4~31u44;" [disassemble newline #function("vc0^u42;" [#function("vc0qm02c1`e2\x8131u43;" [#function("r1~J16<02~G@6Q0e0c1312e2~i10ay42;e3~41;" [princ "\n" disassemble print]) #function("v^~\x7fX6K02c0e1c2q^e333u32520;" [#function("ve0\x80`326A0e1305B0^2`i20azc2qw2e3e4\x8031c5e6e7~31a32c8342\x80ayo002c9~u42;" [> newline #function("r1e0c141;" [princ "\t"]) princ hex5 ": " string.tail string "\t" #function("ve0~c1326Y0i20i32e2i31i1032[312i10b4yo10;e0~c3326}0i20i32i31i10[[312i10ayo10;e0~c4326\xa00e5e6i31i10[31312i10ayo10;e0~c7326\xc70e5e6e2i31i103231312i10b4yo10;e0~c8326\x050e5e6i31i10[31c9322i10ayo102e5e6i31i10[31312i10ayo10;e0~c:326K1e5e6e2i31i103231c9322i10b4yo102e5e6e2i31i103231312i10b4yo10;e0~c;326t1e5ci31i103231322i10b2yo10;e0~c?326\x9d1e5cstring (:loada.l :seta.l :largc :lvargc) (:loadc :setc) " " (:loadc.l :setc.l) (:jmp :brf :brt) "@" hex5 ref-uint16-LE (:jmp.l :brf.l :brt.l)])]) table.foldl #function("r3g217F02\x7fi21\x80[<16F02~;" []) Instructions]) length])]) function:code function:vals]) +#function("s1\x7fA6H0e0~`322e1302];5I0^2c2\x7fMe3~31e4~31u44;" [disassemble newline #function("vc0^u42;" [#function("vc0qm02c1`e2\x8131u43;" [#function("r1~J16<02~G@6Q0e0c1312e2~i10ay42;e3~41;" [princ "\n" disassemble print]) #function("v^~\x7fX6K02c0e1c2q^e333u32520;" [#function("ve0\x80`326A0e1305B0^2`i20azc2qw2e3e4\x8031c5e6e7~31a32c8342\x80ayo002c9~u42;" [> newline #function("r1e0c141;" [princ "\t"]) princ hex5 ": " string.tail string "\t" #function("ve0~c1326Y0i20i32e2i31i1032[312i10b4yo10;e0~c3326}0i20i32i31i10[[312i10ayo10;e0~c4326\xa00e5e6i31i10[31312i10ayo10;e0~c7326\xc70e5e6e2i31i103231312i10b4yo10;e0~c8326\x050e5e6i31i10[31c9322i10ayo102e5e6i31i10[31312i10ayo10;e0~c:326K1e5e6e2i31i103231c9322i10b4yo102e5e6e2i31i103231312i10b4yo10;e0~c;326t1e5ci31i103231322i10b2yo10;e0~c?326\x9d1e5cstring (:loada.l :seta.l :largc :lvargc) (:loadc :setc) " " (:loadc.l :setc.l) (:jmp :brf :brt) "@" hex5 ref-uint16-LE (:jmp.l :brf.l :brt.l)])]) table.foldl #function("r3g217F02\x7fi21\x80[<16F02~;" []) Instructions]) length])]) function:code function:vals]) delete-duplicates #function("r1~?690~;c0~M~Nu43;" [#function("ve0~\x7f326@0e1\x7f41;~e1\x7f31K;" [member delete-duplicates])]) count @@ -203,7 +203,7 @@ compile-while compile-thunk #function("r1e0c1_~L341;" [compile lambda]) compile-sym -#function("r4c0e1g2\x7f`]34u42;" [#function("vc0~Mu42;" [#function("v~c0=6J0e1i10i13`[e2\x803143;~c3=6h0e1i10i13a[e2\x8031e4\x803144;e1i10i13b2[i1243;" [arg emit cadr closed caddr])]) lookup-sym]) +#function("r4c0e1g2\x7f`]34u42;" [#function("vc0~Mu42;" [#function("v~c0<6J0e1i10i13`[e2\x803143;~c3<6h0e1i10i13a[e2\x8031e4\x803144;e1i10i13b2[i1243;" [arg emit cadr closed caddr])]) lookup-sym]) compile-short-circuit #function("r6g3?6C0e0~\x7fg2g444;g3N?6V0e0~\x7fg2g3M44;c1e2~31u42;" [compile-in #function("ve0\x80\x81^i03M342e1\x80e2322e1\x80i05~332e1\x80e3322e4\x80\x81i02i03Ni04i05362e5\x80~42;" [compile-in emit :dup :pop compile-short-circuit mark-label]) make-label]) compile-prog1 @@ -213,7 +213,7 @@ compile-or compile-let #function("r4c0g3Mg3Nu43;" [#function("ve0\x7fe1e2~3131326F0^5Q0e3e4c5~32312e6\x80e7e8\x81~]33332c9e:\x80\x81\x7f33u42;" [length= length cadr error string "apply: incorrect number of arguments to " emit :loadv compile-f #function("ve0i10e1322e0i10i126K0e25M0e3a~y43;" [emit :copyenv :tcall :call]) compile-arglist])]) compile-in -#function("r4g3C6C0e0~\x7fg3c144;g3?6\xb10g3`<6X0e2~e342;g3a<6g0e2~e442;g3]<6v0e2~e542;g3^<6\x850e2~e642;g3_<6\x940e2~e742;e8g3316\xa70e2~e9g343;e2~e:g343;c;g3Mu42;" [compile-sym [:loada :loadc :loadg] emit :load0 :load1 :loadt :loadf :loadnil fits-i8 :loadi8 :loadv #function("v~c0=6G0e1\x80e2e3i033143;~c4=6[0e5\x80\x81i02i0344;~c6=6p0e7\x80\x81i02i03N44;~c8=6\x810e9\x80\x81i0343;~c:=6\xa00e1\x80e2e;\x81i0332332e1\x80e<42;~c==6\xb50e>\x80\x81i02i03N44;~c?=6\xca0e@\x80\x81i02i03N44;~cA=6\xe90eB\x80\x81e3i0331c6eCi0331K44;~cD=6\x0c0eE\x80\x81e3i0331eFi0331eGi033145;~cH=6*0eI\x80\x81]e3i0331342e1\x80eJ42;~cK=6P1eI\x80\x81^eFi0331342eL\x80\x81e3i0331cM44;~cN=6\x9b1eI\x80\x81^c:_e3i0331L3342eOeFi0331316}1^5\x831ePcQ312eI\x80\x81^eFi0331342e1\x80eR42;eS\x80\x81i02i0344;" [quote emit :loadv cadr if compile-if begin compile-begin prog1 compile-prog1 lambda compile-f :closure and compile-and or compile-or while compile-while cddr for compile-for caddr cadddr return compile-in :ret set! compile-sym [:seta :setc :setg] trycatch 1arg-lambda? error "trycatch: second form must be a 1-argument lambda" :trycatch compile-app])]) +#function("r4g3C6C0e0~\x7fg3c144;g3?6\xb10g3`<6X0e2~e342;g3a<6g0e2~e442;g3]<6v0e2~e542;g3^<6\x850e2~e642;g3_<6\x940e2~e742;e8g3316\xa70e2~e9g343;e2~e:g343;c;g3Mu42;" [compile-sym [:loada :loadc :loadg] emit :load0 :load1 :loadt :loadf :loadnil fits-i8 :loadi8 :loadv #function("v~c0<6G0e1\x80e2e3i033143;~c4<6[0e5\x80\x81i02i0344;~c6<6p0e7\x80\x81i02i03N44;~c8<6\x810e9\x80\x81i0343;~c:<6\xa00e1\x80e2e;\x81i0332332e1\x80e<42;~c=<6\xb50e>\x80\x81i02i03N44;~c?<6\xca0e@\x80\x81i02i03N44;~cA<6\xe90eB\x80\x81e3i0331c6eCi0331K44;~cD<6\x0c0eE\x80\x81e3i0331eFi0331eGi033145;~cH<6*0eI\x80\x81]e3i0331342e1\x80eJ42;~cK<6P1eI\x80\x81^eFi0331342eL\x80\x81e3i0331cM44;~cN<6\x9b1eI\x80\x81^c:_e3i0331L3342eOeFi0331316}1^5\x831ePcQ312eI\x80\x81^eFi0331342e1\x80eR42;eS\x80\x81i02i0344;" [quote emit :loadv cadr if compile-if begin compile-begin prog1 compile-prog1 lambda compile-f :closure and compile-and or compile-or while compile-while cddr for compile-for caddr cadddr return compile-in :ret set! compile-sym [:seta :setc :setg] trycatch 1arg-lambda? error "trycatch: second form must be a 1-argument lambda" :trycatch compile-app])]) compile-if #function("r4c0e1~31e1~31e2g331e3g331e4g331F6]0e5g3315^0^u46;" [#function("vg2]<6D0e0\x80\x81i02g344;g2^<6W0e0\x80\x81i02g444;e0\x80\x81^g2342e1\x80e2~332e0\x80\x81i02g3342i026\x860e1\x80e3325\x8e0e1\x80e4\x7f332e5\x80~322e0\x80\x81i02g4342e5\x80\x7f42;" [compile-in emit :brf :ret :jmp mark-label]) make-label cadr caddr cdddr cadddr]) compile-for @@ -221,7 +221,7 @@ compile-for compile-f #function("s2c0e130e2\x7f31u43;" [#function("vi02A@6C0e0~e1325\x970e2\x7fe3326j0e0~e4\x7f31A6^0e55`0e6e7\x7f31335\x970e4\x7f31A6\x820e0~e8e7\x7f31335\x970e0~e9\x7f?6\x900`5\x950e7\x7f31332e:~e;\x7f31\x80K]e<\x8131342e0~e=322e>e?e@~3131eA~3142;" [emit :let length> MAX_ARGS lastcdr :largc :lvargc length :argc :vargc compile-in to-proper caddr :ret function encode-byte-code bcode:code const-to-idx-vec]) make-code-emitter cadr]) compile-call -#function("r4c0g3Mu42;" [#function("vc0~C16]02e1~\x8132@16]02~E16]02e2~3116]02e3~31G6h0e3~315i0~u42;" [#function("vc0~G16?02e1~31u42;" [#function("v~@6E0e0i20i21^\x80345F0^2c1e2i20i21i23N33u42;" [compile-in #function("v\x806C0c0e1e2\x80^33u42;e3i30i326S0e45U0e5~43;" [#function("v~16A02e0i43N~32@6O0e1i20~325P0^2c2i10u42;" [length= argc-error #function("v~e0=6X0i10`W6J0e1i50e242;e1i50i20i1043;~e3=6\x920i10`W6q0e1i50e442;i10b2W6\x840e1i50e542;e1i50i20i1043;~e6=6\xdd0i10`W6\xaa0e7i30a42;i10aW6\xbc0e1i50e842;i10b2W6\xcf0e1i50e942;e1i50i20i1043;~e:=6\x040i10`W6\xf60e1i50e;42;e1i50i20i1043;~e<=6*0i10`W6\x1c0e7i30a42;e1i50i20i1043;~e==6S1i10`W6E1e1i50e>c?43;e1i50i20i1043;~e@=6\x851i10b2X6m1e7i30b242;e1i50i526}1eA5\x7f1e@i1043;e1i50i2042;" [:list emit :loadnil :+ :load0 :add2 :- argc-error :neg :sub2 :* :load1 :/ :vector :loadv [] :apply :tapply])]) get arg-counts emit :tcall :call]) compile-arglist]) builtin->instruction]) in-env? constant? top-level-value])]) +#function("r4c0g3Mu42;" [#function("vc0~C16]02e1~\x8132@16]02~E16]02e2~3116]02e3~31G6h0e3~315i0~u42;" [#function("vc0~G16?02e1~31u42;" [#function("v~@6E0e0i20i21^\x80345F0^2c1e2i20i21i23N33u42;" [compile-in #function("v\x806C0c0e1e2\x80^33u42;e3i30i326S0e45U0e5~43;" [#function("v~16A02e0i43N~32@6O0e1i20~325P0^2c2i10u42;" [length= argc-error #function("v~e0<6X0i10`W6J0e1i50e242;e1i50i20i1043;~e3<6\x920i10`W6q0e1i50e442;i10b2W6\x840e1i50e542;e1i50i20i1043;~e6<6\xdd0i10`W6\xaa0e7i30a42;i10aW6\xbc0e1i50e842;i10b2W6\xcf0e1i50e942;e1i50i20i1043;~e:<6\x040i10`W6\xf60e1i50e;42;e1i50i20i1043;~e<<6*0i10`W6\x1c0e7i30a42;e1i50i20i1043;~e=<6S1i10`W6E1e1i50e>c?43;e1i50i20i1043;~e@<6\x851i10b2X6m1e7i30b242;e1i50i526}1eA5\x7f1e@i1043;e1i50i2042;" [:list emit :loadnil :+ :load0 :add2 :- argc-error :neg :sub2 :* :load1 :/ :vector :loadv [] :apply :tapply])]) get arg-counts emit :tcall :call]) compile-arglist]) builtin->instruction]) in-env? constant? top-level-value])]) compile-begin #function("r4g3?6B0e0~\x7fg2^44;g3N?6U0e0~\x7fg2g3M44;e0~\x7f^g3M342e1~e2322e3~\x7fg2g3N44;" [compile-in emit :pop compile-begin]) compile-arglist @@ -319,6 +319,6 @@ Instructions *whitespace* "\t\n\v\f\r \u0085  ᠎           \u2028\u2029   " *syntax-environment* -#table(define #function("s1~C6?0c0~\x7fML3;c0~Mc1~N\x7fKKL3;" [set! lambda]) letrec #function("s1c0e1e2~32e3e1c4q~32\x7f32KKe1c5q~32K;" [lambda map car nconc #function("r1c0~K;" [set!]) #function("r1^;" [])]) backquote #function("r1e0~41;" [bq-process]) assert #function("r1c0~]c1c2c3~L2L2L2L4;" [if raise quote assert-failed]) label #function("r2c0~L1c1~\x7fL3L3^L2;" [lambda set!]) do #function("s2c0e130\x7fMe2e3~32e2e4~32e2c5q~32u46;" [#function("vc0~c1g2c2\x7fe3c4L1e5\x81N3132e3c4L1e5i0231e3~L1e5g43132L133L4L3L2L1e3~L1e5g33132L3;" [letrec lambda if nconc begin copy-list]) gensym map car cadr #function("r1e0~31F6A0e1~41;~M;" [cddr caddr])]) when #function("s1c0~c1\x7fK^L4;" [if begin]) unwind-protect #function("r2c0e130e130u43;" [#function("vc0\x7fc1_\x81L3L2L1c2c3\x80c1~L1c4\x7fL1c5~L2L3L3L3\x7fL1L3L3;" [let lambda prog1 trycatch begin raise]) gensym]) dotimes #function("s1c0~Me1~31u43;" [#function("vc0`c1\x7faL3e2c3L1~L1L1e4\x813133L4;" [for - nconc lambda copy-list]) cadr]) define-macro #function("s1c0c1~ML2c2~N\x7fKKL3;" [set-syntax! quote lambda]) unless #function("s1c0~^c1\x7fKL4;" [if begin]) let #function("s1c0^u42;" [#function("v\x80C6H0\x80m02\x81Mo002\x81No015I0^2c0c1e2c3q\x8032\x81KKe2c4q\x8032u43;" [#function("v\x806>0c0\x80~L35?0~\x7fK;" [label]) lambda map #function("r1~F6:0~M;~;" []) #function("r1~F6=0e0~41;^;" [cadr])])]) cond #function("s0c0^u42;" [#function("vc0qm02~\x8041;" [#function("r1~?690^;c0~Mu42;" [#function("v~Mc0<17?02~M]<6Q0~NA6K0~M;c1~NK;~NA6e0c2~Mi10\x80N31L3;c3~Mc1~NKi10\x80N31L4;" [else begin or if])])])]) throw #function("r2c0c1c2c3L2~\x7fL4L2;" [raise list quote thrown-value]) time #function("r1c0e130u42;" [#function("vc0~c1L1L2L1c2\x80c3c4c5c1L1~L3c6L4L3L3;" [let time.now prog1 princ "Elapsed time: " - " seconds\n"]) gensym]) let* #function("s1~?6J0e0c1L1_L1e2\x7f3133L1;e0c1L1e3~31L1L1e2~NF6w0e0c4L1~NL1e2\x7f3133L15x0\x7f3133e5~31L2;" [nconc lambda copy-list caar let* cadar]) case #function("s1c0^u42;" [#function("vc0qm02c1e230u42;" [#function("r2\x7fc0<6<0c0;\x7fA6C0^;\x7f?6S0c1~e2\x7f31L3;\x7fNA6e0c1~e2\x7fM31L3;c3~c4\x7fL2L3;" [else eqv? quote-value memv quote]) #function("vc0~i10L2L1e1c2L1e3e4c5qi11323132L3;" [let nconc cond copy-list map #function("r1i10\x80~M32~NK;" [])]) gensym])]) catch #function("r2c0e130u42;" [#function("vc0\x81c1~L1c2c3c4~L2c5c6~L2c7c8L2L3c5c9~L2\x80L3L4c:~L2c;~L2L4L3L3;" [trycatch lambda if and pair? eq car quote thrown-value cadr caddr raise]) gensym])) +#table(define #function("s1~C6?0c0~\x7fML3;c0~Mc1~N\x7fKKL3;" [set! lambda]) letrec #function("s1c0e1e2~32e3e1c4q~32\x7f32KKe1c5q~32K;" [lambda map car nconc #function("r1c0~K;" [set!]) #function("r1^;" [])]) backquote #function("r1e0~41;" [bq-process]) assert #function("r1c0~]c1c2c3~L2L2L2L4;" [if raise quote assert-failed]) label #function("r2c0~L1c1~\x7fL3L3^L2;" [lambda set!]) do #function("s2c0e130\x7fMe2e3~32e2e4~32e2c5q~32u46;" [#function("vc0~c1g2c2\x7fe3c4L1e5\x81N3132e3c4L1e5i0231e3~L1e5g43132L133L4L3L2L1e3~L1e5g33132L3;" [letrec lambda if nconc begin copy-list]) gensym map car cadr #function("r1e0~31F6A0e1~41;~M;" [cddr caddr])]) when #function("s1c0~c1\x7fK^L4;" [if begin]) unwind-protect #function("r2c0e130e130u43;" [#function("vc0\x7fc1_\x81L3L2L1c2c3\x80c1~L1c4\x7fL1c5~L2L3L3L3\x7fL1L3L3;" [let lambda prog1 trycatch begin raise]) gensym]) dotimes #function("s1c0~Me1~31u43;" [#function("vc0`c1\x7faL3e2c3L1~L1L1e4\x813133L4;" [for - nconc lambda copy-list]) cadr]) define-macro #function("s1c0c1~ML2c2~N\x7fKKL3;" [set-syntax! quote lambda]) unless #function("s1c0~^c1\x7fKL4;" [if begin]) let #function("s1c0^u42;" [#function("v\x80C6H0\x80m02\x81Mo002\x81No015I0^2c0c1e2c3q\x8032\x81KKe2c4q\x8032u43;" [#function("v\x806>0c0\x80~L35?0~\x7fK;" [label]) lambda map #function("r1~F6:0~M;~;" []) #function("r1~F6=0e0~41;^;" [cadr])])]) cond #function("s0c0^u42;" [#function("vc0qm02~\x8041;" [#function("r1~?690^;c0~Mu42;" [#function("v~Mc0<17?02~M]<6Q0~NA6K0~M;c1~NK;~NA6e0c2~Mi10\x80N31L3;c3~Mc1~NKi10\x80N31L4;" [else begin or if])])])]) throw #function("r2c0c1c2c3L2~\x7fL4L2;" [raise list quote thrown-value]) time #function("r1c0e130u42;" [#function("vc0~c1L1L2L1c2\x80c3c4c5c1L1~L3c6L4L3L3;" [let time.now prog1 princ "Elapsed time: " - " seconds\n"]) gensym]) let* #function("s1~?6J0e0c1L1_L1e2\x7f3133L1;e0c1L1e3~31L1L1e2~NF6w0e0c4L1~NL1e2\x7f3133L15x0\x7f3133e5~31L2;" [nconc lambda copy-list caar let* cadar]) case #function("s1c0^u42;" [#function("vc0qm02c1e230u42;" [#function("r2\x7fc0<6<0c0;\x7fA6C0^;\x7fC6S0c1~e2\x7f31L3;\x7f?6c0c3~e2\x7f31L3;\x7fNA6u0c3~e2\x7fM31L3;e4e5\x7f326\x8a0c6~c7\x7fL2L3;c8~c7\x7fL2L3;" [else eq? quote-value eqv? every symbol? memq quote memv]) #function("vc0~i10L2L1e1c2L1e3e4c5qi11323132L3;" [let nconc cond copy-list map #function("r1i10\x80~M32~NK;" [])]) gensym])]) catch #function("r2c0e130u42;" [#function("vc0\x81c1~L1c2c3c4~L2c5c6~L2c7c8L2L3c5c9~L2\x80L3L4c:~L2c;~L2L4L3L3;" [trycatch lambda if and pair? eq car quote thrown-value cadr caddr raise]) gensym])) *banner* "; _\n; |_ _ _ |_ _ | . _ _\n; | (-||||_(_)|__|_)|_)\n;-------------------|----------------------------------------------------------\n\n" diff --git a/femtolisp/flisp.c b/femtolisp/flisp.c index aeac78f..71ade84 100644 --- a/femtolisp/flisp.c +++ b/femtolisp/flisp.c @@ -799,7 +799,7 @@ static value_t do_trycatch() #endif /* - stack on entry: + stack on entry: MAX_ARGS> caller's responsibility: - put the stack in this state - provide arg count @@ -819,7 +819,7 @@ static value_t apply_cl(uint32_t nargs) uint8_t *code; // temporary variables (not necessary to preserve across calls) - uint32_t op; + uint8_t op; symbol_t *sym; static cons_t *c; static value_t *pv; @@ -935,9 +935,10 @@ static value_t apply_cl(uint32_t nargs) v = apply_cl(n); } else { - op = uintval(func); - if (op > OP_ASET) + i = uintval(func); + if (i > OP_ASET) type_error("apply", "function", func); + op = (uint8_t)i; s = builtin_arg_counts[op]; if (s >= 0) argcount(builtin_names[op], n, s); diff --git a/femtolisp/system.lsp b/femtolisp/system.lsp index ca8c5f9..029daba 100644 --- a/femtolisp/system.lsp +++ b/femtolisp/system.lsp @@ -21,8 +21,15 @@ (define (symbol-syntax s) (get *syntax-environment* s #f)) (define (map f lst) - (if (atom? lst) lst - (cons (f (car lst)) (map f (cdr lst))))) + ((lambda (first acc) + (begin + (set! first acc) + (while (pair? lst) + (begin (set! acc + (cdr (set-cdr! acc (cons (f (car lst)) ())))) + (set! lst (cdr lst)))) + (cdr first))) + () (list ()))) (define-macro (label name fn) (list (list 'lambda (list name) (list 'set! name fn)) #f)) @@ -362,8 +369,11 @@ (define (vals->cond key v) (cond ((eq? v 'else) 'else) ((null? v) #f) + ((symbol? v) `(eq? ,key ,(quote-value v))) ((atom? v) `(eqv? ,key ,(quote-value v))) ((null? (cdr v)) `(eqv? ,key ,(quote-value (car v)))) + ((every symbol? v) + `(memq ,key ',v)) (else `(memv ,key ',v)))) (let ((g (gensym))) `(let ((,g ,key)) diff --git a/femtolisp/test.lsp b/femtolisp/test.lsp index 564c9c9..20f4378 100644 --- a/femtolisp/test.lsp +++ b/femtolisp/test.lsp @@ -226,3 +226,35 @@ (sub h n (string.inc h i) (cons i lst)) (reverse! lst)))) (sub haystack needle (if (null? offs) 0 (car offs)) ())) + +(let ((*profiles* (table))) + (set! profile + (lambda (s) + (let ((f (top-level-value s))) + (set-top-level-value! s + (lambda args + (define tt (get *profiles* s 0)) + (define t0 (time.now)) + (define v (apply f args)) + (put! *profiles* s (+ tt (- (time.now) t0))) + v))))) + (set! show-profiles + (lambda () + (define (swapad c) (cons (cdr c) (car c))) + (for-each (lambda (p) + (princ (cdr p) "\t\t" (car p)) + (newline)) + (simple-sort (map swapad (table.pairs *profiles*))))))) + +#;(for-each profile + '(emit encode-byte-code const-to-idx-vec + index-of lookup-sym in-env? + compile-sym compile-if compile-begin + list-partition just-compile-args + compile-arglist + compile-app compile-let compile-call + compile-in compile compile-f + map length> length= count filter append + lastcdr to-proper reverse reverse! list->vector + table.foreach list-head list-tail assq memq assoc member + assv memv nreconc bq-process)) diff --git a/femtolisp/torture.scm b/femtolisp/torture.scm index 2f25e8c..74905b8 100644 --- a/femtolisp/torture.scm +++ b/femtolisp/torture.scm @@ -1,19 +1,24 @@ +(define ones (map (lambda (x) 1) (iota 1000000))) + +(display (apply + ones)) +(newline) + (define (big n) (if (<= n 0) 0 `(+ 1 1 1 1 1 1 1 1 1 1 ,(big (- n 1))))) -(define nst `(display ,(big 100000))) +(define nst (big 100000)) (display (eval nst)) (newline) +(define longg (cons '+ ones)) +(display (eval longg)) +(newline) + (define (f x) (begin (display x) (newline) (f (+ x 1)) 0)) - -(define longg (cons '+ (map (lambda (x) 1) (iota 1000000)))) -(display (eval longg)) -(newline)