Subroutines and Control Abstraction Aaron Bloomfield CS 415 Fall 2005 1 Definitions • Function: subroutine that returns a value • Procedure: subroutine that does not return a value 2 Review of Stack Layout • Storage consumed by parameters and local variables can be allocated on a stack • Activation record contains arguments and/or return values, bookkeeping info, local variables, and/or temporaries • On return, stack frame is popped from stack 3 Review of Stack Layout (cont’d) • Stack pointer: contains address of the first unused location at the top of the stack • Frame pointer: contains address within frame • Displacement addressing • Objects with unknown size placed in variable-size area at top of frame 4 Review of Stack Layout (cont’d) Static chain - Each stack frame contains a reference to the lexically surrounding subroutine 5 Review of Stack Layout (cont’d) Display - used to reduce memory accesses to an object k levels out 6 Calling Sequences • Calling sequence: code executed by the caller immediately before and after a subroutine call • Prologue • Epilogue 7 Calling Sequences (cont’d) • Tasks on the way in (prologue) – Passing parameters, saving return address, changing program counter, changing stack pointer, saving registers, changing frame pointer • Tasks on the way out (epilogue) – Passing return parameters, executing finalization code, deallocating stack frame, restoring saved registers and pc 8 Case Study 1: C on the MIPS (example of RISC) 9 Case Study 2: Pascal on the 680x0 (example of CISC) 10 In-Line Expansion • Allows certain subroutines to be expanded in-line at the point of call • Avoids several overheads (space allocation, branch delays, maintaining static chain or display, saving and restoring registers) 11 Implementations of In-line Expansion • C++ uses keyword inline: inline int max( … ) { … } • Ada: pragma inline (function_name); • Pragmas make suggestions to the compiler. Compiler can ignore suggestion. 12 In-line Expansion versus Macros • in-line expansion – Semantically preferable – Disadvantages? • macros – Semantic problems – Syntactic problems 13 Parameter Passing Parameter Modes Special-Purpose Parameters Function Returns 14 Parameter Passing Basics • Parameters - arguments that control certain aspects of a subroutine’s behavior or specify the data on which they are to operate • Global Variables are other alternative • Parameters increase the level abstraction of 15 More Basics • Formal Parameters parameter name in the subroutine declaration • Actual Parameters – values passed to a subroutine in a particular call 16 Parameter Modes • Some languages define a single set of rules which apply to all parameters – C, Fortran, Lisp • Some languages provide two or more sets of rules, which apply to different parameter modes – Algol, Pascal, Ada, Modula – We will discuss Ada Parameter Modes in more detail 17 Call by Value • • • • For P(X), two options are possible: Call by Value and Call by Reference Call by Value - provides P with a copy of X’s value Actual parameter is assigned to the corresponding formal parameter when subroutine is called, and the two are independent from then on Like creating a local or temporary variable 18 Call by Reference • Call by Reference – provide P with the address of X • The formal parameter refers to the same object as the actual parameter, so that changes made by one can be seen by the other 19 Language Specific Variations • Pascal: Call by Value is the default, the keyword VAR denotes Call by Reference • Fortran: all parameters passed by Reference • Smalltalk, Lisp: Actual Parameter is already a reference to the object • C: always passed by Value 20 Value vs. Reference • Pass by Value – Called routine cannot modify the Actual Parameter • Pass by Reference – Called routine can modify Actual Parameter 21 Call by name • Pretty much only in Algol • Re-evaluates the actual parameter on every use – For actual parameters that are simple variables, it’s the same as call by reference – For actual parameters that are expressions, the expression is re-evaluated on each access • No other language ever used call by name… 22 Safety and Efficiency • Without language support, working with large objects that are not to be modified can be tricky – Call by Value: – Call by Reference: • Examples of Language Support – Modula: READONLY parameter mode – C/C++: const keyword 23 Ada Parameter Modes Three parameter passing modes • In – Passes information from the caller to the callee, can read but not write – Call by Value • Out – Passes information from the callee to the caller, can write but not read – Call by Result (formal parameter is copied to actual parameter when subroutine exits) • Inout - passes information both directions 24 C++ Parameter Modes C passes pointers as addresses, must be explicitly dereferenced when used C++ has notion of references: • Parameter passing: void swap (int &a, int &b) • Variable References: int &j = i; • Function Returns: for objects that don’t support copy operations, i.e. file buffers 25 Review: references to functions • When are scope rules applied? – When the function is called? • Shallow binding – When the reference is created? • Deep binding 26 int max_score; float scale_score (int raw_score) { return (float) raw_score / (float) max_score; } float highest_score (int[] scores, function_ptr scaling_function) { float max_score = 0; foreach score in scores { float percent = scaling_function (score); if ( percent > max_score ) max_score = percent; function is called } return max_score; } main() { reference is created max_score = 50; int[] scores = ... print highest_score (scores, scale_score); } 27 Deep Binding • Generally the default in lexically (statically) scoped languages • Dynamically scoped languages tend to use shallow binding 28 Closures • Implementation of Deep Binding for a Subroutine – Create an explicit representation of the current referencing environment and its bindings – Bundle this representation with a reference to the subroutine – This bundle is called a Closure 29 Closures as Parameters • Closures: a reference to a subroutine and its referencing environment • Closures can be passed as a parameter • Pascal, C, C++, Modula, Scheme void apply_to_A (int (*f) (int), int A[], int A_size) { int i; for (i = 0; i < A_size; i++) A[i] = f (A[i]); } 30 Special-Purpose Parameters • Named Parameters - parameters that are not positional, also called keyword parameters. An Ada example: funcB (argA => 21, argB => 35); funcB (argB => 35, argA => 21); • Some languages allow subroutines with a variable number of arguments: C, Lisp, etc. int printf (char *format, …) {… • Standard Macros in function body to access extra variables 31 Function Returns • Some languages restrict Return types – Algol 60, Fortran: scalars only – Pascal, Modula: scalars or pointers only – Most imperative languages are flexible • Return statements specify a value and also cause the immediate termination of the subroutine 32 Generic Subroutines and Modules Generic Subroutines Generic Modules 33 Generic Subroutines • Large Programs often use the same data structures for different object types • Characteristics of the queue data structure independent of the characteristics of the items in the queue • Polymorphic subroutines – Argument types are incompletely specified – Can cause slower compilation – Sacrifice compile-time type checking 34 Generic Modules • Similar subroutines are created from a single piece of source code • Ada, Clu, Modula-3 • C++ templates • Similar to macros, but are actually integrated into the rest of the language • Follow scope, naming, and type rules 35 Exception Handling 36 Exceptions • Exceptions are an unexpected or unusual condition that arises during program execution. • Most common are various sorts of runtime errors (ex. encountering the end of a file before reading a requested value) 37 Handling Exceptions • Exception handling was pioneered by PL/I • Utilized an executable statement of the following form: ON condition statement • Handler is nested inside and is not executed on the ON statement but is remembered for future reference. • Executes exception when exception condition is encountered 38 Handling Exceptions • Recent languages provide exception-handling facilities where handlers are lexically bound to blocks of code. • General rule is if an exception isn’t handled in the current subroutine, then the subroutine returns and exception is raised at the point of call. • Keeps propagating up dynamic chain until exception is handled. • If not handled a predefined outermost handler is invoked which will terminate the program. 39 3 Main Handler Uses • 1) Perform some operation that allows the program to recover from the exception and continue executing. • 2)If recovery isn’t possible, handler can print helpful message before termination • 3)When exception occurs in block of code but can’t be handled locally, it is important to declare local handler to clean up resources and then reraise the exception to propagate back up. 40 Defining Exceptions • Ada declare empty_queue : exception; • Modula-3 EXCEPTION empty_queue; • C++ and Java class empty_queue{}; 41 Exception Propagation try{ ... //protected block of code ... }catch(end_of_file) { ... }catch(io_error e) { //handler for any io_error other than end_of_file ... }catch(…) { //handler for any exception not previously named //… is a valid token in the case in C++, doesn’t //mean code has been left out. } 42 Implementing Exceptions • Can be made as a linked list stack of handlers. • When control enters a protected block, handler for that block is added to head of list. • Propagation down the dynamic chain is done by a handler in the subroutine that performs the work of the subroutine’s epilogue code and the reraises the exception. 43 Problems With This Implementation • Incurs run-time overhead in the common case • Every protected block and every subroutine begins with code to push a handler onto the handler list, and ends with code to pop it off the list. 44 A Better Implementation • Since blocks of code in machines can translate to continuous blocks of machine instructions, a table can be generated at compile time that captures the correspondence between blocks and handlers Starting Address Address of of Code Block Corresponding Handler 45 Implementing Exceptions • Table is sorted by the first field of the table • When an exception occurs the system performs a search of the table to find the handler for the current block. • If handler re-raises the exception, the process repeats. 46 Coroutines 47 Coroutines • Coroutines are execution contexts that exist concurrently, but execute one at a time, and transfer control to each other explicitly, by name. • They can implement iterators and threads. 48 Stack Allocation • Since they are concurrent they can’t share a single stack because subroutine calls and returns aren’t LIFO • Instead the run-time system uses a cactus stack to allow sharing. 49 Transfer • To go from one coroutine to another the run-time system must change the PC, stack, and register contents. This is handled in the transfer operation. 50