Папулярным метадам для дасягнення належнага рэкурсіі хвост не ў хваставой рэкурсіяй рэалізацыі З батуце. [2] батут вонкавая функцыя якога ітератівно званкі ўнутраная функцыя. Унутраная функцыя вяртае адрас іншай функцыі выкліку, а таксама вонкавая функцыя, тое заве гэту новую функцыю. Гэта значыць, калі ўнутраная функцыя жадаў бы звярнуць іншага ўнутраная функцыя хваста рэкурсіўна, яна вяртае адрас функцыі яна жадае, каб ператэлефанаваць на батуце, які затым выклікае вяртаецца функцыяй. Па вяртанні перад выклікам, стэк першы выскачыў так, што яна не расце неабмежавана на простай ітэрацыі. Нажаль, кошт такіх батуце выкліку функцыі ў 2-3 разу павольней, чым звычайны выклік C, і яна патрабуе, каб аргументы перадаюцца ў глабальных зменных [Tarditi92].
неапублікаваныя прапанова Аппеля для дасягнення належнага рэкурсіі хвост у C выкарыстоўвае значна больш фіксаванага памеру стэка, працяг абыход стылі, а таксама не ставіць якіх-небудзь аргументаў ці дадзеных на C стэка. Калі стэк пра перапаўненне, адрас наступнай функцыі выклік longjmp 'Эд (ці вяртанне "ЭД) на батуце. Метад Аппеля пазбягае прыняцці вялікага ліку дробных адмоў батуце час ад часу, каб саскочыць з Эмпайр Стейт Білдінг.
З Са "Стэк" ніколі не кантракты, мы можам вылучыць усе нашы замыканні і карыстацкіх дадзеных структур на гэты стэк, як аўтаматычная / дынамічная / лакальных дадзеных. Усе засаўкі і карыстацкія дадзеныя структуры, памеры якіх вядомыя падчас кампіляцыі статычна вылучана ў Са "Стэк" рамкі; дынамічных масіваў і іншых структур дадзеных, памер якіх невядомы падчас кампіляцыі могуць быць вылучаны па's ALLOCA З прымітыўныя (ці эквівалент), якія таксама атрымлівае месца, пачынальна са "Стэк". [3] Бо наш C "Стэк", таксама "кучы", не існуе адрозненні паміж стэка і кучы размеркавання.
Паколькі ніводная з нашых функцый C калі-небудзь вяртаецца, толькі жыць на гэтым кадры "Стэк" з'яўляецца верхняя. Аднак, у шматлікіх з мёртвых кадраў будзе знойдзены жыць замыканні і жыць карыстацкіх дадзеных аб'ектаў. Урэшце, Са "стэк" будзе перапаўненне прасторы, ускладзеныя на яго, і мы павінны выконваць збор смецця. Вываз смецця (GC) шляхам капіявання з'яўляецца адносна прамы наперад працэсу. Ёсць цэлы шэраг статычных карані, а таксама апошнія працяг зачынення, якая перадаецца ў ГК у якасці аргументу. (Фармаванне відавочнае зачыненне працягу для GC дазваляе пазбегнуць неабходнасці сканавання C кадраў стэка.) Жывыя аб'екты і жыць замыканні ўсіх скапіяваных (і тым самым кандэнсату) у іншую вобласць, так што пакаранне смерцю можа быць перазапушчаны "Сцёк" кадр Пачатак Са "Стэк" вылучэнне вобласці.
Ключавым момантам з'яўляецца тое, што бо толькі жывыя аб'екты прасочваюцца - гэта значыць, смецце (у тым ліку C кадраў, якія ўсе мёртвыя) не прасочваецца - ГК не павінны ведаць, фармат кадра стэка і можа быць запісаны ў сябе. З Чейні стылі сканар павінен ведаць фармат усіх tospace аб'ектаў, але мы капіюем толькі тыя аб'екты, - ніколі C кадраў. Калі GC будзе зроблена, ён стварае новыя рамкі для выканання яе працяг. GC завецца відавочна з кода C ці пасля праверкі паказальнік стэка дасягнула зададзенай мяжы. Хоць стэк-паказальнік праверкі такім чынам, можа запатрабавацца яшчэ некалькі каманд, чым калі б гэта было зроблена на асэмблеры, гэта яшчэ хутчэй, чым батуце выкліку будзе.
/* The following macro definition is machine-dependent. */
#ifdef stack_grows_upward
#define stack_check(sp) ((sp) >= limit)
#else
#define stack_check(sp) ((sp) <= limit)
#endif
...
object foo(env,cont,a1,a2,a3) environment env; object cont,a1,a2,a3;
{int xyzzy; void *sp = &xyzzy; /* Where are we on the stack? */
/* May put other local allocations here. */
...
if (stack_check(sp)) /* Check allocation limit. */
{closure5_type foo_closure; /* Locally allocate closure with 5 slots. */
/* Initialize foo_closure with env,cont,a1,a2,a3 and ptr to foo code. */
...
return GC(&foo_closure);} /* Do GC and then execute foo_closure. */
/* Rest of foo code follows. */
...
}
Пасля GC вырабляецца капіяванне, ён павінен скінуць C сцёк паказальнік на пачатак вобласці размеркавання і выклікаць яго працяг аргумент. З GC сама выконвала з рамы ў fromspace, яна павінна выклікаць паказальніка стэка для скіду з вылучэннем вобласці ў tospace а затым выклікаць яго працяг. Адзін са спосабаў перасоўвання паказальніка стэка для GC тэлефанаваць ALLOCA функцыі з аргументам, які з'яўляецца розніца - дадатнае ці адмоўнае -! Паміж бягучага паказальніка стэка і жаданага паказальніка стэка. Тады, GC можа выклікаць яго працяг.
(Альтэрнатыўны метад, прапанаваны Аппель варта SML / NJ больш цесна -. Пасля аператыўныя дадзеныя былі скапіяваны ў іншым месцы гэта малаважныя калекцыі - GC можа longjmp на батуце (ці проста вярнуць яе аргумент!) І батут будзе перазагрузіць працяг паказальнік стэка вылучэння ў ніжняй частцы стэка зноў. Пры агульнай скапіяваныя дадзеныя ў другой вобласці перавышае вызначаную суму, асноўныя калекцыі ажыццяўляецца на другой вобласці.)
object revappend(cont,old,new) object cont,old,new;
{if (old == NIL)
{clos_type *c = cont;
/* Call continuation with new as result. */
return (c->fn)(c->env,new);}
{cons_type *o = old; cons_type newer; /* Should check stack here. */
/* Code for (revappend (cdr old) (cons (car old) new)). */
newer.tag = cons_tag; newer.car = o->car; newer.cdr = new;
return revappend(cont,o->cdr,&newer);}}
Замыканні, памер якіх заўсёды вядомыя кампілятар, відавочна пабудаваных у мясцовых кадраў у аналагічным чынам. Вектары і масівы, памер якіх невядомы падчас кампіляцыі могуць быць вылучаны па тэлефоне ALLOCA (ці яго эквівалент), каб пашырыць бягучага кадра стэка. (Гл. таксама ніжэй частка, прысвечаны Malloc-вылучаных аб'ектаў.) Ключавой асаблівасцю нашай схемы з'яўляецца тое, што зборшчык смецця пазбаўляе ад неабходнасці адсочвання смецця, і, такім чынам, не трэба ведаць фармат гэтага смецця, які складаецца з усё C кадраў стэка. У кошт увесь час праверкі і пасля перасылання паказальнікі, мы маглі б зрабіць нашы схемы "рэальным часе" [Baker78]. папярэдняй працы[Baker92] таксама выступае вылучэнні аб'ектаў у стэку ў лакальнай сістэме C. Аднак, бягучая схема прасцей, бо яна не патрабуе, каб аб'екты перадаюцца дынамічна падчас выканання. У нас ёсць рукі-пераклад Бойер Benchmark у З выкарыстаннем метадаў гэтай працы [cboyer13.c] .
[Appel89] Appel, A.W. "Simple Generational Garbage Collection and Fast Allocation". Software--Practice and Experience 19, 2 (Feb. 1989), 171-183.
[Appel90] Appel, A.W. "A Runtime System". Lisp and Symbolic Computation 3, 4 (Nov. 1990), 343-380.
[Appel91] Appel, A.W., and MacQueen, D.B. "Standard ML of New Jersey". In Wirsing, M., ed. Third Int'l Symp on Programming Language Implementation and Logic Programming, Springer, August 1991.
[Baker78] Baker, H.G. "List Processing in Real Time on a Serial Computer". Comm. of the ACM 21, 4 (April 1978), 280-294.
[Baker92] Baker, H.G. "CONS Should Not CONS Its Arguments, or, a Lazy alloc is a Smart alloc". ACM Sigplan Not. 27, 3 (Mar. 1992), 24-34.
[Bartlett89] Bartlett, J. Scheme->C: A portable Scheme-to-C compiler. Tech. Rept., DEC West. Res. Lab., 1989.
Berry, D.M. "Block Structure: Retention vs. Deletion". Proc. 3rd Sigact Symposium Theory of Computation, Shaker Hgts., 1971.
Cheney, C.J. "A nonrecursive list compacting algorithm". Comm. of the ACM 13, 11 (Nov. 1970), 677-678.
Clinger, W., Hartheimer, A., and Ost, E. "Implementation strategies for continuations". Proc. Lisp and Functional Programming, 1988, 124-131.
Danvy, O. "Memory Allocation and Higher-Order Functions". Proc. Sigplan '87 Symposium on Interpretation and Interpretive Techniques, ACM Sigplan Not. 22, 7 (July 1987), 241-252.
Fairbairn, J., and Wray, S.C. "TIM: a simple abstract machine to execute supercombinators". Proc. 1987 Functional Programming and Computer Architecture.
Fischer, M.J. "Lambda Calculus Schemata". ACM Conf. Proving Assertions about Programs, ACM Sigplan Not. 7, 1 (Jan. 1972).
Friedman, D.P., and Wise, D.S. "CONS Should Not Evaluate Its Arguments". In Michaelson, S., and Milner, R., eds. Automata, Languages and Programming. Edinburgh U. Press, 1976, 257-284.
Hanson, C. "Efficient stack allocation for tail-recursive languages". Proc. Lisp and Functional Programming, June 1990.
[Rees] IEEE. IEEE Standard for the Scheme Programming Language. IEEE-1178-1990, IEEE, NY, Dec. 1990.
Peyton Jones, S.L. The Implementation of Functional Programming Languages. Prentice-Hall, New York, 1987.
Stallman, R.M. "Phantom Stacks: If you look too hard, they aren't there". AI Memo 556, MIT AI Lab., Sept. 1974.
Stallman, R.M. Using and Porting GNU CC. Free Software Foundation, Inc. February, 1990.
Steiner, J., and Hawkes, B. "The M.T.A." On the album, The Kingston Trio At Large, released June 8, 1959, reached number 15 on June 15, 1959. Copyright Atlantic Music 1956-57.
[Tarditi92] Tarditi, D., and Lee, P. "No assembly required: Compiling standard ML to C". ACM Letters on Programming Languages and Systems 1, 2 (1992), 161-177.
[1] спасылка на 1959 песня Чарлі на MTA [Steiner56] запісаны Kingston Trio. Тэксты ўключаюць прыпеў:
Ах, ці будзе ён калі-небудзь вярнуцца?Чарлі не мог выйсці мітрапаліт Transit Authority (цяпер Масачусецкага заліва Transit Authority "MBTA") мятро (труба) цягнік, таму што яму бракавала грошай, каб аплаціць праезд. (Дарэчы, "Чарлі" таксама вайскоўцы назва літары "З".)
Не, ён ніколі не вярнуся,
і яго лёс дагэтуль вывучыўся.
Ён будзе ездзіць вечна,
"Ніт вуліцах Бостана,
Ён чалавек, які ніколі не вярнуся.
[2] Іншыя назвы батуце з'яўляюцца дыспетчара ці аператара, які павінен перадаваць вашы тэлефонныя званкі для вас.
[3] Максімальна партатыўных рэалізацыі могуць пазбягаць ALLOCA, бо яна не патрабуе ні ANSI C ці Unix.
[4] Джером Chailloux кажа мне, што IBM RS6000 і HP 9700 C кампілятары ствараюць павольней "заглушкі" для ўскосна-выкліканых функцый C - напрыклад, нашы замыканняў. Схема-на-C кампілятары, такім чынам, утвораць званкі на "вядомыя" функцыі па меры магчымасці.
[5] Максімальна партатыўных рэалізацыі могуць аддаюць перавагу Malloc да ALLOCA для аб'ектаў, памер якіх не вядомы падчас кампіляцыі.
[6] З, які робяць хвост рэкурсіі спробы - напрыклад, Gnu C - можа быць аштрафаваны, калі яны аднаўляюць задзірлівым захаванні рэгістраў!