1 / 17

Implementing Subprograms

Understand the actions required when calling and terminating subprograms. Learn how subprogram linkage is performed via activation records and the runtime stack in languages like FORTRAN and ALGOL. Explore parameter passing methods and memory management techniques.

atravers
Download Presentation

Implementing Subprograms

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Implementing Subprograms • What actions must take place when subprograms are called and when they terminate? • calling a subprogram has several associated actions: • calling subprogram’s environment must be saved • subprogram’s local variables, execution status return location • handle parameter passing to called subprogram • allocation and storage of local variables • transfer control to subprogram • subprogram termination then has the following actions: • return parameters that are out-mode • deallocation of local variables • return value from subprogram (if it is a function) • restore calling subprogram’s environment • transfer control to calling subprogram at the proper place • Generically, this is known as subprogram linkage and in most languages, this is performed through the run-time stack by using activation record instances

  2. FORTRAN I-77 • We first examine FORTRAN first since it is simplest • early FORTRAN had no recursion, all memory allocation was set up at compile time • so all variable and parameter names had specific memory locations known at compile time • subprogram call • save execution status of current program unit • carry out parameter passing • pass by copy required copying parameters • pass by reference required substituting an address for the value • pass return address to called subprogram • start execution of the subprogram • subprogram return • if pass-by-result parameters, copy current values to corresponding actual parameters and if subprogram is a function, value is moved to a place accessible by the caller • execution status of caller is restored • control is transferred back to caller

  3. In order to simplify the tasks of saving an environment and passing parameters compiler generates ARs for each subprogram The AR for FORTRAN will store: status of caller which include local variables parameters return address functional value (for functions) The compiler sets this up providing storage space for each subprogram’s AR parameter passing is now merely a matter of copying values from one area of memory to another transferring control is merely a matter of changing the PC based on subprogram start addresses or calling subprogram return addresses memory access is efficient because all addresses are known at compile time Activation Records (AR)

  4. ALGOL-like Activation Records • ALGOL used the run-time stack to permit recursion • the single activation record approach of FORTRAN does not permit multiple copies of local variables and parameters needed for recursion, and with only one copy, newer values would replace older values • the run-time stack, used in FORTRAN only to denote where to return to after subprograms terminate, will now also be used to store local variables and parameters • The ALGOL approach was to have the compiler generate an AR for every subprogram • the AR is a template • upon subprogram call, an instance of the template is generated and pushed onto the run-time stack, an instance is called an activation record instance (ARI) and contains: • local variables • parameters • return location • return value (if a function) • links to connect to rest of run-time stack

  5. Local variables Parameters Dynamic Link Static Link Return Address ALGOL ARI • Static Link • points to bottom of ARI for static parent • used for non-local variable access • Dynamic Link • points to top of ARI of caller used to destroy current ARI end of subprogram • Parameters • Store space for every parameter (whether a value or a pointer) • Local variables store space for each local variable • stack-dynamic storage allocated at run-time but compile-time type checked • recursion available by creating an instance for each recursion call NOTE: In C-languages, the static link will point to main’s data since there are no other static parents

  6. Example of ARI for C function void sub(float total, int part) { int list[4]; float sum; … } Need space for 2 parameters (a float and an int) 2 variables, a 4-element int array and a float Return address (where in the code to return to when sub terminates) Dynamic link points to next ARI on stack so that this ARI can be popped off Static link points to static parent (main) for non-local variable references Since this is a void function, no space needed for return value

  7. Example Without Recursion void A(int x) { int y; ... C(y); ... } void B(float r) { int s, t; ... A(s); ... } void C(int q) { ... } void main() { float p; ... B(p); ... } Stack after: main calls B B calls A A calls C

  8. Example With Recursion (part I) int factorial(int n) { if(n<=1) return 1; else return n*factorial(n-1); } void main( ) { int value; value = factorial(3); } Point 1 Point 2 Point 3 Stack contents at point 1 during each recursive call

  9. Example With Recursion (part II) Stack contents at point 2 as each recursive call completes Stack contents at point 3

  10. Non Local Variable References • Assume in some subprogram, a reference is made to a non-local variable • how do we determine what is being referenced? • non-local variables will be stored somewhere either in static memory (if the variable is global or declared static) or on the run-time stack • if on the run-time stack, which ARI do we check? • a top-down search through the ARIs would be inefficient, instead, the compiler can determine where the variable is stored using scope rules, and set up a pointer directly • recall in C/C++/Java, subprograms are not nested, so the only static parent a C function can have is main • but in non-C languages (notably Ada/Pascal-like languages), subprograms can be nested, the nestedness of the subprograms provides the information needed to find the non-local variable • Two methods: Static Chains, Displays

  11. Static Chains • The compiler can determine for any given subprogram, which subprogram is it’s static parent • the static link in the ARI points to this static parent • Further, the compiler can determine how many static links must be taken to track down a given reference • for instance, assume • Main contains SubA – so SubA has a static link to Main • SubA contains SubB – so SubB has a static link to SubA • SubB has a static parent of subA which has a static parent of Main • now assume that Main has declared a variable x and neither SubA nor SubB has declared a variable x • if SubB references x, then x is found by following 2 links to reach Main on the run-time stack • A static chain is the information needed to resolve the reference and consists of: • chain offset – the distance in terms of number of static links • this is equivalent to the nestedness between the reference and where it is declared using static scope rules • local offset – the position in the ARI of the variable (starting from the bottom of this ARI)

  12. The stack at position 1 Ada Example program Main_2; var X : integer; procedure Bigsub; var A, B, C : integer; procedure Sub1; var A, D : integer; begin { Sub1 } A := B + C; <----------1 end; { Sub1 } procedure Sub2(X : integer); var B, E : integer; procedure Sub3; var C, E : integer; begin { Sub3 } Sub1; E := B + A: <--------2 end; { Sub3 } begin { Sub2 } Sub3; A := D + E; <----------3 end; { Sub2 } begin { Bigsub } SUB2(7); end; { Bigsub } begin Bigsub; end. { Main_2 } Static chains: Position 1: A = (0, 3) B = (1, 4) C = (1, 5) Position 2: E = (0, 4) B = (1, 4) A = (2, 3) Position 3: A = (1, 3) D = error E = (0, 5) NOTE: Main_2 calls Bigsub which calls Sub2 which calls Sub3 which calls Sub1

  13. Displays • Static chains are easy to generate at compile-time • but they are inefficient at run-time because the number of static links that might need to be followed to access a variable is strictly based on the degree of nestedness of the subprogram • this could be any arbitrary amount in a language like Ada or Pascal • An alternative approach is to use displays: • collect all static links into an array • at any time, the contents of this array is the addresses of accessible ARIs on the stack • a display offset value is used to link to the correct ARI and then a local offset is used to find the location of the variable • every subprogram call and return requires modification of the Display to reflect the new static scope situation • so this approach is also costly at run-time, but only requires modification when a subprogram is called or terminates • non-local references can be performed by following only one link

  14. Display Example • Using our previous code, we see how the Display and run-time stack change during the execution of the program • Main_2 calls Bigsub calls Sub2 • Sub2 calls Sub1 “hides” Sub2 • Return to Sub2, Sub2 calls Sub3 From point 1, A = B + C A  (0, 3) B  (2, 3) (down 2 in Display) C  (1, 3) (down 1 in Display) Now, assume that Sub1 contains a nested subprogram, Sub4 where Main_2 calls Bigsub calls Bus2 callsSub3 calls Sub1 calls Sub4 Before Sub1 calls Sub4 and after Sub1 calls Sub4 Dotted line means pointer currently inactive (unavailable)

  15. C-Language Concerns • Since C-languages do not permit nested subprograms, these approaches do not seem necessary • However, C-languages make use of blocks in which local variables can be declared • therefore, blocks are treated like subprograms in that each block has its own ARI • in this case, the ARI contains local variables declared in the block, static and dynamic links, but no return links, parameters or return value • non-local references in this context refer to references to variables not declared in this block, but possibly in this function, and can be resolved using static chains • blocks can also be implemented by allocating all memory for the function at run-time but still setting up static chains within the function – this saves on having to follow static links • a brief example is shown on pages 459-460 if you are interested

  16. Implementing Dynamic Scoping • Reference to non-local variables is determined • based on the order of subprogram calls • not their spatial relationship as in static scoping • two implementation methods • Deep Access • similar to static chains except dynamic links are followed • there are no static links • the distance traversed cannot be determined at compile time so dynamic links are followed until the variable is found • Shallow Access • in dynamic scoping, if variables share the same name, only the most recently declared one is currently active • shallow access uses a separate stack, one for each variable • this stack is modified after each function call/return • access to a variable is always the one at the top of that particular stack • don’t confuse deep/shallow access and deep/shallow binding

  17. Dynamic Scope Example void sub3( ) { int x, z; x = u + v; … } void sub2( ) { int w, x; … } void sub1( ) { int v, w; … } void main( ) { int v, u; … } Assume main calls sub2 which calls sub1 which calls sub2 which calls sub3 The run-time stack using deep access is shown to the right whereas the shallow access is shown below at the point where sub3 is active We see that v is from sub1 (the most recent sub1) and w is from sub2

More Related