macaroni is better than spaghetti

7
Hacaronl ls Better than Spaghetti by Guy Lewis Steele Jr. Massachusetts Institute of Technology Artificial Intelligence Laboratory 545 Technology Square Cambridge, Rassachusetts 0Z139 N~stract: We present a stack Implementation of multlple environments slmllar In principle to that of Bobrow and Wegbrett, but based on a model which provides both statlc and dynamlc scoplng. We n o t e some of the pra91nattc consequences of this choice of models; one is that no unnecessary control stack is retained for certain important constructions such as "upward funargs' and corouttnes. We also discuss the correct treatment of exit functions, and the need for "entry functions" If dynamic switching of control contexts Is to be consistent. Introduction The stack Implementation of environments described In [BW] was deslgned to combine the flexibility of generalized tree-structured environments with the efficiency of existing stack hardware. It was based on the dynamic-binding model then prevalent among LISP systems. Since that tlme a number of problems wlth dynamic blndlng have come to light. We propose here a revtslon of the spaghetti stack Implementation whlch retains much the same storage management techniques while substituting a better model of environment and control relationships. This model assumes statlc (lexlcal) btndlng as the prlmary scoplng discipline, but has provisions for dynamic blnding as well. We will not argue the relatlve merits of lexlcal and dynamic scoplng here; for that the reader is referred to [Imperative] and [Declarative]. However, where relevant we w111 note some of the pragmatic consequences of the differences between the models. Internal Storage Structures We introduce five klnds of storage objects. Three of these are "stack-allocated frames', to be managed by the storage reclamation techniques discussed In [BW]. Each such frame has three flelds SIZE, mAX, and USE for use by the storage manager. The other two are "heap-allocated objects" which are managed by the garbage coUector in the usual way, except that when such an object is reclaimed the USE field of any frame pointed to by the object must be decremented, possibly resulting In the reclamation of the frame. These new objects are: (l) Access frames. These are analogous to the basic frames of [BW]. An access frame contains values of statically scoped variables and an ALINK pointer to another access frame (or NIL if thls is the highest access frame of the static environment). Notice that, by the very nature of static access, these frames need not contain names for each of the variables (though they may, if deslred, for debugging purposes; but see also theramarks in [Declarative]), but only the values. ...... -l xl use I s,zE] . A~INK "t ........ VALUES[I] / VALUES[Z] / (Z) Control frames. These are analogous to the frame extensions of [BW]. Control frames contaln varlous temporary quantities, a CLINK polnter to a prevlous control frame, and an ALINK pointer to the current access frame. ,.x I use I s'zE CLINK -" AL]NK e, Tf.HPORARY 1 TEMPORARY Z (3) Dynamic blndlng frames. These are slmllar to control frames, but also contain name-value pairs for dynamic variable lookup. A dynamic binding frame may also have an additional DLINK pointer to the previous dynamic binding frame. The DLINK pointer is not logically necessary, since the same frame can be found by following the CLINK chain, but can speed up the search in the case of deep access, or the context switch in the case of shallow access. 60

Upload: guy-lewis

Post on 23-Dec-2016

241 views

Category:

Documents


8 download

TRANSCRIPT

Page 1: Macaroni is better than spaghetti

Hacaronl l s Be t te r than S p a g h e t t i

by Guy Lewis Steele J r .

Massachusetts I n s t i t u t e o f Technology A r t i f i c i a l I n t e l l i g e n c e L a b o r a t o r y

545 Technology Square Cambridge, Rassachusetts 0Z139

N~s t rac t : We p r e s e n t a s t a c k I m p l e m e n t a t i o n o f

m u l t l p l e environments s l m l l a r In p r i n c i p l e to t h a t o f Bobrow and Wegbrett, but based on a model which p rov ides both s t a t l c and dynamlc scoplng. We note some o f the pra91nattc consequences of t h i s choice o f models; one i s tha t no unnecessary con t ro l s tack i s r e t a i n e d f o r ce r ta in important const ruc t ions such as "upward f u n a r g s ' and co rou t t nes . We a l so d i scuss the c o r r e c t t r ea tmen t o f e x i t f u n c t i o n s , and the need f o r "en t r y func t ions" I f dynamic sw i t ch ing o f c o n t r o l contexts Is to be cons is tent .

I n t r o d u c t i o n

The s tack Imp lementa t ion o f env i ronments d e s c r i b e d In [BW] was des lgned t o combine the f l e x i b i l i t y o f g e n e r a l i z e d t r e e - s t r u c t u r e d environments w i th the e f f i c i e n c y o f e x i s t i n g s tack hardware. I t was based on the dynamic-binding model then p reva len t among LISP systems. Since t ha t t lme a number o f problems w l th dynamic b lnd lng have come to l i g h t . We propose here a r e v t s l o n o f t h e s p a g h e t t i s tack Imp lementa t ion whlch r e t a i n s much the same s t o r a g e management t e c h n i q u e s w h i l e s u b s t i t u t i n g a b e t t e r mode l o f e n v i r o n m e n t a n d c o n t r o l r e l a t i o n s h i p s . This model assumes s t a t l c ( l e x l c a l ) b tnd lng as the prlmary scoplng d i s c i p l i n e , but has p rov is ions f o r dynamic b lnd ing as w e l l . We w i l l no t argue the r e l a t l v e m e r i t s o f l e x l c a l and dynamic s c o p l n g h e r e ; f o r t h a t t he r e a d e r i s r e f e r r e d t o [ I m p e r a t i v e ] and [ D e c l a r a t i v e ] . However, where r e l e v a n t we w111 note some o f the p ragma t i c consequences o f the d i f f e r e n c e s between the models.

I n t e r n a l Storage S t r u c t u r e s

We in t roduce f i v e klnds o f s torage o b j e c t s . Three o f these are " s tack -a l l oca ted f rames ' , to be managed by the s t o r a g e r e c l a m a t i o n t e c h n i q u e s discussed In [BW]. Each such frame has th ree f l e l d s SIZE, mAX, and USE f o r use by the s t o r a g e manager . The o t h e r two a r e " h e a p - a l l o c a t e d o b j e c t s " which a r e managed by t he garbage c o U e c t o r in t he u s u a l way, e x c e p t t h a t when such an o b j e c t i s r e c l a i m e d t h e USE f i e l d o f any frame p o i n t e d to by t h e o b j e c t must be d e c r e m e n t e d , p o s s i b l y r e s u l t i n g In t h e r e c l a m a t i o n o f the frame. These new ob jec ts are:

( l ) Access frames. These are analogous to the bas ic frames o f [BW]. An access frame conta ins values o f s t a t i c a l l y scoped v a r i a b l e s and an AL INK p o i n t e r to another access frame (or NIL i f t h l s i s the h i g h e s t access f rame o f the s t a t i c env i ronment) . Not ice tha t , by the very nature o f s t a t i c access, these frames need not con ta in names f o r each o f the v a r i a b l e s ( though they may, i f d e s l r e d , f o r debugging purposes; bu t see a lso the ramarks in [ D e c l a r a t i v e ] ) , but on l y the va lues.

...... -l xl use I s,zE] . A~INK " t . . . . . . . . VALUES[I] / VALUES[Z] /

(Z) C o n t r o l f rames. These are analogous to the f rame e x t e n s i o n s o f [BW]. C o n t r o l f r ames c o n t a l n va r l ous temporary q u a n t i t i e s , a CLINK p o l n t e r to a p rev lous c o n t r o l f rame, and an ALINK po in te r to the current access frame.

,.x I use I s'zE CLINK -" AL]NK e,

Tf.HPORARY 1 TEMPORARY Z

( 3 ) Dynamic b l n d l n g f rames. These are s l m l l a r to c o n t r o l f rames, but a lso con ta in name-value p a i r s f o r dynamic v a r i a b l e lookup. A dynamic b ind ing frame may also have an a d d i t i o n a l DLINK p o i n t e r to the previous dynamic b ind ing frame. The DLINK p o i n t e r i s no t l o g i c a l l y necessary , s ince the same frame can be found by f o l l o w i n g the CLINK chain, but can speed up the search in the case o f deep access, or the contex t swi tch in the case o f shal low access.

60

Page 2: Macaroni is better than spaghetti

---':'3. ~ = I USE I SlZE CLINK @

ALINK •

DLINK 4k

DYNAHIC NAME 1

OYNARIC VALUE 1

. , .

DYNAHIC NAME M

OYNAMIC VALUE M

TEMPORARY 1

TEMPORARY 2

..o

TERPORARY N

3~

(4) Funarg ob jec t s . Each funarg ob jec t con ta ins a p o i n t e r to a piece of code and an ALINK p o i n t e r t o the access frame w i t h r espec t t o which t he code i s c losed.

(5 ) Escape f u n c t i o n o b j e c t s . These are o b j e c t s s i m i l a r to those created by Land ln 's J - o p e r a t o r [ L a n d t n ] , Reynold 's escape cons t ruc t [Reyno lds ] , o r SCHEHE's CATCH cons t ruc t [SCHEHE]. An escape f u n c t i o n ob jec t conta ins a CLINK p o i n t e r to some c o n t r o ! f rame, and a l so a c o r r e s p o n d i n g DLINK p o i n t e r s I f such p o i n t e r s are used by dynamic b i nd ing frames.

[ 0L,N I CLI.K

Our m o d e l d i c t a t e s t h a t t h e r e be a d i s t i n g u i s h e d r e g l s t e r CURCLINK which po in t s to the c o n t r o l frame being run In . ( In the mu l t i p rocess tng case, t h e r e would be a CURCLINK f o r each p rocess , b u t we s h a l l n o t go i n t o t h e d e t a i l s o f m u l t t p r o c e s s t n g h e r e . ) I f DLINKs are be ing used, t he re must a lso be a CURDLINK. We s h a l l assume the use o f DLINKs, and de te rmine whether the c u r r e n t c o n t r o l frame ls a dynamic b ind ing frame by means o f the t e s t CURDLINK = CURCLINK. I f DLINKs a re n o t used, a l l code r e l a t i n g to them shou ld be I g n o r e d here , and another means prov ided f o r d i s t i n g u i s h i n g dynamic b ind ing frames from o rd i na ry c o n t r o l f rames.

A l l c o n t r o l frames which are not c u r r e n t are " s e a l e d ' , and must conta in a c o n t i n u a t i o n p o i n t , a p o i n t e r t o the code to execute on r e t u r n to t h a t c o n t r o l f rame. In [BW] t h i s c o n t i n u a t i o n p o i n t i s shown in a f i x e d l o c a t i o n In the frame e x t e n s i o n , b u t I t i s o f t e n more c o n v e n i e n t t o push t h e c o n t i n u a t i o n po in t onto the end j u s t be fo re s e a l i n g I t , and pop I t on unseal ing I t ( p o s s i b l y r e p l a c i n g i t w i t h a re tu rned v a l u e ) .

We now p r e s e n t s c e n a r i o s f o r t he common o p e r a t i o n s .

C a l l i n g a f u n c t i o n . We have a funarg ob jec t f o r a f u n c t i o n we wish to c a l l , we know how many arguments t o g i ve i t , and we w i l l ca l cu l a t e the arguments on t h e f l y .

C a l l Functton(FNARG, Number of Args) l e t A = A l l o c a t e Access Frame(Number of Args) t_nn

begin A.ALINK ~ Grab Access Frame(FNARG.ALINK); f o r I from 1 to Number of Args d_£

A.VALUE3[I] ~- Ca lcu la te Argument ( i ) ; Release Access Frame(CURCLINK.ALINK); CURCLINK.ALINK~- A; go t o(FNARG.CODE)

end

Note t h a t no c o n t r o l frame i s pushed; our model p reserves the impor tan t p rope r t y o f t a i l - r e c u r s i o n . 3ee "Push Return Address" below.

A p p l i c a t i o n . Th i s b reaks down I n t o two c a s e s : o r d i n a r y funargs and escape func t i ons .

Apply(FUN, ARGLIST) • case type(FUN) In

Funarg: Apply Funarg(FUN, ARGLIST);

Escape Funct ion: App ly Escape Function(FUN, ARGLIST);

esac

A p p l y i n g a f u n a r g . We have a f una rg o b j e c t f o r a f u n c t i o n and a computed l i s t o f arguments.

App ly Funarg(FNARG, ARGLIST) • l e t A = A l l o c a t e Access Frame(length(ARGLlST)) l_p_n begi.

A.ALINK ~- Grab Access Frame(FNARG.ALINK); comment This fo._.E loop steps [ and X in

p a r a l l e l ; for" I from 1, X i_nnARGLIST do

A.VALUE3[I] *- X; Release Access Frame(CURCLINK.ALINK); CURCLINK.ALINK~- A; go t_.£o(FNARG.CODE)

end

C rea t i ng a funarg . We have a piece o f code and wish t o c lose i t In the cu r ren t envi ronment .

Cons Funarg(CODE) • l e t F = A l l o c a t e Funarg Ob jec t ( ) i_nn

begin F.CODE ~- CODE; F.ALINK *- Grab Access Frame(CURCLINK.ALINK); F

end

Note t h a t a funarg po in ts on ly to chains o f access f rames, and r e t a i n s no c o n t r o l f rames. Under t h e dynamic b i nd ing model o f [BW], funargs r e t a i n frame ex tens ions even though they w i l l never be used.

61

Page 3: Macaroni is better than spaghetti

E v a l u a t i n g a sub-combina t ion . As ment ioned above and discussed more thoroughly in [ D e c l a r a t i v e ] , the l o g i c a l l y c o r r e c t t lme to push " c o n t r o l s t ack " i s when commencing eva luat ion of a sub-combinat ion, not when c a l l i n g a func t ion . ThUS:

Push Return Address(Continuation Point ) • begin

Push(Continuat ion Point , CURCLINK); le__tt C = A l l oca te Control Frame(.) Ln

begin C.CLINK~- CURCLINK; E.ALINK *- Grab Access Frame(CURCLINK.ALINK); CURCLINK~- C

end en__.dd

Dynamic B ind ing . We have a se t o f v a r i a b l e names (which may be po in te rs to atomic symbols, addresses o f value c e i l s , or anything else tha t can be given to the dynamic lookup rou t ine to locate a va lue) and a corresponding set o f values. Here we s h a l l assume the deep access method, in which the va lues are p laced on the s tack . As f o r the c r e a t i o n o f an escape func t ion , at t h i s po in t we should be running in a f resh c o n t r o l f rame, which w i l l be conve r t ed i n t o a dynamic b ind ing frame.

Blnd Dynamic Vartables(NANELIST, VALUELIST) • begin

PUSH(CURDLINK, CURCLINK); comment This code l s f o r deep access; f o r N In NAMELIST, V LnVALUELIST do

begln PUSH(N, CURCLINK); PUSH(V, CURCLINK);

end; CURDLINK~- CURCLINK

end

R e t u r n f rom f u n c t i o n . We have computed one o r more v a l u e s , and w i s h t o r e t u r n f rom t h e c u r r e n t c o n t r o l f rame. (See [ D e c l a r a t i v e ] f o r a d iscussion of why i t i s on ly p r i m i t i v e operators which ever do t h i s , and how such operators can be accomodated In a LISP- l i k e language.)

Return from Contro l Frame(VALUES) = l e t A = CURCLINK.ALINK,

C = CURCLINK.CLINK I n begln

comment I f we use shal low access f o r dynamic va r i ab les , t h i s i s the place t o r e s t o r e the o ld bindings i f t h i s i s a dynamic b indings frame;

l_ff CURDLINK = CURCLINK t h e n begin

Undo Dynamic B ind ings( ) ; CURDLINK(- CURCLINK.DLINK

end; comment Because we are running in the current

con t ro l frame, CURCLINK is the on ly reference to i t ;

Delete SegNent(CURCLINK); Release Access Frame(A); CURCLINK~- C;

Ensure Runnab t l i t y ( ) ; comment The cont inuat ion po in t Is on the top

of the new con t ro l frame, and we s h a l l rep lace i t w i th the returned va lues;

l e t X = Pop(CURCLINK) 1._nn begin

f o r Y In VALUES do PUSH(Y, CURCLINK); go t_9(x)

en_dd end

C r e a t i n g an escape f u n c t i o n . We want to c r e a t e a new access frame w i t h a va lue in I t which is an escape f u n c t i o n . We should have j u s t en te red a f resh c o n t r o l frame (which w i l l be the case i f the escape expression Is a sub- form o f a c o m b i n a t i o n , f o r example); I f not , we must f i r s t have sealed the c u r r e n t c o n t r o l frame w i t h a r e t u r n address and created a new one. The actua l c rea t ion and b ind ing o f the escape func t ion Is s i m i l a r to the process o f en te r i ng a func t i on ; i t requ i res the c rea t i on o f an access frame, but not of a con t ro l frame.

Blnd Escape Funct ion() • le__tt E = A l l oca te Escape Function Ob jec t ( ) ,

A = A l l o c a t e Access Frame(l) l_nn begin

E.CLINK *- Grab Control Frame(CURCLINK.CLINK); comment The cur rent frame cannot be a dynamic

b lndtng frame; E.DLINK~- CURDLINK; A.VALUES[I] *- E; A.ALINK~- CURCLINK.ALINK; CURCLINK.ALINK4- A

end

A p p l y l n g an escape f u n c t i o n . We have an escape f u n c t l o n o b j e c t and a l i s t o f the v a l u e ( s ) t o be re tu rned .

Apply Escape Functlon(ESCFUN, ARGLIST) • begln

comment I f shal low dynamic b ind ing ls used, I t takes some e f f o r t to change CLINKs, and there is a lso the mat ter o f e x i t func t ions (see below);

Switch Dynamic Context(CURCLINK, ESCFUN.CLINK); Release Contro l Frame(CURCLINK); CURCLINK (- Grab Control Frame(ESCFUN.CLINK); CURDLINK(- ESCFUN.DLINK; Ensure R u n n a b l l l t y ( ) ; le_~tX = POP(CURCLINK) l_nn

begin f o r Y In ARGLIST d_9o PUSH(Y, CURCLINK); go Lo(X)

end en__dd

Here are some of the u t l l l t y rou t lnes assumed by the func t i ons Just presented. Thel r pr imary purpose Is to enforce a reference-count storage d i s c i p l i n e on the frames.

Grab A c c e s s Frame(A) • i f A ~ NIL t h e n A.USE +- A.USE + 1

62

Page 4: Macaroni is better than spaghetti

6rab Con t ro l Frame(C) • i f C # NIL then C.USE 4- C.USE + 1

Release Access Frme(A) , l_ff A ~ NIL then

begin A.USE ~- A.USE - 1; i_ff A.USE = 0 then

le.._.t.t B = A.ALINK l_nn begin

Delete Segment(A); Relea se Access F r u e ( B )

end end

Release Con t ro l Frame(C) • i f C * NIL then

begin C.USE ~- C.USE - 1; I f C.USE = 0 then

1 e t a = C.ALINK, B = C.CLINK t_nn begin

Delete Segment(C); Release Access F rme(A ) ; Release Cont ro l Frame(B)

end en__d_d

Ensure R u n n a b l l l t y ( ) • i t" CURCLINK.USE > 1 the.~n

begin CURCLINK.USE ~- CURCLINK.USE - 1; CURCLINK 4- Copy $egmenZ(CURCLINK); CURCLINK.ALINK.USE ( - CURCLINK.ALINK.USE + 1

end e l se i f Not Enough Room to Run() then

le_~t C = Copy 3egment(CURCLINK) i n begin

Delete Segment(CURCLINK); CURCLINK~- C

end

The p r i m i t i v e s "A l l oca te Access Frame" and " A l l o c a t e C o n t r o l Frame" are assumed to i n i t i a l i z e the U~E f i e l d o f the newly a l l o c a t e d frame to 1. See [BW] f o r a d e s c r i p t i o n o f the opera t ion o f the p r i m i t i v e "De le te Segment' .

E x i t f unc t i ons

E x l t f u n c t i o n s , as d e s c r i b e d i n [BW], were n o t i m p l e m e n t e d i n I n t e r L I S P [ T e t t e l m a n ] , w h i c h c o n t a i n s , t o ou r know ledge , t he o n l y w o r k i n g Implementa t ion o f spaghe t t i s tacks. ( In f a c t , the o n l y language we know o f which implements g e n e r a l e x i t f u n c t i o n s Is ITS TECO! [TECO]) Th is may be because they are o f marg ina l u t i l i t y , or because f o r some purposes they are e a s i l y s imulated by the user . Le t us denote a dynamic v a r i a b l e by p r e f i x i n g i t w i t h a co lon ; then we might w r i t e :

((L/~BDA ( : V ) ( (L~BDA (GO001)

(COND ((NULL :V) 60001) (T (FUNCALL :V G0001)) ) )

<form>)) NIL)

(The HacLISP f u n c t i o n FUNCALL Is the same as t he In te rL ISP f unc t i on APPLY*; i t Is e s s e n t i a l l y a way o f d e f e a t i n g t he c o n v e n t i o n t h a t t h e f u n c t i o n p o s i t i o n o f a c o m b i n a t i o n i s " e v a l u a t e d N i n a d i f f e r e n t way from the argument p o s i t i o n s . Thus the f i r s t argument to FUNCALL is c a l l e d as a f u n c t i o n on the r e s t of the arguments.)

Now t h i s code w i l l b i nd :V d y n a m i c a l l y t o NIL and then execute <form>. I f :V i s ever se t non- n i l , then I t w i l l be run as an " e x i t f u n c t i o n " on the va lue o f the form.

This does no t behave p r e c i s e l y as an e x i t f u n c t i o n as desc r i bed in [BW] wou ld , because e x i t f u n c t i o n s a r e supposed t o be run even when t h e system i s sk ipp ing out o f the frame, as f o r a non- l o c a l go to o r an e r r o r . There a re , however , a c o u p l e o f d i f f i c u l t i e s h e r e . One i s t h a t t h e s p a g h e t t i s tack model does not p rescr ibe what va lue to feed to the e x i t f unc t ion In the case o f a non- l o c a l e x i t ( the desc r i p t i ons of "Setexfn" and " E x i t Access Frame" do not cover t h i s case) . I t p robab l y ough t t o r e c e i v e a b i t o f i n f o r m a t i o n d e s c r i b i n g wh,~ther t he e x i t Is normal or n o n - l o c a l . A n o t h e r pr( ,b lem i s t h a t c o n t r o l frames may be n o n - l o c a l l y e n l e r e d ! E x i t f u n c t i o n s are desc r i bed as b e i n g u s e f u l f o r c l o s i n g f i l e s , f o r example; i t wou ld seem t h a t i f such a frame were re -en te red , thanks to the use o f an "escape" f u n c t i o n , we migh t want t o re-open the f i l e !

This l a t t e r problem Is s i m i l a r t o t h a t o f hand l i ng shal low-access dynamica l l y bound v a r i a b l e s du r i ng a c o n t r o l con tex t swi tch. I t i s necessary to f i n d some p o i n t In the c o n t r o l t r e e which Is an a n c e s t o r ( a c t u a l l y a descendant , c o n s i d e r i n g t he d i r e c t i o n o f the po in te r s ) o f both the o ld and the new c o n t e x t , and then t r a v e l a path from o ld c o n t e x t t o "Jo in p o i n t " to new con tex t , updat ing v a r i a b l e s [ G r e e n b l a t t l ] [ B a k e r l ] . One needs to do a s i m i l a r t h i n g f o r " e x i t f u n c t i o n s ' ; one should t r a v e l f rom o l d c o n t e x t t o j o i n p o i n t , r u n n i n g a l l e x i t f u n c t i o n s , and then from j o i n po in t to new c o n t e x t , runn ing a l l e n t r y func t ions . (Presumably the e x i t f u n c t i o n and e n t r y func t ion f o r a g iven frame should be i n v e r s e s . ) In a simple case, such as a n o n - l o c a l e x i t , the new con tex t Is the Join p o i n t , and e n t r y f u n c t i o n s are not needed; but they are necessary in t h e g e n e r a l case , such as f o r generators (see be low) .

The s imu la t i on descr ibed above doesn ' t work f o r n o n - l o c a l e x i t s , and so the e n t r y / e x i t - f u n c t i o n f a c i l i t y must be b u i l t - I n . However, i t i s p robab l y b e t t e r t o r e q u i r e the user t o e x p l i c i t l y s p e c i f y when one l s necessary, r a the r than a l l o w i n g him to p i c k any f rame and patch one i n . Thus one m i g h t ~ i t e :

(EXITBIND (LNIBDA (VALUE NORMALP)

(PROGN (3ETQ SAVED-FP03 (FILEPOS THE-FILE))

(CLOSE THE-FILE) VALUE))

(LNIBDA ( ) (PROGN (OPEN THE-FILE)

(FILEPO3 THE-FILE SAVED-FPOS)))

<body>)

63

Page 5: Macaroni is better than spaghetti

This would execute (body) In a frame marked as having exlt and entry functions. We have represented the exlt function as taking the value end a switch. We are not sure what arguments the entry function should receive; there is also the matter of whether the entry function should be invoked on the first (normal) entry to the construct. Although exit functions, as a generallzation of the context-swltching mechanism, wlll probably prove Invaluable In future languages, we dld not Include handling of exlt functions In the routines presented above because of these present u n c e r t a i n t i e s . {Note Binding P r i n c i p l e }

Omitted Features

We have purposely omitted certain features from our model which were provided in [BN]. We omit relatlve evaluation because we do not want to be constrained to store names In access frames. Hore accurately, we do not wish to commit ourselves to a partlcular format for names; names may be represented as atomic symbols, addresses of value cells, effective addresses of machine instructions, etc. A name ls any entity whlch'allows one to identify the value represented by the name. It would be possible to provide relative evaluation for dynamlcally-bound variables, because for those we do effectively have to use a single, system-wide representation of names.

Hore generally, we suggest that the user not be given access to frame pointers, but only to primitives such as funargs and escape functions whlch may be implemented In terms of frames. This Is to reduce the dependence of user programs on a particular implementation.

As a corollary, the concept of a framename i s unnecessary , because t h e r e i s no need to r e f e r d l r e c t l y t o f rames. The p r i m i t i v e o p e r a t i o n s we p resen t here have no need to search dynam ica l l y f o r frames of a p a r t i c u l a r name. {Note Debugging}

Generators and Corouttnes

Of In terL ISP users who make n o n - t r i v i a l use o f t he s p a g h e t t i - s t a c k f e a t u r e , a lmos t a l l use i t a l m o s t e x c l u s i v e l y t h r o u g h t he g e n e r a t o r s and co rou t t nes f e a t u r e . [Kap lan ] For some reason, the c o r o u t t n e Implementat ion descr ibed in [BW] r e q u i r e d t h e u s e r t o s u p p l y t o t he "Resume" p r i m i t i v e a f u n c t i o n w i t h w h i c h t o c o n t i n u e t h e c u r r e n t c o r o u t i n e on resumpt ion. This was p robab ly so t h a t r e s u m p t i o n cou ld pass more than one v a l u e between c o r o u t l n e s . Th is has v e r y much the f l a v o r o f t he " c o n t i n u a t i o n - p a s s i n g s t y l e " o f coding. We p resen t here our ve rs ion o f t ha t approach:

Start(FNARG, ARGLIST) • beg in

CURPROC e- FNARG; Apply(FNARG, ARGLIST);

end

Resume(FNARG, ARGLIST, BACKFN) • begin

CURPROC.CODE ~- BACKFN.CODE; Release Access Frame(CURPROC.ALINK); CURPROC.ALINK 4- Grab Access Frame(BACKFN.ALINK); CURPROC 4- FNARG; Apply(FNARG, ARGLIST);

en___dd

This implementat ion of co rou t tnes has g r e a t appea l , because i t makes i t c l ea r t ha t t he re i s o n l y one " r e a l " th read o f c o n t r o l running among a l l the c o r o u t t n e s . A co rou t l ne funarg does no t r e t a i n any c o n t r o l s tack ; the user must summarize the s t a t e o f t he c o r o u t l n e In the funa rg BACRFN, which r e t a i n s o n l y s t a t i c a c c e s s f r a m e s . ( R e c a l l t h e c o n t i n u a t i o n - p a s s i n g v e r s i o n o f an o r d i n a r y f u n c t i o n , in which there Is no " r e a l " c o n t r o l s tack , b u t t h e c o n t r o l s t a t e i s s i m u l a t e d by means o f funarg env i ronments. [ I m p e r a t i v e ] [ D e c l a r a t i v e ] )

The usua l approach, however, I s t o a l l o w each "Resume" to spec i f y a va lue which becomes the v a l u e o f the "Resume m c a l l o f the resumed process. We see no d i f f i c u l t y w i th func t i ons r e t u r n i n g more than one va lue , and so the re i s no d isadvantage to u s i n g t h i s t echn ique ( o t h e r than t h a t i t r e q u i r e s t h e r e to be more than one " r e a l m c o n t r o l s t a c k ) . We t h e r e f o r e r e w r i t e the co rou t l ne p r i m i t i v e s In terms o f escape f u n c t i o n s :

3tart(FNARG, ARGLIST) • beg in

comment I n i t i a l l y CURPROC must be set to an escape f unc t i on ;

Swap Out Co rou t i ne ( ) ; CURCLINK ~- A l l o c a t e Cont ro l Frame(); CURCLINK.CLINK(- NIL; CURCLINK.ALINK4- NIL; CURPROC ~- A l l o c a t e Escape Funct ion O b j e c t ( ) ; App ly Funarg(FNARG, ARGLIST);

end

Resume(ESCFUN, ARGLIST) • beg in

Swap Out Co rou t t ne ( ) ; CURPROC ~- ESCFUN; comment A c t u a l l y , r a t he r than c a l l i n g A p p l y

Escape Funct ion, we ought to do what i t does but a l so set CURPROC.CLINK (and a lso CURPROC.DLINK, f o r neatness, though i t l s n ' ¢ necessary) to NIL so t ha t CURPROC w i l l no t unnecessa r i l y r e t a i n c o n t r o l f rames;

App ly Escape Functlon(ESCFUN, ARGLIST); end

Swap Out Co rou t i ne ( ) • beg in

Release Con t ro l Frame(CURPROC.CLINK); CURPROC.CLINK~

Grab Cont ro l Frame(CURCLINK.CLINK); comment The cu r ren t c o n t r o l frame must no t be a

dynamic b ind ing frame; CURPROC.DLINK~- CURDLINK;

end

64

Page 6: Macaroni is better than spaghetti

I f escape functions are used only for this purpose, it is easy to see that the control frames do not form trees, but o n l y a forest of stacks. {Note Stack Groups}

Each of these implementations of coroutines has the property that no more control stack is retained for the coroutlnes than necessary; the first retains none, and the second only the relevant control stack for each coroutine. The implementation in [BW] had the problem that every coroutine retained the control stack of its creator in order to retain the environment also. {Note ENVEVAL Trick}

Storage Allocation

In the simple cases, control and access frames are allocated alternately as the control stack grows, and de-allocated alternately as t h e control stack shrinks. This is true even if the structures are not parallel; the control stack may grow linearly while the access stack becomes a "leafy tree". As long as no funargs are created, the access frames can be de-allocated alternately with the control frames.

If downward funargs are used, then when the control stack shrinks back, it may be possible to de-allocate an access frame except for the fact that a funarg object points to it, and it would require a garbage c o l l e c t i o n to de te rmine t h a t the f u n a r g object is actually garbage. {Note Stack Allocation} In the case of an upward funarg, it would actually be impossible to de-allocate an access frame. Finally, i n t h e c a s e of an Iterative (tail- recurslve) loop no control frames are allocated or de-allocated, but access frames may be alternately allocated and released at a great rate.

These cases will lead to fragmentation of the stack area of control and access frames are actually allocated alternately. Ne suggest a11ocatlng control frames from the bottom up and access frames from the top down to avoid this fragmentation. In the simple case, each end of the stack area will grow and shrink as a stack. In the funarg cases, the control stack will remain stack- llke without fragmentation as the access frame area becomes possibly fragmented. In the iteration case, the control stack will be stacklike while the access frames chase around a r i ng bu f f e r , in e f f e c t , a t t he o t h e r end. {Note Reusing Access Frames}

[ B a k e r Z ] i n d i c a t e s t h a t a h y b r i d s t o r a g e a l l o c a t i o n scheme using both garbage c o l l e c t i o n and reference counts may be inferior to a system using pure garbage c o l l e c t i o n . I f so, i t would be b e t t e r t o use h i s garbage c o l l e c t o r and s imply a l l o c a t e a l l f rames in the heap. In p r a c t i c e t h i s may depend c r i t i c a l l y on the p a r t i c u l a r hardware used.

Acknowledgements

Daniel Bobrow, Alice Hartley, Ron Kaplan, and Narren Teltelman were most patient in describing the Implementation and use of spaghetti stacks in InterLISP. Comments by Gerald Jay Sussman, Jon Doyle, Johan de Kleer, and Richard Stallman were a l s o h e l p f u l .

Notes

{Note B ind ing P r i n c i p l e ) Our dec is ion to use a spec ia l " b i n d i n g - t y p e "

c o n s t r u c t f o r e x i t f unc t ions was guided by a genera l princlple: anything you can do by assignment, except communicating with other processes, can probably be accompllshed more clearly by binding, because the extent of the effect is contained in an obvious way. The use of "8etexfn" in [BN] may be compared to the use of the ALTER statement in COBOL. The use of a binding primitive also avoids the n e c e s s i t y to compose user and system e x i t f u n c t i o n .

{Note Debugging} Framenames, l i k e v a r i a b l e names in access

f rames, may be use fu l f o r debugging, but should no t be r e q u i r e d f o r the c o r r e c t e x e c u t i o n o f t he user program. One shou ld draw a d i s t i n c t i o n between programs such as debuggers and c o m p i l e r s , wh ich depend on the p a r t i c u l a r r e p r e s e n t a t i o n o f o t h e r p rograms, and programs which depend on t h e i r own particular representation. Programs o f the latter kind cannot easily take advantage of new Implementatlon techniques which Involve different representations.

{Note Stack Groups} The fact that generators are the primary use

of spaghetti stacks In InterLISP leads us to specu la te t h a t the less genera l "s tack group" model p r o p o s e d b y G r e e n b l a t t f o r t h e LISP m a c h i n e [ G r e e n b l a t t Z ] may be adequate f o r many purposes . This model p rov ides m u l t i p l e sets o f c o n t r o l s tacks , w i t h o u t a l l o w i n g f o r a genera l t r ee s t r u c t u r e . This model has now been implemented on the LISP Machine a t NIT.

{Note ENVEVAL Trick} Ron Kaplan [Kaplan] tells us that a certain

system in InterLISP creates several generators as it is being loaded for use at run time, and that speclal pains must be taken, using the ENVEVAL primitive, so that the control stack of the loader w i l l n o t be r e t a i n e d by the c o n t r o l s tacks o f t he gene ra to r s .

{Note Stack A l l o c a t i o n } Some l a n g u a g e s , such as ECL [ C o n r a d ]

[ N e g b r e l t ] , p r o v i d e f o r s t a c k a l l o c a t i o n o f a r b i t r a r y , da ta ob jec ts , which might a l l e v i a t e t h i s problem.

{Note Reuslng Access Frames} In many Iteratlve sltuatlons it is easy for

a compiler to detect that a provided access frame will be thrown away on tall-recurslon to another function; if the frame for the called function is t he same s i z e ( o r s m a l l e r ) than the one f o r t he c a l l i n g f u n c t i o n , the compi ler may arrange to re -use the frame r a t h e r than a l l o c a t i n g a new one. This Is s i m i l a r t o some o f the ideas i n [ D a r l t n g t o n and Burs ta11 ] , but more l i k e l y to be a p p l i c a b l e because the comp i l e r can o f ten determine a b s o l u t e l y t h a t the frame i s t o be d iscarded.

65

Page 7: Macaroni is better than spaghetti

References

[Baker l ] Baker, Henry B., Jr. Shallow Binding in LISP 1.5. AI Working Paper 138. HIT AI Lab (January i977).

[Baker2] Baker, Henry B., Jr . L is t Processing in Real Time on a Ser ia l Computer. AI Working Paper 139. HIT AI Lab (February 1977). To appear in Comm. ACH.

[ ~ ] Bobrow, Danlel O. and Wegbrelt, Ben. "A Model and Stack Implementation of Multiple Environments. = CACM 4, I0 (October 1973) pp. 591-603.

[Conrad] Conrad, William R. Internal Representations of ECL Data Types. Technical Report 5-75. Center for Research In Computing Technology, Harvard U. (Cambridge, March 1975).

[Darllngton and Burstall] Darllngton, J., and Burs ta l l , R.M. "A System whlch Automatically Improves Programs." Acta Informatlca 6 (1976), 41-60.

[ Declarat ive ] Steele, Guy Lewls Jr . LAMBDA: The Ul t imate Declarative. AI Nemo 379. MIT AI Lab (Cambridge, November 1976).

[ O r e e n b l a t t l ] O r e e n b l a t t , R lchard . The LISP machine. Artlflclal I n te l l i gence Working Paper 79, HIT (Cambridge, November 1974).

[Oreenblatt2] Personal communications with Rlchard Oreenblatt (March 1978).

[ Imperat ive] Steele, Guy Lewis Jr . , and Sussman, Gerald Jay. LMIBDA: The Ultimate Imperative. AI Memo 353. MIT AI Lab (Cambridge, March 1976).

[Landln] Landtn, Peter J. "A Correspondence between ALGOL 60 and Church's Lambda-Notation." CACM 8, 2-3 (February and March 1965).

[Kaplan] Persona l communicat ions (February 1977).

w i th Ron Kap lan

[Reynolds] Reynolds, John C. =Definitional Interpreters for Higher Order Programming Languages." ACM Conference Proceedings 1072.

[SCHEME] Sussman, Gerald Jay, and Steele, Guy Lewis Jr. SCHEME: An Interpreter for Extended Lambda Calculus. AI Memo 349. NIT AI Lab (Cambridge, December 1975).

[TECO] There Is no published reference for ITS TECO, but those with ARPANET access can re t r ieve the f l l e ".INFO.;TECO ORDER" ~ MIT-AI. See the FN command therein.

[Teltelman] Teltelman, Warren, et al. InterLISP Reference Manual. Revised edition. Xerox Palo Alto Research Center (Palo Alto, 1975).

[Wegbrelt] Wegbrelt, Ben, et al. ECL Programmer's Manual. Technical Report Z3-74. Center for Research In Computing Technology, Harvard U. (Cambridge, December 1974).

66