First-Class Functions • Reading: Appel 15.1-15.6 27 Apr 01
Total Page:16
File Type:pdf, Size:1020Kb
Administration CS 412 • Programming Assignment 6 write-up due in one week Introduction to Compilers – register allocation Andrew Myers –constant folding Cornell University – unreachable code elimination Lecture 35: First-class functions • Reading: Appel 15.1-15.6 27 Apr 01 Lecture 35 CS 412/413 Spring '01 -- Andrew Myers 2 Advanced Language Support First-class vs. Second-class • “advanced” language features so far: • Values are first-class if they can be used in objects all the usual ways • Next four lectures: more modern language – assigned to local variables features – passed as arguments to functions/methods – first-class functions – returned from functions –exceptions – created at run-time – parametric polymorphism • Iota: modules, functions are denoted by – dynamic typing and meta-object protocols expressions but are only usable in limited ways (uses, function call) Lecture 35 CS 412/413 Spring '01 -- Andrew Myers 3 Lecture 35 CS 412/413 Spring '01 -- Andrew Myers 4 First-class functions Function Types + • Many languages allow functions to be used •Iota-F0: Iota with function values that can be in a more first-class manner than in Iota passed as arguments (still not fully first-class) or Java: C, C++, ML, Modula-3, Pascal, • Need to declare type of argument; will use Scheme,... program notation function(T1, T2): T3 to denote the function type T ×T →T . – Passed as arguments to functions/methods 1 2 3 • Example: sorting with a user-specified ordering: – Nested within containing functions sort(a: array[int], (exc. C, C++) order: function(int, int):bool) { – Used as return values (exc. Modula-3, Pascal) … if (order(a[i], a[j])) { … } ... Lecture 35 CS 412/413 Spring '01 -- Andrew Myers 5 Lecture 35 CS 412/413 Spring '01 -- Andrew Myers 6 1 Passing a Function Value Objects subsume functions! leq(x: int, y: int): bool = x <= y interface comparer { geq(x: int, y:int): bool = x >= y compare(x: int, y:int): bool sort(a: array[int], } order: function(int, int):bool) … sort(a: array[int], cmp: comparer) { … if (cmp.compare(a[i], a[j])) { … } … sort(a1, leq) sort(a2, geq) class leq implements comparer { compare(x: int, y:int) = x <= y; • Allows abstraction over choice of } functions sort(a1, new leq); Lecture 35 CS 412/413 Spring '01 -- Andrew Myers 7 Lecture 35 CS 412/413 Spring '01 -- Andrew Myers 8 Type-checking functions Representing functions • Same rules as in Iota static semantics, but •For Iota-F0, a function may be represented function invoked in function call may be a as a pointer to its code (cheaper than an object) general expression • Old translation: E f(e1,…,en) = → ∈ A e : T × ... × T →T E E f : T1 × ... × Tn TR A 0 1 n R CALL(NAME( f ), e1 ,…, en ) i ∈ 1..n i ∈ 1..n A ei : Ti A ei : Ti • New: Ee (e ,…,e )= A f ( e ,..., e ) : T 0 1 n 1 n R A e0 ( e1,..., en ) : TR E E E CALL( e0 , e1 ,…, en ) • Subtyping on function types: usual Eid = NAME(id) contravariant/covariant conditions (if id is a global fcn) Lecture 35 CS 412/413 Spring '01 -- Andrew Myers 9 Lecture 35 CS 412/413 Spring '01 -- Andrew Myers 10 Nested Functions Iteration in Iota-F1 • Also useful for iterators, other user-defined control flow • In functional languages (Scheme, ML) and constructs interface set { members(f: function(o: object)) } Pascal, Modula-3, Iota-F1 • Nested function can access variables of the countAnimals(s: set) = ( containing lexical scope count: int = 0; loop_body(o: object) = ( plot_graph(f: function(x: float): float)= if (cast(o, Animal)) count ++; ( … y = f(x) … ) ) plot_quadratic(a,b,c: float) = ( s.members(loop_body); q(x: float): float = a*x*x+b*x+c; return count; plot_graph(q) ) • Nested functions may access, update free variables from ) containing scopes! Must change function representation nested function free variables Lecture 35 CS 412/413 Spring '01 -- Andrew Myers 11 Lecture 35 CS 412/413 Spring '01 -- Andrew Myers 12 2 A subtle program Lexical scope int f(n: int, • g(): int = x creates a new function value g1: function(): int, • Free variable (x) is bound to the variable g2: function(): int) = ( lexically visible at evaluation of function int x = n+10; expression int f(n: int, g(): int = x; g1: function(): int, if (n == 0) f(1, g, dummy) g2: function(): int) = ( call stack int x = n+10; else if (n==1) f(2, g1, g) call stack f(0,dummy,dummy) x=10 f(0,dummy,dummy) x=10 g(): int = x; else g1() + g2() + g() f(1, g, dummy) x=11 f(1,g,dummy) x=11 if (n == 0) f(1, g, dummy) else if (n==1) f(2, g1, g) ) f(2,g1,g) x=12 f(2, g1, g) x=12 else g1() + g2() + g() g1(), g2(), g() g1(), g2(), g() f(0,dummy,dummy) = ? ) Lecture 35 CS 412/413 Spring '01 -- Andrew Myers 13 Lecture 35 CS 412/413 Spring '01 -- Andrew Myers 14 Closures Closure • Problem: nested function (g) may need to • Closure -- A pointer to the code plus a static link to allow access to outer scope access variables arbitrarily high up on • Static link passed to function code as implicit stack argument • Before nested functions: function value was pointer to code (1 word) f activation record f(n: int, …) = { • With nested functions: function value is a x int x = n + 10; g g(): int = x; closure of code + environment for free other stack g closure … frames } variables code ptr (2 words) g activation record static link static link shared g Lecture 35 CS 412/413 Spring '01 -- Andrew Myers 15 Lecture 35 CS 412/413 Spring '01 -- Andrew Myers code 16 Supporting Closures Static Link Chains E e0(e1,…,en) = f() = (a: int; E implicit static link argument ESEQ(MOVE(t1, e0 ), g() = (b:int; f stack frame E E CALL(MEM(t1), MEM(t1+4), e1 ,…, en ) h() = ( a Sid(..a : T ..) : T = e= ...other function i i R c = a + b; stack frames... t1 = FP — k ; g stack frame id ) … b [t1] = NAME(id); t1 code addr static link to f [t1+4] = FP; static link ) … ...other function stack frames... • Can optimize direct calls ) h stack frame • Function variable takes 2 stack locations static link to g • What about variable accesses? Lecture 35 CS 412/413 Spring '01 -- Andrew Myers 17 Lecture 35 CS 412/413 Spring '01 -- Andrew Myers 18 3 Variable access code Progress Report • Local variable access √ Passed as arguments to unchanged f stack frame functions/methods • Free variable access: a √ Nested within containing functions as walk up n static links ...other function before indexing to stack frames... local variables g stack frame variable b —Used as return values static link to f • If no nested functions, functions are just ...other function stack frames... pointers to code; can be used as return values (C) h stack frame static link to g • Problem: interaction with nested fcns Lecture 35 CS 412/413 Spring '01 -- Andrew Myers 19 Lecture 35 CS 412/413 Spring '01 -- Andrew Myers 20 Iota-F2 (first-class functions) Dangling static link! •Augment Iota-F1 to allow the return ret addr make_counter( ): (function( ): int) = ( type of a function to be a function itself. // returns a counter function old FP int count; make_counter( ): (function( ): int) = ( count make_counter inc( ): int = ( count++; ) stack frame return inc; // returns a new counter function ) int count = 0; inc inc(): int = ( count++ ); return inc inc code ) make_counter()() + make_counter()() = ? c = make_counter(); c() + c() + c() = ? Lecture 35 CS 412/413 Spring '01 -- Andrew Myers 21 Lecture 35 CS 412/413 Spring '01 -- Andrew Myers 22 Heap allocation The GC side-effect ret addr stack make_counter( ): function( ): int = ( • Every function call creates an object that frame old fp // returns a counter function must be garbage collected eventually -- make_counter int count; activation inc( ): int = ( count++; ) increases rate of garbage generation record return inc; count ) • Activation records of all lexically enclosing functions are reachable from a closure via inc stack link chains inc code • Activation record makes a lot of garbage • Solution: heap-allocate the look reachable! make_counter activation record (at least count) • Activation record ≠ stack frame •Even local variable accesses indirected Lecture 35 CS 412/413 Spring '01 -- Andrew Myers 23 Lecture 35 CS 412/413 Spring '01 -- Andrew Myers 24 4 Escape analysis Example • Idea: local variable only needs to be stored on make_counter(start: int): function( ): int = ( // returns a counter function heap if it can escape and be accessed after this int count = start; function returns inc( ): int = ( c: int; count++; ) return inc; • Only happens if ) – variable is referenced from within some nested activation escaping variable function and stack frame stack frame record (heap) record (heap) – the nested function is turned into a closure: •returned, or start start ret addr count • passed to some function that might store it in a data ret addr start structure old fp old fp count (calls to nested functions not a problem) inc • This determination: escape analysis inc Lecture 35 CS 412/413 Spring '01 -- Andrew Myers 25 Lecture 35 CS 412/413 Spring '01 -- Andrew Myers 26 Benefits of escape analysis Summary • Variables that don’t escape are allocated • Looked at 3 languages progressively making functions more first-class on stack frame instead of heap: cheap to • No lexical nesting (F0, C) access – Fast but limited • If no escaping variables, no heap – Function = pointer to code allocation at all (common case) • Lexical nesting, no upward function values or storage in data structures (F1, Pascal, Modula-[123]): • Closures don’t pin down as much garbage – function value is closure (F , Scheme, ML): when created • Fully first-class: return values 2 – lots of heap-allocation, more indirection • One problem: precise escape analysis is a – Functions roughly as powerful as objects (sometimes more global analysis, expensive.