Path: utzoo!utgpu!news-server.csri.toronto.edu!cs.utexas.edu!usc!snorkelwacker!bloom-beacon!mitech.COM!gjc From: gjc@mitech.COM Newsgroups: comp.lang.scheme Subject: (none) Message-ID: <9008151749.AA23832@mailhost.samsung.com> Date: 15 Aug 90 17:49:42 GMT Sender: daemon@athena.mit.edu (Mr Background) Reply-To: gjc@mitech.com Organization: The Internet Lines: 135 I hope people may find some interesting technical details in the replies herein. >From: Alfred Kayser >I've once tryed to port it to MSDOS or OS2 (compiler and cpu are the same) >but it crashed enormously. The code was too unreadable to be debugged. >Keep in mind that it was started from a 'joke'. SIOD stands for >Scheme In One Defun. Thus a scheme interpreter in Lisp, which was ported to >C somewhere between 1.0 and 2.4. SIOD was never intended to be a joke. The fact that it was in one DEFUN made it convenient to compile into MICROCODE on the LMI-LAMBDA lispmachine, which had a PAGED microcode feature. Also, SIOD version 1.0 was in C, (24-APR-1988), as is obvious from the comments in the source code. Under the microsoft C compiler, small code and data model at least the 1.3 version of SIOD compiled and ran the first time I tried it. Anybody who would want to utilize the large data model 80286 mode would have to be an expert MSDOS/C programmer, I am told by someone who did a port. The details were something I had a hard time grasping. Very strange stuff along the lines of PADDING the "struct obj" structure so it would be 16 bytes long instead of 10 bytes long. Be that as it may the fellow was using SIOD in a commercial product and must have felt his port to be too valuable to send back to me. Or perhaps he just didn't want to have his name on it and have to put up with complaints from people. >From: UUCP%"rees@parc.xerox.com" 14-AUG-1990 17:21 >> What is one requirement for living well with C? That if you >> have a lisp-level call to a procedure like (equal (f x) (g y)) that >> you must be able to call it at C-level as equal(f(x),g(y)); >This is a tall order; the only solution of which I'm aware is a >conservative GC, and I didn't think siod had one of those (I deduce >this from the presence in slib.c of a function called "gc_protect"). SIOD has both stop-and-copy and mark-and-sweep GC, the latter being able to run in "conservative" mode. This can be deduced from the discussion on garbage collection in SIOD.DOC. >Or do you have some other way of dealing with the situation where >assuming left-to-right argument evaluation in C) > - the result of f is consed > - the only pointer to this result while in g is on the C stack > - invoking g triggers a GC > - after the gc g does more allocation, thereby overwriting the > result of the call to f? A good way of describing the problem. Interesting side-note: A company called Chesnut software was at AAAI showing their LISP->C translator. It was interesting in that it produced *readable* C code. For only $75000 with a free runtime license it may have been the bargain of the show. (Many lisp vendors want $750 or more per copy runtime license). I played with it a little bit. The disturbing thing was that it seemed to give BETTER performance than native lisp implementations from the other 3rd-party lisp vendors. Tells you something about the state of the art of lisp implementation if such a crude but effective hack as idiomatic LISP->C can do better. The other disturbing thing is that I swear I could DEBUG the compiled LISP->C code better than I could debug the native compiled lisp code, because the state of the art in C language debuggers is better than the state of the art in LISP (compiled) language debuggers. The Chesnut Software marketroid person did not seem to pick up on that as a selling point. "We have a good relationship with the lisp vendors" he said. From: Andrew Ginter >>This is a tall order; the only solution of which I'm aware is a >>conservative GC... >There's another solution to the problem - the one I believe GNU emacs >uses. At the top of the command loop, emacs checks that there is a >"fair" amount of memory left in the garbage collected heap (as I >recall, "fair" = no more than about 90% full). If there's not enough >room, the collector is called. At this point in time, there are no >pointers to the heap anywhere on the stack. In the rare case that a >lisp command consumes all of the remaining > 10% of the heap before >returning to the top of the command loop, emacs simply allocates more >memory for the heap. Not accurate for GNU emacs which has explicit calls, in both the S-expression and byte-code interpreters to macros which effectively provide a linked list of pointers to GC-protected objects. This is a good way of doing things. There is overhead in setting up all the GC protection information, and you have to be very careful to never RETURN from a function before calling GC-unprotect, but it is more natural looking and probably as fast or faster than having a special array to be used for all lisp objects. I would have done the same thing in later versions of SIOD, except that doesn't allow you to write things like f(g(),h()), and it slows things down. There is a very explicit comment in the gnu emacs source, LISP.H about this: /* Structure for recording stack slots that need marking This is a chain of structures, each of which points at a Lisp_Object variable whose value should be marked in garbage collection. Normally every link of the chain is an automatic variable of a function, and its `val' points to some argument or local variable of the function. On exit to the function, the chain is set back to the value it had on entry. This way, no link remains in the chain when the stack frame containing the link disappears. Every function that can call Feval must protect in this fashion all Lisp_Object variables whose contents will be used again. */ extern struct gcpro *gcprolist; struct gcpro {struct gcpro *next; Lisp_Object *var; /* Address of first protected variable */ int nvars; /* Number of consecutive protected variables */ }; #define GCPRO1(varname) \ {gcpro1.next = gcprolist; gcpro1.var = &varname; gcpro1.nvars = 1; \ gcprolist = &gcpro1; } #define GCPRO2(varname1, varname2) \ {gcpro1.next = gcprolist; gcpro1.var = &varname1; gcpro1.nvars = 1; \ gcpro2.next = &gcpro1; gcpro2.var = &varname2; gcpro2.nvars = 1; \ gcprolist = &gcpro2; } /* Call staticpro (&var) to protect static variable `var'. */ void staticpro(); #define UNGCPRO (gcprolist = gcpro1.next)