330 likes | 447 Vues
Subroutines. Programming Language Principles Lecture 24. Prepared by Manuel E. Bermúdez, Ph.D. Associate Professor University of Florida. Abstraction. A process by which a programmer associates a name with a potentially complicated program fragment.
E N D
Subroutines Programming Language Principles Lecture 24 Prepared by Manuel E. Bermúdez, Ph.D. Associate Professor University of Florida
Abstraction A process by which a programmer associates a name with a potentially complicated program fragment. • Goal: Think in terms of purpose vs. implementation. • Two forms of abstraction: • Control Abstraction: Represent an action. • Data abstraction: represent data (more later).
Control Abstraction • Main control abstraction mechanism: the subroutine. • Subroutines perform operations on behalf of the caller. • Can accept parameters. Parameters influence the subroutine's behavior. Give the subroutine data on which to operate.
Terminology • Argument: actual parameter. • Parameters: formal parameter. • Subroutine that returns a value: a function. • Subroutine that doesn't return a value: a procedure. • Procedures are only executed for their side effects.
Subroutine Stack Layout • Storage consumed by parameters can be allocated on a stack. • Each routine that is called gets a stack frame/activation record on top of the stack. A frame contains: • Arguments, that are passed into the subroutine. • Bookkeeping info (such as return address of caller, saved registers). • Local variables / temporaries.
Frame Management • Keeping the stack frame intact is the responsibility of the calling sequence code executed by the caller immediately before and after a subroutine call. • Prologue : Code executed at beginning (pass parameters, save return address, change program counter, change SP, save registers) • Epilogue : Code executed at the end (restore SP, restore registers, etc.) • Calling sequence varies from processor to processor, and compiler to compiler.
Frame Management • When a subroutine is finished it pops its frame from the stack (and leaves its return value if there is one on top of the stack) • Stack pointer (SP): Register contains the address of the first unused location at the top of the stack. • Frame pointer (FP): Contains an address within the frame. Objects within the stack are referenced via displacement addressing with respect to the FP.
Static Links (revisited) • In a language with nested subroutines and static scoping (Pascal, Ada, Modula) objects that lie in surrounding subroutines (neither local, nor global) can be found by maintaining a static chain. • Static Link (SL): Reference to (most recent instance of) the frame of the lexically surrounding subroutine. Needed to look up non-local variables (in surrounding scope).
Maintenance of static chains • Standard approach: • caller computes callee's SL and passes it as an extra hidden parameter. • Two cases:
Static Links (revisited) • The callee is nested (directly) inside the caller. The callee's static link should refer to the caller's frame. The caller passes its own FP as the callee's SL. Example: A calls E, or B calls D.
Maintenance of static chains (cont’d) • The callee is k > 0 scopes outward -- closer to the outer level of lexical nesting. All scopes that surround the callee also surround the caller. The caller dereferences its own SL k times and passes the result as the callee's SL. Example: E calls B, D calls C, or C calls B.
Static Link Disadvantage • An object in a scope k levels out requires dereferencing the chain k times. • We can fix this by using a display. • A display embeds a static chain into an array. • The j-th element of the display contains a reference to the frame of the most recently active routine at nesting level j.
Maintenance of Displays • When calling subroutine at level j, the callee saves the current value of the jth display into the stack and replaces it with a copy of its own FP. • Two cases:
Maintenance of Displays (Case 1) The callee is nested (directly) inside the caller. Caller and callee share all display elems up to the current level. Put callee's FP into the display. Example: A calls E, B calls D.
Maintenance of Displays (Case 2) The callee is at nesting level j, k > 0 scopes outward from the caller. Caller and callee share display up to j-1. The caller's entry at j is different, so callee must save it before storing its own FP. Example: E calls B, D calls E.
Handling Closures • If callee is called through closure, the display scheme breaks. • Solved by storing the entire display in the callee’s frame. • Expensive, and not always necessary to store the entire display. • Good argument for using static links. In general maintaining display is more expensive than SL.
Efficiency (Static link vs. Display) • Display in memory: a non-local object can be loaded in memory with two memory access operations. One for display, one for object loading. • Static links: non-local loading requires k dereferencing operations. • Most programs don't nest subroutines more than 2/3 levels deep. So static chain is short.
Efficiency (Static link vs. Display) • Maintaining display is more expensive then maintaining static chain. • Static chains allow closures (subroutines passed as parameters). • Display (typically) uses fixed size array. Imposes a maximum depth of nested subroutines.
Case study 1 • C (gcc v. 2.7.2) on MIPS architecture (RISC) • For description of MIPS architecture, see Section 5.5.1 of the textbook. • Arguments are accessed via offset from fp. • First four scalar arguments are passed through registers (r4-r7, or f12-f15)
gcc on MIPS Architecture (cont’d) The caller: • Saves any caller-saved registers that are still needed. • Puts up to four scalar arguments into the registers. • Puts remaining arguments at top of current frame. • Performs a JAL (jump) which puts the return address in register ra and jumps to the target.
gcc on MIPS Architecture (cont’d) In the prologue the callee: • Subtracts the frame size from the sp. • Saves any necessary registers into the beginning of the new frame, using sp as base for displacement mode addressing. • copies sp into fp.
gcc on MIPS Architecture (cont’d) In the epilogue the callee: • Places return value (if any) into r2, f0 or memory. • Copies the fp into the sp, to deallocate any allocated space. • Restores saved registers including the ra, if needed, using sp as base for displacement mode addressing. • Adds the frame size to the sp, to deallocate the frame. • Performs a jra instruction (jump back)
Case Study 2 • Pascal (CodeWarrior v.9) on the Motorola 680x0. (old Mac, Amiga, Atari ST) • CISC architecture. • All arguments passed on the stack, not in registers. • Arguments are pushed and popped (using auto increment and auto decrement instruction modes), updating the sp dynamically, rather than assembling them in a pre-allocated area. • fp gets a dedicated register, by convention, a6.
Pascal on M680x0 (cont’d) • The Caller: • allocates space for a small return value, or pushes the address of a large one. Skip if this is a procedure. • pushes arguments (or their addresses) left-to-right. Skip if there are no parameters.
Pascal on M680x0 (cont’d) The Callee, in the prologue: • executes a link instruction: decrement sp enough to accommodate all locals, temps, and large arguments copied from caller. • pushes any registers that need to be saved (fp, in a6). • copies any large arguments needed.
Pascal on M680x0 (cont’d) The Callee, in the epilogue: • sets the return value (bottom of frame) • pops saved registers. • executes an unlkinstruction, to restore the sp • pops arguments and SL. • returns.
Pascal on M680x0 (cont’d) • Since Pascal allows subroutines to be nested, passing a subroutine as a parameter requires a closure. Eight-byte long closure: • First four are static link of closure (environment link in RPAL). • Last four bytes are address of subroutine's code. • Passed by address (due to its length), though it's never changed.
In-line expansion • Compiler can choose to compile routine inline. • Inline expansion increases code size, but is significantly faster. C++: inline int max (int a, int b) { return a > b ? a : b; }
In-line expansion (cont’d) Ada: function max (a, b :integer) return integer is begin if a > b then return a; else return b; end if; end max; pragma inline (max); In both languages, the compiler directive is a suggestion that can be ignored.
Subroutines Programming Language Principles Lecture 24 Prepared by Manuel E. Bermúdez, Ph.D. Associate Professor University of Florida