CS 342 Lecture -*- Outline -*- * Addressing variables (don't have to worry about addressing procs because they are constants) ** variables located by 2 coordinates (snl, offset) *** static nesting level (gives AR) static nesting level: number of enclosing scopes *** offset within AR offset: number of words into local data area of AR where variable is ------------ program sort; var a: array[0..10] of integer; x: integer; procedure readarray; var i: integer; begin end; procedure exchange(i,j: integer); begin x:=a[i]; a[i]:=a[j]; a[j]:=x end; procedure quicksort(m,n: integer); var k,v: integer; function partition(y,z: integer): integer; var i,j: integer; begin ...a...v...; ...exchange(i,j);... end; begin ... end; begin readarray; quicksort(0,10) end. ------------ *work static nesting levels for some names (including procs) sort = 0, x = 1, quicksort = 1, k = 2 ** Two fundamental methods for finding AR from static nesting level *** Static chain each AR has pointer (static link, SL) to AR of *most recent* activation of lexically enclosing block, these make a chain of enclosing ARs follow this chain to find variables |\\\\\\\\\\\\\\\\\\\\\\\\ | ... | <------ EP |------------------------| partition | static link *---------| |------------------------| | | ... | | |========================| | | ... | <----- |------------------------| quicksort | static link *-------->| |------------------------| | | ... | | |========================| | | ... | | |------------------------| | quicksort | static link *---------| |------------------------| | | ... | | |========================| V | ... | | |------------------------| | sort | static link 0 | <----- |------------------------| | ... | |========================| *work some examples (particular variables) *** Display stack of pointers to ARs of *most recent* activation of lexically enclosing activations ----------------------- | AR for partition | |-------------| |---------->| | 3 | *---------- |-----------------------| |-------------| | AR for quicksort| 2 | *-------------------->| | |-------------| |-----------------------| 1 | *--------- | AR for quicksort| |-------------| | | | | |-----------------------| ------------>| AR for sort | ----------------------- *work some examples ** Static Chaining *** Accessing variable V 1. at run-time, follow static chain for SD links, where SD is static distance from using stmt. to decl. of variable V (computed at compile time) -result is a pointer to most active AR containing V 2. add offset of V in the AR (computed at compile time) -result is pointer to V Cases: -local's address = EP + offset(V) -V at static distance SD AP := EP; AP := M[AP].SL; ... {SD of these} AP := M[AP].SL; M[AP + offset(V)] := value Cost to access variable at nesting level SD: SD+1 memory references AP := M[AP].SL; M[callee].SL := AP can combine some steps: e.g., if SD = 1, callee's SL := M[EP].SL quicksort calling itself Maintainence Procedure call: have to set SL correctly in callee's AR Procedure return: nothing special (SL already in caller's AR) non-local goto: like return if pops off stack info: static nesting level for each procedure (in symbol table) => can compute static distance (SD) between call site's SNL and proc declaration. *use static distance to set callee's SL correctly if SD = 0 (call to nested proc), then callee's SL := EP e.g., body of sort calls quicksort or quicksort calls partition if SD > 0, then follow static chain SD links to set callee's SL general AP := EP; AP := M[AP].SL; ... {SD of these} AP := M[AP].SL; M[callee].SL := AP can combine some steps: e.g., if SD = 1, callee's SL := M[EP].SL quicksort calling itself maintenance cost: on call, SD memory references on return, 0 ** Displays *** Accessing a variable V at (SNL(V),offset(V)) address = display[SNL(V)] + offset(V) cost to access is 2 memory references (display, variable itself) -reduced to 1 if display in registers -constant *** Maintainence Procedure call: have to save caller's display, set callee's display correctly Procedure return: have to restore caller's display alternatives: 1. could have separate stack of displays, but expensive (cost of call proportional to SNL) 2. could save whole display each time on run-time stack, but expensive (cost of call proportional to SNL) 3. save only one element each time on run-time stack, complex but cheaper (see below) allocate field (called EP) in AR for saved display element replaces SL in AR *use static nesting level of callee, SNL(callee) Procedure call 1. save display[SNL(callee)+1] in caller's AR.EP AP := display[SNL(caller)+1] M[AP].EP := display[SNL(callee)+1] 2. install new AR in display display[SNL(callee)+1] := callee's AR (=SP) Procedure return 1. restore caller's display AP := M[display[SNL(callee)+1]].DL; {address} display[SNL(callee)+1] := M[AP].EP; *draw pictures of calls: quicksort to quicksort partition to exchange -shows that display has to be saved cost: on call, 3 memory references on return, 3 memory references ** Costs comparision (in mem. references): Operation static chain display local var access 1 2 var at static diff sd sd+1 2 procedure call sd+3 6 procedure return 2 5 which has faster variable access? which has faster procedure calls? Problem: which to pick? (slow variable accesses or proc calls?) What to do? -maintain display in hardware (Burroughs machine) -use static chaining, create a display on demand for each activation -redesign language (exercise) For example: C does not have nesting, so only static difference of 1.