Path: csiph.com!weretis.net!feeder6.news.weretis.net!feeder.usenetexpress.com!feeder-in1.iad1.usenetexpress.com!border1.nntp.dca1.giganews.com!nntp.giganews.com!news.misty.com!news.iecc.com!.POSTED.news.iecc.com!nerds-end From: rpw3@rpw3.org (Rob Warnock) Newsgroups: comp.compilers Subject: Re: Add nested-function support in a language the based on a stack-machine Date: Sat, 3 Mar 2018 16:00:25 -0000 (UTC) Organization: Rob Warnock, Consulting Systems Architect Lines: 49 Sender: news@iecc.com Approved: comp.compilers@iecc.com Message-ID: <18-03-013@comp.compilers> References: <18-02-009@comp.compilers> <18-02-034@comp.compilers> <18-03-002@comp.compilers> <18-03-006@comp.compilers> Injection-Info: gal.iecc.com; posting-host="news.iecc.com:2001:470:1f07:1126:0:676f:7373:6970"; logging-data="94344"; mail-complaints-to="abuse@iecc.com" Keywords: code, design Posted-Date: 03 Mar 2018 13:17:35 EST X-submission-address: compilers@iecc.com X-moderator-address: compilers-request@iecc.com X-FAQ-and-archives: http://compilers.iecc.com Originator: rpw3@rpw3.org (Rob Warnock) Xref: csiph.com comp.compilers:1972 Kaz Kylheku <217-679-0842@kylheku.com> wrote: +--------------- | George Neuner wrote: | > It certainly is true that closeure conversion is a better solution | > overall because it flattens all non-local accesses to use a single | > indirection ... but it also significantly complicates the compiler, | > and creates a need for handling wide pointers (or equivalent). Many | > useful languages simply don't need that extra complexity. | | How do flat representations handle the fact that different levels | of the lexical environment have different lifetimes? +--------------- I'm not sure if this counts as "closure conversion" or not, but some Common Lisp implementations [such as CMUCL] use flat environments just fine (even in the interpreter). The trick is to do some minimal pre-analysis of the code, to see which closed-over variables are *not* ever mutated or are *not* used in closures which "escape" the original lexical context. All such variables may be copied into a single "flat" vector at closure creation time. All other closed-over variables are converted into "indirect" variables -- such variables are individually heap-allocated, pointed to by "ref" pointers which are also copied into a the same flat environment vector at closure creation time. Then when the closure is called, all of the up-level variables are either *in* the (flat) environment or available via *one* indirection. Because all of the "ref" pointers for a given environment variable in all the (potential) copies point to the same heap location, closures which mutate a shared variable work just fine. And all the rest are either read-only [and thus all the copies are the same] or else mutated and *not* accessed in any interior closure which escapes. This is normally performs better than linked environments or even displays, unless there are a *large* number of nested closures. In the latter case, when each level of closure is created, it will have to copy all of its free variables from its parent's flat environment into its own. [I apologize if I haven't explained this very well.] This approach is not unique to Lisp. Appel discusses it for ML in his "Compiling With Continuations". -Rob ----- Rob Warnock 627 26th Avenue San Mateo, CA 94403