Chapter 5 (3)
Chapter 5 (3)
Fig. Example of subroutine nesting: Within B, C, and D, all five routines are visible. Within A and E,
routines A, B, and E are visible, but C and D are not. Given the calling sequence A, E, B, D, C, in that
order, frames will be allocated on the stack as shown at right, with the indicated static and dynamic links.
Calling Sequence
• Maintenance of the subroutine call stack is the responsibility of the calling Sequence,
• The code executed by the caller immediately before and after a subroutine
• Prologue (code executed at the beginning) and
• Epilogue (code executed at the end) of the subroutine itself
• Tasks that must be accomplished on the way into a subroutine include:
Passing parameters,
Saving the return address,
Changing the program counter,
Changing the stack pointer to allocate space,
Saving registers (including the frame pointer) that contain important values and
that may be overwritten by the callee,
Changing the frame pointer to refer to the new frame, and
Executing initialization code for any objects in the new frame that require it.
Cont’d
Calling Sequence..
• Tasks that must be accomplished on the way out include:-
passing return parameters or function values,
executing finalization code for any local objects that require it,
deallocating the stack frame (restoring the stack pointer),
restoring other saved registers (including the frame pointer), and
restoring the program counter.
• Some of these tasks (e.g., passing parameters) must be performed by the caller, because
they differ from call to call.
• Most of the tasks, however, can be performed either by the caller or the callee.
Calling Sequence.. Cont’d
Calling sequence conventions for many processors (MIPS and x86 among others)
• Two sets: caller responsibility and callee responsibility.
• Callee can assume that there is nothing of value in any of the caller saved
register set.
• Caller can assume no callee will destroy contents in any of the callee saves set.
• In the interests of code size ,compiler will then use
• callee-saves registers for local variables and other long-lived ones if possible &
• caller-saves set for transient values, which are less likely to be needed across
calls. .
Calling Sequences: RISC architecture
Cont’d
Fig. A typical stack frame. Though we draw it growing upward on the page, the stack actually grows downward toward
lower addresses on most machines. Arguments are accessed at positive offsets from the fp. Local variables and
temporaries are accessed at negative offsets from the fp. Arguments to be passed to called routines are assembled at the
top of the frame, using positive offsets from the sp.
In-Line Expansion
• In some languages, programmers can actually flag routines that should be expanded inline –stack
overhead is avoided.
• Example (in C++ or C99):
inline int max(int a,int b)
{ return a > b ? a : b}
• Ada does something similar, but keyword is:
pragma inline(max);
• A copy of the called routine becomes a part of the caller
no actual subroutine call occurs.
• In-line expansion avoids a variety of overheads, including space allocation
Parameter Passing
• Formal parameters: Parameter names that appear in the declaration of a subroutine
• Actual parameters: Variables and expressions that are passed to a subroutine in a particular call.
int main()
{
add(m,n) // Actual parameters
}
int add(int a, int b) // Formal parameters
{
return (a+b);
}
Parameter Passing
• Parameter passing modes:
• Call by value: make a copy of the parameter.
• Call by reference (aliasing): allows the function to change the parameter
• The two names are aliases for the same object, and changes made through one
will be visible through the other
• closure/name: reference to a subroutine, together with its referencing environment
• Call by sharing: requires parameter to be a reference itself.
• Makes copy of reference that initially refers to the same object. E.g.,
Python, Java Objects.
• Many languages (e.g., Pascal, Ada, Modula) provide different modes
• Others have a single set of rules (e.g. C, Fortran, ML, Lisp)
Parameter Passing Cont’d
Read only parameters : formal parameters declared read only cannot be changed by called
routines.
• Similar to c constant and available in Modula -3
Parameter Passing Cont’d
Call-by-value:
Can be expensive to implement (e.g., copying large objects).
Can't change a parameter, except by returning a new copy.
Call-by-reference:
Out-parameters (i.e., the procedure returns values through its parameters).
• Allows callee to change something and have it persist
• Saves space/time copying
Good: More flexibility.
Bad: Can be confusing when arguments change.
begin Output:
intger n;
procedure p(k:integer); Call by value: 1 1 1
begin
print(k); Call by name:1 11 16
n=n+10;
print(k);
n:=n+5;
print(k);
end;
n:=0;
p(n+1);
end;
Parameter Passing Cont’d
Fig. Parameter-passing modes. Column 1 indicates common names for modes. Column 2 indicates prominent
languages that use the modes, or that introduced them. Column 3 indicates implementation via passing of values,
references, or closures. Column 4 indicates whether the callee can read or write the formal parameter. Column 5
indicates whether changes to the formal parameter affect the actual parameter. Column 6 indicates whether changes
to the formal or actual parameter, during the execution of the subroutine, may be visible through the other.
Generic Subroutines and Modules
• Structured programming is away to split your code in blocks.
• Subroutines is a sequence of program instruction that performs a specific task, packeged
unit.
• Modules help the programmer to split their code
• Generic modules or classes are particularly valuable for creating containers: data
abstractions that hold a collection of objects
• Example: OS needs queues that can hold processes, memory descriptors, file
buffers, etc.
• Generic subroutines (methods) are needed in generic modules (classes), and may also be
useful in their own right.
• With large programs containing many method subroutines will be needed to perform similar
Generic Subroutines and Modules
Subroutine Add example: Generic subroutine
string add(string a, string b) Public T <T> add(T a, T b)
return a+b; return a+b;
int add(int a, int b)
return a+b; int c= add(5,7)
double add(double a, double b) double d= add(4.5, 5.5)
return a+b; String concat=add(“gen”, “erics”)
• Subroutine should be written once and be capable of accepting any argument. This idea is
known as generic programming.
• Generic or polymorphic subroutine is one that takes parameter of different types on different
activation.
E.g. Java, C++, Ada, clu, Eiffel, modula-3 ,C#..
Generic Subroutines and Modules
Implementation approaches:
• Ada and C++ they are a purely static mechanism: all the work required to create and use multiple
instances of the generic code takes place at compile time.
• The compiler creates a separate copy of the code for every instance.
• Java 5, in contrast, guarantees that all instances will share the same code at run time,
• If T is a generic type parameter in Java, objects of class T are treated as instances of the standard
base Object that Java supports
A generic add method in C++ & Java:
template <typename T> T add(T a, Tb) public <T> T add(T a, Tb)
{ ava
{ J
return a+b; return a+b;
} }
To call the method:
+ add(5,6);
C+ add(5.6, 7,8);
Exception Handling
What is an exception?
• A hardware-detected run-time error or unusual condition detected by software
Examples
• arithmetic overflow
• end-of-file on input
• wrong type for input data
• user-defined conditions, not necessarily errors
What is an exception handler?
• code executed when exception occurs
• may need a different handler for each type of exception
Why design in exception handling facilities?
• allow user to explicitly handle errors in a uniform manner
Exception Handling
• Many more recent languages, including Clu, Ada, Modula-3, Python, PHP, Ruby, C++,
Java, C#, and ML, all provide exception-handling facilities in which handlers are lexically
bound to blocks of code,
A simple try block in C++ In Ada, exception is a built-in type; an exception
is simply an object of this type:
declare empty_queue : exception;
• Coroutines cannot share a single stack: their subroutine calls and returns, taken as a
whole, do not occur in last-in-first-out order.
• If each coroutine is declared at the outermost level of lexical nesting, then their
stacks are entirely disjoint.
• A coroutine is represented by a closure (a code address and a referencing environment),
• Coroutines can be used to implement
• iterators
• threads
Coroutines
Fig. Coroutines stack allocation. Each branch to the side represents the creation of a coroutine (A, B, C, and D ). The static
nesting of blocks is shown at right. Static links are shown with arrows. Dynamic links are indicated simply by vertical
arrangement: each routine has called the one above it. (Coroutine B, for example, was created by the main program, M. B in
turn called subroutine S and created coroutine D .)
End of chapter - 5
a:int a:int
Procedure P(b:int) Procedure P(a:int, b:int)
{ {
b=b+1 b=a
b=b+a b=a
} }
a=2 a=3
P(a) P(a+1,a)
Print a Print a