+ sequences\r
\r
- generic skip\r
-- dipping seq-2nmap, seq-2each\r
+- dipping 2nmap, 2each\r
- array sort\r
- 2map slow with lists\r
- nappend: instead of using push, enlarge the sequence with set-length\r
] check-recursion ;}
\end{alltt}
-\chapter{Dealing with runtime errors}
+\chapter{Debugging and optimizing}
\section{Looking at stacks}
If you accidentally start an infinite loop, you can send the Factor runtime a \texttt{QUIT} signal. On Unix, this is done by pressing \texttt{Control-\bs} in the controlling terminal. This will cause the runtime to dump the data and return stacks in a semi-readable form. Note that this will help you find the root cause of the hang, but it will not let you interrupt the infinite loop.
-
-\chapter{Defensive coding}
-
\section{Unit testing}
Unit tests are very easy to write. They are usually placed in source files. A unit test can be executed with the \texttt{unit-test} word in the \texttt{test} vocabulary. This word takes a list and a quotation; the quotation is executed, and the resulting data stack is compared against the list. If they do not equal, the unit test has failed. Here is an example of a unit test:
Unit testing is a good habit to get into. Sometimes, writing tests first, before any code, can speed the development process too; by running your unit test script, you can gauge progress.
-\chapter{Optimization}
-
-While both the Factor interpreter and compiler are relatively slow at this stage, there
-are still ways you can make your Factor code go faster. The key is to find bottlenecks,
-and optimize them.
-
\section{Timing code}
The \texttt{time} word reports the time taken to execute a quotation, in milliseconds. The portion of time spent in garbage collection is also shown:
tuple: 688 bytes, 22 instances}
\end{alltt}
-\section{The profiler}
-
-Factor provides a statistical sampling profiler for narrowing down memory and processor bottlenecks.
-The profiler is only supported on Unix platforms. On FreeBSD 4.x, the Factor runtime must
-be compiled without the \texttt{-pthread} switch, since FreeBS 4.x userspace threading makes
-use of a signal that conflicts with the signal used for profiling.
-
-The \texttt{allot-profile} word executes a quotation with the memory profiler enabled, then prints a list of all words that allocated memory, along with the bytes allocated. Note that during particularly long executions, or executions where a lot of memory is allocated, these counters may overrun.
-
-\begin{alltt}
-\textbf{ok} [ "boot.image.le32" make-image ] allot-profile
-\emph{... many lines omitted ...}
-\textbf{[[ write-little-endian-32 673952 ]]
-[[ wait-to-read-line 788640 ]]
-[[ blocking-read-line 821264 ]]
-[[ vocabularies 822624 ]]
-[[ parse-resource 823376 ]]
-[[ next-line 1116440 ]]
-[[ vector-map 1326504 ]]
-[[ fixup-words 1326520 ]]
-[[ vector-each 1768640 ]]
-[[ (parse) 2434208 ]]
-[[ classes 2517920 ]]
-[[ when* 2939088 ]]
-[[ while 3614408 ]]
-[[ (parse-stream) 3634552 ]]
-[[ make-list 3862000 ]]
-[[ object 4143784 ]]
-[[ each 4712080 ]]
-[[ run-resource 5036904 ]]
-[[ (callcc) 5183400 ]]
-[[ catch 5188976 ]]
-[[ 2slip 8631736 ]]
-[[ end 202896600 ]]
-[[ make-image 208611888 ]]
-[[ with-scope 437823992 ]]}
-\end{alltt}
-
-The \texttt{call-profile} word executes a quotation with the CPU profiler enabled, then prints a list of all words that were found on the return stack, along with the number of times they were seen there. This gives a rough idea of what words are taking up the majority of execution time.
-
-\begin{alltt}
-\textbf{ok} [ "boot.image.le32" make-image ] call-profile
-\emph{... many lines omitted ...}
-\textbf{[[ stream-write 7 ]]
-[[ wait-to-write 7 ]]
-[[ vector-map 11 ]]
-[[ fixup-words 11 ]]
-[[ when* 12 ]]
-[[ write 16 ]]
-[[ write-word 17 ]]
-[[ parse-loop 22 ]]
-[[ make-list 24 ]]
-[[ (parse) 29 ]]
-[[ blocking-write 32 ]]
-[[ while 35 ]]
-[[ (parse-stream) 36 ]]
-[[ dispatch 47 ]]
-[[ run-resource 50 ]]
-[[ write-little-endian-32 76 ]]
-[[ (callcc) 173 ]]
-[[ catch 174 ]]
-[[ each 175 ]]
-[[ 2slip 199 ]]
-[[ end 747 ]]
-[[ make-image 785 ]]
-[[ with-scope 1848 ]]}
-\end{alltt}
-
-Normally, the memory and CPU profilers run every millisecond, and increment counters for all words on the return stack. The \texttt{only-top} variable can be switched on, in which case only the counter for the word at the top of the return stack is incremented. This gives a more localized picture of CPU and memory usage.
-
\chapter{Stack effect inference}
The stack effect inference tool checks correctness of code before it is run.
[ stack-space ] keep
[ [ c-aligned - dup ] keep unbox-parameter ] map nip % ;
+: incr-param ( reg-class -- )
+ #! OS X is so ugly.
+ dup class [ 1 + ] change dup float-regs? [
+ os "macosx" = [
+ int-regs [ swap float-regs-size 4 / + ] change
+ ] [
+ drop
+ ] ifte
+ ] [
+ drop
+ ] ifte ;
+
: load-parameter ( n parameter -- node )
c-type "reg-class" swap hash
- [ class dup get dup 1 + rot set ] keep
- %parameter ;
+ [ [ class get ] keep incr-param ] keep %parameter ;
: load-parameters ( params -- )
[
: fill ( count char -- string ) <repeated> >string ;
-: pad ( string count char -- string )
- >r over length - dup 0 <= [
- r> 2drop
- ] [
- r> fill swap append
- ] ifte ;
+: padding ( string count char -- string )
+ >r swap length - dup 0 <= [ r> 2drop "" ] [ r> fill ] ifte ;
+
+: pad-left ( string count char -- string )
+ pick >r padding r> append ;
+
+: pad-right ( string count char -- string )
+ pick >r padding r> swap append ;
: ch>string ( ch -- str ) 1 <sbuf> [ push ] keep (sbuf>string) ;
! See http://factor.sf.net/license.txt for BSD license.
IN: kernel USING: errors lists namespaces sequences ;
-: reify ( quot -- )
- >r datastack >pop> callstack >pop> namestack catchstack
- r> call ;
+TUPLE: interp data call name catch ;
-: (callcc) cons cons cons cons swap call ;
+: interp ( -- interp )
+ datastack callstack >pop> >pop>
+ namestack catchstack <interp> ;
-: continue0 ( ds rs ns cs -- )
- set-catchstack set-namestack
+: >interp< ( interp -- data call name catch )
+ [ interp-data ] keep
+ [ interp-call ] keep
+ [ interp-name ] keep
+ interp-catch ;
+
+: set-interp ( interp -- )
+ >interp< set-catchstack set-namestack
>r set-datastack r> set-callstack ;
-: callcc0 ( code -- )
- #! Calls the code with a special quotation at the top of the
- #! stack. The quotation has stack effect:
- #!
- #! ( -- ... )
- #!
- #! When called, the quotation restores execution state to
- #! the point after the callcc0 call.
- [ [ continue0 ] (callcc) ] reify ;
+: continuation ( interp -- )
+ interp dup interp-call >pop> >pop> drop
+ dup interp-data >pop> drop ;
-: continue1 ( obj ds rs ns cs -- obj )
- set-catchstack set-namestack
- rot >r >r set-datastack r> r> swap set-callstack ;
+: callcc0 ( quot ++ | quot: cont -- | cont: ++ )
+ continuation
+ [ set-interp ] cons swap call ;
-: callcc1 ( code -- )
- #! Calls the code with a special quotation at the top of the
- #! stack. The quotation has stack effect:
- #!
- #! ( X -- ... )
- #!
- #! When called, the quotation restores execution state to
- #! the point after the callcc1 call, and places X at the top
- #! of the original datastack.
- [ [ continue1 ] (callcc) ] reify ;
+: callcc1 ( quot ++ obj | quot: cont -- | cont: obj ++ obj )
+ continuation
+ [ [ interp-data push ] keep set-interp ] cons swap call ;
#! Turn a hash table that maps values to quotations into a
#! quotation that executes a quotation depending on the
#! value on the stack.
- dup hash-size 4 <= [
+ ( dup hash-size 4 <= ) t [
hash>alist alist>quot
] [
(hash>quot)
] make-string ;
: >hex-color ( triplet -- hex )
- [ CHAR: # , [ >hex 2 CHAR: 0 pad % ] each ] make-string ;
+ [ CHAR: # , [ >hex 2 CHAR: 0 pad-left % ] each ] make-string ;
: fg-css, ( color -- )
"color: " , >hex-color , "; " , ;
dup url-quotable? [
,
] [
- CHAR: % , >hex 2 CHAR: 0 pad %
+ CHAR: % , >hex 2 CHAR: 0 pad-left %
] ifte
] each
] make-string ;
no-effect ;
M: primitive (apply-word) ( word -- )
- dup "infer-effect" word-prop consume/produce ;
+ dup "infer-effect" word-prop [
+ consume/produce
+ ] [
+ no-effect
+ ] ifte ;
M: compound (apply-word) ( word -- )
#! Infer a compound word's stack effect.
] assoc ;
: ch>unicode-escape ( ch -- esc )
- >hex 4 CHAR: 0 pad "\\u" swap append ;
+ >hex 4 CHAR: 0 pad-left "\\u" swap append ;
: unparse-ch ( ch -- ch/str )
dup quotable? [
[ [[ 2 1 ]] ] [ [ remove ] infer old-effect ] unit-test
[ [[ 1 1 ]] ] [ [ prune ] infer old-effect ] unit-test
+[ [ callstack ] infer ] unit-test-fails
+
: no-base-case dup [ no-base-case ] [ no-base-case ] ifte ;
[ [ no-base-case ] infer ] unit-test-fails
[ 2 2 + ] test-interpreter
] unit-test
+[ { } ] [
+ [ 3 "x" set ] test-interpreter
+] unit-test
+
[ { 3 } ] [
[ 3 "x" set "x" get ] test-interpreter
] unit-test
: next ( -- obj )
meta-cf get [ meta-cf [ uncons ] change ] [ up next ] ifte ;
+: meta-interp ( -- interp )
+ meta-d get meta-r get meta-n get meta-c get <interp> ;
+
+: set-meta-interp ( interp -- )
+ >interp< meta-c set meta-n set meta-r set meta-d set ;
+
: host-word ( word -- )
- #! Swap in the meta-interpreter's stacks, execute the word,
- #! swap in the old stacks. This is so messy.
- push-d datastack push-d
- meta-d get set-datastack
- catchstack >r meta-c set-catchstack
- namestack >r meta-n set-namestack
- >r execute datastack r> tuck push
- r> set-namestack
- r> set-catchstack
- set-datastack meta-d set ;
+ [
+ \ call push-r interp [
+ interp over interp-data push
+ set-interp
+ ] cons cons push-r meta-interp set-interp
+ ] call set-meta-interp pop-d 2drop ;
: meta-call ( quot -- )
#! Note we do tail call optimization here.
! Printing an overview of heap usage.
-: kb. 1024 /i unparse 6 CHAR: \s pad write " KB" write ;
+: kb. 1024 /i unparse 6 CHAR: \s pad-left write " KB" write ;
: (room.) ( free total -- )
2dup swap - swap ( free used total )
fcntl(1,F_SETFL,0);
#endif
- fprintf(stderr,"Factor low-level debugger\n");
fprintf(stderr,"d <addr> <count> -- dump memory\n");
fprintf(stderr,". <addr> -- print object at <addr>\n");
fprintf(stderr,"sz <addr> -- print size of object at <addr>\n");
{
char cmd[1024];
- fprintf(stderr,"ldb ");
+ fprintf(stderr,"fep ");
fflush(stdout);
if(scanf("%s",cmd) <= 0)
#include "factor.h"
+void foobar(int x, int y, int z, int t)
+{
+ printf("%d\n",x);
+ printf("%d\n",y);
+ printf("%d\n",z);
+ printf("%d\n",t);
+}
+
double to_float(CELL tagged)
{
F_RATIO* r;