Lecture #24: Achieving Runtime Effects—Functions
Total Page:16
File Type:pdf, Size:1020Kb
Lecture #24: Achieving Runtime Effects—Functions • Language design and runtime design interact. Semantics of func- tions make good example. • Levels of function features: 1. Plain: no recursion, no nesting, fixed-sized data with size known by compiler. 2. Add recursion. 3. Add variable-sized unboxed data. 4. Allow nesting of functions, up-level addressing. 5. Allow function values w/ properly nested accesses only. 6. Allow general closures. 7. Allow continuations. • Tension between these effects and structure of machines: – Machine languages typically only make it easy to access things at addresses like R + C, where R is an address in a register and C is a relatively small integer constant. – Therefore, fixed offsets good, data-dependent offsets bad. Last modified: Mon Mar 31 10:58:48 2008 CS164: Lecture #24 1 1: No recursion, no nesting, fixed-sized data • Total amount of data is bounded, and there is only one instantiation of a function at a time. • So all variables, return addresses, and return values can go in fixed locations. • No stack needed at all. • Characterized FORTRAN programs in the early days. • In fact, can dispense with call instructions altogether: expand func- tion calls in-line. E.g., def f (x): x *= 42 x_1 = 3 y=9+x; =⇒ =⇒ x_1 *= 42 g (x, y) becomes y_1 = 9 + x_1 g (x_1, y_1) f (3) • However, program may get bigger than you want. Typically, one in- lines only small, frequently executed functions. Last modified: Mon Mar 31 10:58:48 2008 CS164: Lecture #24 2 2: Add recursion Top of stack f’s • Now, total amount of data is un- locals fixed distance bounded, and several instantiations of ra Base of a function can be active simultaneously. arguments 1st frame • Calls for some kind of expandable data to f structure: a stack. g’s • However, variable sizes still fixed, so locals size of each activation record (stack ra frame) is fixed. arguments to g • All local-variable addresses and the value of dynamic link are known offsets f’s from stack pointer, which is typically in locals a register. ra . Last modified: Mon Mar 31 10:58:48 2008 CS164: Lecture #24 3 Calling Sequence when Frame Size is Fixed Top of stack f’s • So dynamic links not really needed. locals fixed distance ra Base of • Suppose f calls g calls f, as at right. arguments 1st frame • When called, the initial code of g (its to f prologue) decrements the stack pointer g’s by the size of g’s activation record. locals • g’s exit code (its epilogue): ra arguments – increments the stack pointer by this to g same size, f’s – pops off the return address, and locals – branches to address just popped. ra . Last modified: Mon Mar 31 10:58:48 2008 CS164: Lecture #24 4 3: Add Variable-Sized Unboxed Data • “Unboxed” means “not on heap.” • Boxing allows all quantities on stack to Top of stack have fixed size. unboxed storage • So Java implementations have fixed- other size stack frames. locals • But does cost heap allocation, so local some languages also provide for placing pointer variable-sized data directly on stack DL (“heap allocation on the stack”) ra Frame pointer arguments • alloca in C, e.g. to g • Now we do need dynamic link (DL). f’s • But can still insure fixed offsets of locals data from frame base (frame pointer) DL ra using pointers. • To right, f calls g, which has variable- sized unboaxed array (see right). Last modified: Mon Mar 31 10:58:48 2008 CS164: Lecture #24 5 Other Uses of the Dynamic Link • Often use dynamic link even when size of AR is fixed. • Allows use of same strategy for all ARs, simplifies code generation. • Makes it easier to write general functions that unwind the stack (i.e., pop ARs off, thus returning). Last modified: Mon Mar 31 10:58:48 2008 CS164: Lecture #24 6 4: Allow Nesting of Functions, Up-Level Addressing • When functions can be nested, there are three classes of variable: Top of stack a. Local to function. g’s b. Local to enclosing function. frame c. Global . • Accessing (a) or (c) is easy. It’s (b) g’s How far??? that’s interesting. frame • Consider (in Pyth or Python): def f (): g’s y = 42 # Local to f frame def g (n, q): Enclosing f if n == 0: return q+y f’s else: return g (n-1, q*2) frame • Here, y can be any distance away from top of stack. Last modified: Mon Mar 31 10:58:48 2008 CS164: Lecture #24 7 Static Links • To overcome this problem, go back to environment diagrams! Top of stack • Each diagram had a pointer to g’s frame SL lexically enclosing environment DL • In Pyth example from last slide, ra g’s frame each ‘g’ frame contains a pointer SL to the ‘f’ frame where that ‘g’ DL was defined: the static link (SL) ra g’s frame • To access local variable, use SL frame-base pointer (or maybe DL ra stack pointer). f’s frame • SL To access global, use absolute DL address. ra • To access local of nesting func- . tion, follow static link once per difference in levels of nesting. Last modified: Mon Mar 31 10:58:48 2008 CS164: Lecture #24 8 The Global Display • Historically, first solution to nested function problem used an array indexed by call level, rather than static links. def f0 (): q = 42; g1 () def f1 (): def f2 (): ... g2 () ... def g2 (): ... g2 () ... g1 () ... def g1 (): ... f1 () ... g1 1 • Each time we enter a function at lexical level k f0 0 (i.e., nested inside k functions), save pointer to its frame base in DISPLAY[k]; restore on exit. • Access variable at lexical level k through g1’s DISPLAY[k]. frame • Relies heavily on scope rules and proper f0’s DISPLAY function-call nesting frame Last modified: Mon Mar 31 10:58:48 2008 CS164: Lecture #24 9 The Global Display • Historically, first solution to nested function problem used an array indexed by call level, rather than static links. def f0 (): q = 42; g1 () def f1 (): def f2 (): ... g2 () ... def g2 (): ... g2 () ... g1 () ... def g1 (): ... f1 () ... f1 1 • Each time we enter a function at lexical level k f0 0 (i.e., nested inside k functions), save pointer to f1’s its frame base in DISPLAY[k]; restore on exit. frame • Access variable at lexical level k through g1’s DISPLAY[k]. frame • Relies heavily on scope rules and proper f0’s DISPLAY function-call nesting frame Last modified: Mon Mar 31 10:58:48 2008 CS164: Lecture #24 9 The Global Display • Historically, first solution to nested function problem used an array indexed by call level, rather than static links. def f0 (): q = 42; g1 () def f1 (): def f2 (): ... g2 () ... def g2 (): ... g2 () ... g1 () ... def g1 (): ... f1 () ... f1’s f1 1 • Each time we enter a function at lexical level k frame f0 0 (i.e., nested inside k functions), save pointer to f1’s its frame base in DISPLAY[k]; restore on exit. frame • Access variable at lexical level k through g1’s DISPLAY[k]. frame • Relies heavily on scope rules and proper f0’s DISPLAY function-call nesting frame Last modified: Mon Mar 31 10:58:48 2008 CS164: Lecture #24 9 The Global Display • Historically, first solution to nested function problem used an array indexed by call level, rather than static links. def f0 (): q = 42; g1 () def f1 (): def f2 (): ... g2 () ... f2’s def g2 (): ... g2 () ... g1 () ... frame def g1 (): ... f1 () ... f2 2 f1’s f1 1 • Each time we enter a function at lexical level k frame f0 0 (i.e., nested inside k functions), save pointer to f1’s its frame base in DISPLAY[k]; restore on exit. frame • Access variable at lexical level k through g1’s DISPLAY[k]. frame • Relies heavily on scope rules and proper f0’s DISPLAY function-call nesting frame Last modified: Mon Mar 31 10:58:48 2008 CS164: Lecture #24 9 The Global Display • Historically, first solution to nested function problem used an array indexed by call level, rather than static links. def f0 (): q = 42; g1 () g2’s def f1 (): frame def f2 (): ... g2 () ... f2’s def g2 (): ... g2 () ... g1 () ... frame def g1 (): ... f1 () ... g2 2 f1’s f1 1 • Each time we enter a function at lexical level k frame f0 0 (i.e., nested inside k functions), save pointer to f1’s its frame base in DISPLAY[k]; restore on exit. frame • Access variable at lexical level k through g1’s DISPLAY[k]. frame • Relies heavily on scope rules and proper f0’s DISPLAY function-call nesting frame Last modified: Mon Mar 31 10:58:48 2008 CS164: Lecture #24 9 The Global Display • Historically, first solution to nested function problem used an array indexed by call level, rather than static links. g2’s frame def f0 (): q = 42; g1 () g2’s def f1 (): frame def f2 (): ... g2 () ... f2’s def g2 (): ... g2 () ... g1 () ... frame def g1 (): ... f1 () ... g2 2 f1’s f1 1 • Each time we enter a function at lexical level k frame f0 0 (i.e., nested inside k functions), save pointer to f1’s its frame base in DISPLAY[k]; restore on exit. frame • Access variable at lexical level k through g1’s DISPLAY[k]. frame • Relies heavily on scope rules and proper f0’s DISPLAY function-call nesting frame Last modified: Mon Mar 31 10:58:48 2008 CS164: Lecture #24 9 The Global Display • Historically, first solution to nested function g1’s problem used an array indexed by call level, frame rather than static links.