home *** CD-ROM | disk | FTP | other *** search
- Path: sparky!uunet!zaphod.mps.ohio-state.edu!cs.utexas.edu!sun-barr!news2me.EBay.Sun.COM!exodus.Eng.Sun.COM!rbbb.Eng.Sun.COM!chased
- From: chased@rbbb.Eng.Sun.COM (David Chase)
- Newsgroups: comp.std.c++
- Subject: C++ nested functions and C interoperability
- Date: 16 Dec 1992 23:35:27 GMT
- Organization: Sun
- Lines: 76
- Message-ID: <livf9vINN88l@exodus.Eng.Sun.COM>
- References: <24392@alice.att.com> <1992Dec12.162211.5076@ucc.su.OZ.AU> <24400@alice.att.com>
- NNTP-Posting-Host: rbbb
- Summary: It is elementary. Next objection, please.
-
-
- >In article maxtal@extro.ucc.su.OZ.AU (John MAX Skaller) writes:
-
- >> Do you personally favour nested functions?
- >> If not, why not?
-
- In article <24400@alice.att.com> ark@alice.UUCP () writes:
- >In general, yes. For C++, I'm not sure.
-
- >The main argument against it is that C doesn't have them, which means
- >that having them in C++ would make C interoperability more difficult.
- >It would also be more difficult to interface C++ programs with
- >low-level assembly-language things like on-board controllers. I don't
- >care about that personally, but I know that other people do.
-
- C interoperability is elementary, and already done before. This
- should also be transparent to other assembly languages like those used
- in on-board controllers. (Besides which, people in those situations
- have been known to live with restrictions before.)
-
- Implementation method #1: generate code into your stack frame to load
- up the lexical pointer and branch to where the "real" function is.
- For a 68k, this means pushing an additional parameter. For a SPARC,
- this means (for example) loading a value into %g2. The assembly
- language for this looks something like:
-
- sethi func>>10,%g1
- sethi addr>>10,%g2
- jmp %g1+func&0x3ff
- add %g2,addr&0x3ff,%g2
-
- Of course, when you generate this, you had better do the appropriate
- cache flushes. "func" is entered with %g2 containing a pointer to
- whatever representation of the parent frame you find most suitable.
- (I got this trick from Thomas Breuel [sp?], and used it in an early
- Modula-3 implementation on the 68k. It worked just fine -- Modula-3
- functions looked just like C functions.)
-
- Implementation method #2: generate about 512 pieces of code of the
- form (SPARC-specific, for concreteness)
-
- sethi abslocX>>10,%g2
- ld [%g2+abslocX&0x3ff],%g1
- jmp %g1
- add %g2,abslocX&0x3ff,%g2
-
- and about 512 8-byte chunks of data.
-
- (In this case, "func" is entered with a ptr to a thunk_data, and
- not a direct ptr to the parent frame.)
-
- where you have
-
- struct thunk_code {unsigned int sethi, ld, jmp, add; };
- struct thunk_data {unsigned int function, parent_frame; };
- struct thunk_code_page { struct thunk_code code [512]; };
- struct thunk_data_page { struct thunk_data data [512]; };
-
- Given a code page, code[i] has abslocX equal to data+i in a
- corresponding data page. The code page is initialized once, flushed,
- mmap'd no-write, and nested functions are created by allocating them
- out of this pool and filling in the appropriate entries in the data
- page. If you run out, create a new pair of pages. Note that
- deallocating a thunk is now necessary (much like running destructors)
- but because exceptions in C++ are synchronous and interaction with
- longjmp is undefined, everything will work (ho, ho, ho). At worst,
- longjmp creates a storage leak that can probably be dealt with by
- putting a little bit more information into a thunk_data.
-
- So, given that we can implement nested functions and maintain
- compatibility with C, why not?
-
- David Chase
- Sun
-
-
-