Path: csiph.com!usenet.pasdenom.info!weretis.net!feeder4.news.weretis.net!nuzba.szn.dk!pnx.dk!fu-berlin.de!uni-berlin.de!individual.net!not-for-mail From: "Pascal J. Bourguignon" Newsgroups: comp.lang.java.programmer,comp.programming Subject: Re: Creating a new stack from an exisiting one. Date: Sun, 04 Nov 2012 13:14:45 +0100 Organization: Informatimago Lines: 206 Message-ID: <87vcdllg3u.fsf@informatimago.com> References: <0.73472d82415d5353822e.20121103155132GMT.87mwyyvg57.fsf@bsb.me.uk> <0.898697c4e5f8819c7fa0.20121104004445GMT.878vaiurgi.fsf@bsb.me.uk> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii X-Trace: individual.net J6i8LZGZelDzXTbkmwnyugEGhvDr5dHZA9/OPSniwnarUcrtKxkySloJe8GJlcdwWX Cancel-Lock: sha1:MzE0MmZjNTJlMDIwMGJmNzIzYjEwYjUyYjM0ZDExN2E4YzM0NzhiOQ== sha1:Yl8zAzhiE4a4lsJtoreHkbjZT6Q= Face: iVBORw0KGgoAAAANSUhEUgAAADAAAAAwAQMAAABtzGvEAAAABlBMVEUAAAD///+l2Z/dAAAA oElEQVR4nK3OsRHCMAwF0O8YQufUNIQRGIAja9CxSA55AxZgFO4coMgYrEDDQZWPIlNAjwq9 033pbOBPtbXuB6PKNBn5gZkhGa86Z4x2wE67O+06WxGD/HCOGR0deY3f9Ijwwt7rNGNf6Oac l/GuZTF1wFGKiYYHKSFAkjIo1b6sCYS1sVmFhhhahKQssRjRT90ITWUk6vvK3RsPGs+M1RuR mV+hO/VvFAAAAABJRU5ErkJggg== X-Accept-Language: fr, es, en User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/23.4 (darwin) Xref: csiph.com comp.lang.java.programmer:19616 comp.programming:2458 Ben Bacarisse writes: > I think you are probably confusing yourself by writing []s and calling > the contents a stack. I am still not sure what you want, but the new > words "runStack" and "framePointers" and the function call example put > this in a context I understand. > > Why do think a new stack is needed? The conventional thing to do is to > push the function's arguments and the record the new top of stack in the > frame pointer. Since the previous frame pointer will need to be > restored when this function exits, it is reasonable to record these > frame pointers in a stack, though some implementations will use the main > stack for these as well (often just relying on the register save/restore > mechanism). Anyway, that aside, the effect is that the 3 won't be on a > new stack, just in a portion of the main stack identified by the frame > pointer for this function call. > > If function G calls function F we get a stack that looks like this at > the point that F starts to run: > > ][args for G | G's locals][args for F | > > Now the []s don't denote stacks. Each bracketed part is a stack > frame -- a region on the main stack. The |s mark the frame pointers. > Function arguments are to the left, and locals are to the right. > > To be very explicit, let's assume that your stack uses plain integer > indexes and the functions look like this > > function G(a) { c = 42; F(c, a) } > function F(a, b) { ... don't care about what's in F } > > and G is called like this, G(99). If 66 stack cells have already been > used, we get the following situation: > > index ... 67 68 69 70 71 > content ... 99 42 99 42 > corresponding to ... G:a G:C F:b F:a > > frame pointer stack: ... 68 71 > > Top of stack: 71. > > The two numbers in the frame pointer stack mark the |s in the previous > schematic. The code is now ready to allocate the first local variables > in F (if any). > > All this excludes any mention of the return address. Maybe that's being > handled separately. Well, I don't know of any processor that uses a separate stack for the frame pointers. See for example the instructions LINK and UNLK of the 680x0 (there are similar instructions on X86 and others). The top frame pointer is usually kept in A6, while the stack pointer is A7=SP. At the entry point of functions, there's an instruction: LINK A6,#-localSpace and at the exit of them, there are: UNLK A6 RTN So for functions like: > function G(a) { c = 42; F(c, a) } > function F(a, b) { ... don't care about what's in F } and starting with A7=SP=0xfff0 (stacks tend to grow downward in processors, but it makes no differences, only the offsets are opposites): A7: 0xfff0 A6: 0xfff8 the caller pushes 99 for the argument of G, then calls G, with a JSR G, which pushes the return address onto the stack: 0xfff0: 0xffec: 99 0xffe8: return-address-to-caller A7: 0xffe8 A6: 0xfff8 then G executes LINK A6,#-4 since it needs one local variable. 0xfff0: 0xffec: 99 0xffe8: return-address-to-caller 0xffe4: 0xfff8 ; old fram pointer 0xffe0: random value for c A7: 0xffe0 A6: 0xffe4 ; G frame pointer c:=42 This writes into the local frame at the address -4(A6): 0xfff0: 0xffec: 99 0xffe8: return-address-to-caller 0xffe4: 0xfff8 ; old fram pointer 0xffe0: 42 ; c A7: 0xffe0 A6: 0xffe4 ; G frame pointer F(c,a) this reads the local frame: c is in the local variables at -4(A6), and a is in the parameters at 8(A6). The arguments are pushed on the stack: 0xfff0: 0xffec: 99 0xffe8: return-address-to-caller 0xffe4: 0xfff8 ; old fram pointer 0xffe0: 42 ; c 0xffdc: 42 0xffd8: 99 A7: 0xffd8 A6: 0xffe4 ; G frame pointer then F is called. 0xfff0: 0xffec: 99 0xffe8: return-address-to-caller 0xffe4: 0xfff8 ; old fram pointer 0xffe0: 42 ; c 0xffdc: 42 0xffd8: 99 0xffd4: return address into G A7: 0xffd4 A6: 0xffe4 ; G frame pointer So F executes LINK A6,#-n (n depending on the local storage F needs): And so on. When F returns, it calls: UNLK A6 which restores the stack to:\ 0xfff0: 0xffec: 99 0xffe8: return-address-to-caller 0xffe4: 0xfff8 ; old fram pointer 0xffe0: 42 ; c 0xffdc: 42 0xffd8: 99 0xffd4: return address into G A7: 0xffd4 A6: 0xffe4 ; G frame pointer and: RTN which returns to G 0xfff0: 0xffec: 99 0xffe8: return-address-to-caller 0xffe4: 0xfff8 ; old fram pointer 0xffe0: 42 ; c 0xffdc: 42 0xffd8: 99 A7: 0xffd8 A6: 0xffe4 ; G frame pointer When G returns, it executes: UNLK A6 which restores the stack to: 0xfff0: 0xffec: 99 0xffe8: return-address-to-caller A7: 0xffe8 A6: 0xfff8 and then: RTN and we're back to the caller: 0xfff0: 0xffec: 99 A7: 0xffec A6: 0xfff8 -- __Pascal Bourguignon__ http://www.informatimago.com