Upload
others
View
2
Download
0
Embed Size (px)
Citation preview
Program OrganizationLecture 12
Happy President’s Day, Mr. Lincoln
Inference Rules for Typechecking
É Formal way of representing typing judgments
O[String/x],M,C ` "Hello" : StringO[String/x],M,C ` x : String
O[String/x],M,C ` "Hello".concat(x) : String
String =
¨
SELF_TYPEC if String = SELF_TYPEString otherwise
O,M,C ` let x : String in "Hello".concat(x) : String
Compiler Construction 2/47
Type Checking Wrap up
É Type checking battles between expressivepower and safetyÉ SELF_TYPE is an example of a feature that adds
expressive power at the cost of increasing typechecker complexity
É The type checker guarantees some propertiesof the program at runtimeÉ Rejects invalid programs (sound)É Accepts valid programs (complete)
Compiler Construction 3/47
Inference Rules Wrap up
É Consider: The alternative to inference ruleswould be expressing typing judgments inwritten proseÉ This is error prone and cumbersome
É Inference rules are concise, standard way forcommunicating proofs of expression typesÉ Some degree of complexity is necessary!
Compiler Construction 4/47
The compiler so far
É You made it! You’ve survived the front end
Compiler stages
1. Lexical Analyzer: Regular Expressions2. Syntactic Analyzer: Context-free Grammars3. Semantic Analyzer: Inference Rules4. Next up: Code Generation
Compiler Construction 5/47
Code Generation PrimerWe generate code that ultimately ends up on theCPU
Things we’ll be covering
É What constitutes a programÉ How a program runs
É InitializationÉ Function calls and activation recordsÉ Object lifetime
É How programs interact with the OSÉ IOÉ Dynamic memory management
Compiler Construction 6/47
Where it all begins
ÉÉ CPU executes program code
Compiler Construction 7/47
CPU Instruction Set Architecture
CPU executes a limited set of instructions
É An instruction is alogically-atomic operationperformed by the CPUÉ e.g., add, mov, li, jmp
É The collective set ofinstructions implementedby the CPU is theinstruction set architecture
Compiler Construction 8/47
CPU Instruction Set Architecture (2)
Example Instruction Set Architectures (ISA)
É Intel IA-32 (32 bit x86)É Intel x86-64
É Not to be confused with IA-64 (lol)
É ARM (v7, v8, etc.)É MIPSÉ PowerPCÉ Almost ISAs
É Java VMÉ Cool ASM
Compiler Construction 9/47
CPU Instruction Set Architecture (2)
Example Instruction Set Architectures (ISA)
É Intel IA-32 (32 bit x86)É Intel x86-64
É Not to be confused with IA-64 (lol)
É ARM (v7, v8, etc.)É MIPSÉ PowerPCÉ Almost ISAs
É Java VMÉ Cool ASM
Compiler Construction 9/47
Program
É Compiler technically produces assemblyÉ Assembler produces machine code object filesÉ object files are linked into a single executable
program
Compiler Construction 10/47
Compilation vs. Assembling
Compiler Construction 11/47
Run-time EnvironmentsÉ Before generating code, we need to
understand what we are trying to execute
É Standard techniques exist for structuringexecutable code
É Standard Ways:É CodeÉ StackÉ Heap
Compiler Construction 12/47
Run-time Organization Outline
Management of Run-time resources
Correspondence between static (compile-time) anddynamic (run-time) structures
Storage organization
Compiler Construction 13/47
Run-time Resources
É Execution of a program is initially undercontrol of the operating systemÉ Linux: Fork/exec syscalls;
Windows: CreateProcess APIÉ When a program is invoked:
É The OS alocates space for the programÉ The (machine) code is loaded into part of this spaceÉ The OS jumps to the entry point
(i.e., begin (new Main).main() )
É How does space work?
Compiler Construction 14/47
Program Memory Layout
Memory
Code
Other Space
Low Address (0x0000)
High Address (0xffff)Compiler Construction 15/47
Other Space?Holds all data for the program
Other Space = Data Space
The compiler is responsible for:É Generating code (which is run later)É Orchestrating use of the data area
Compiler Construction 16/47
Code Execution Goals
É Two GoalsÉ CorrectnessÉ Speed
É Most complicationscome from trying tobe both fast andcorrect
Compiler Construction 17/47
Assumptions about Execution
É Execution is sequential; control moves fromone point in a program to another in awell-defined order
É When a procedure is called, control eventuallyreturns to the point immediately after the call
É Do these assumptions always hold?
Compiler Construction 18/47
Compiler Construction 19/47
Procedures/Functions/Methods
É Control abstractionÉ Call/return semantics, parameters, recursion
É Controlled namespaceÉ Scope (local/non-local), binding, addressing
É External interfacesÉ separate compilation, libraries (later in the
semester)
Compiler Construction 20/47
Procedures as Abstractions
É Control flow: call and returnÉ Data flow: parameters and return valuesÉ RecursionÉ Variable addressing
There is no single correct answer for implementingthese abstractions. We use best-practices. Examples:
É Stack discipline, name mangling, etc.
Compiler Construction 21/47
Activations
É An invocation of procedure P is an activationof PÉ The lifetime of an activation of P is
É All the steps to execute PÉ Including all the steps in procedures that P calls
Compiler Construction 22/47
Lifetime vs. Scope
The lifetime of a variable x is the portion ofexecution during which x is defined
N.B. Scope is a static concept, lifetime is a dynamic(run-time) concept
Compiler Construction 23/47
Activation Trees
Recall: when a procedure is called, controleventually returns to the point immediately afterthe call
É This requires that when P calls Q, then Qreturns before P doesÉ Lifetimes of procedure activations are properly
nestedÉ Activation lifetimes can be depicted as a tree
Compiler Construction 24/47
Example Call Tree1 class Main {2 g() : Int {1};3 f() : Int {g()};4 main() : Int {{ g(); f(); }};5 };
main()
g() f()
g()Compiler Construction 25/47
Example Call Tree1 class Main {2 g(x:Int) : Int {1 + x};3 f(x:Int) : Int {g(x+5)};4 main() : Int {{ g(); f(5); f(3); }};5 };
main()
g() f(5)
g(10)
f(3)
g(8)Compiler Construction 26/47
Notes
É Call tree depends on run-time behaviorÉ You could instead construct a call graph statically
É Call tree may be different for every programinput
É How might we store data related to activations?We have a run-time control flow problem
Compiler Construction 27/47
Static Allocation
É First approach: statically allocate space for eachfunction
É All space allocated staticallyÉ Code area
É machine instructions for each procedureÉ Data (static) area
É single data area allocated for each procedureÉ local variables, parameters, return value, saved
registersÉ return address for each procedure
Compiler Construction 28/47
Static AllocationCode area
Code generatedfor f
Code generatedfor g
Data area for f
return addrlocal datareturn valuesaved data for f
Data area for g
return addrlocal datareturn valuesaved data for g
Processing with Static AllocationCaller:1. Save needed data locally (e.g., registers)2. Determine return address, save itCallee:3. Execute4. Save return value5. Restore saved return address
Compiler Construction 29/47
Example Call Tree (2)1 class Main {2 g() : Int {1};3 f(x:Int): Int{4 if x = 0 then g() else f(x-1) fi5 };6 main (): Int {{ f(3); }};7 };
What is the activtion tree for this example?
Compiler Construction 30/47
Example Call Tree (2)1 class Main {2 g() : Int {1};3 f(x:Int): Int{4 if x = 0 then g() else f(x-1) fi5 };6 main (): Int {{ f(3); }};7 };
What is the activtion tree for this example?main()
f(3)f(2)
f(1)f(0)
g()
Compiler Construction 30/47
Notes
É Call tree depends on run-time behaviorÉ You could instead construct a call graph statically
É Call tree may be different for every programinput
É Since activations are properly nested, a stackcan track currently active proceduresÉ We call this the call stack
Compiler Construction 31/47
Call StackCall stack corresponds to a single path in the calltree1 class Main {2 g() : Int {1};3 f() : Int {g()};4 main() : Int {{ g(); f(); }};5 };
Stack
Compiler Construction 32/47
Call StackCall stack corresponds to a single path in the calltree1 class Main {2 g() : Int {1};3 f() : Int {g()};4 main() : Int {{ g(); f(); }};5 };
main()Stackmain()
Compiler Construction 32/47
Call StackCall stack corresponds to a single path in the calltree1 class Main {2 g() : Int {1};3 f() : Int {g()};4 main() : Int {{ g(); f(); }};5 };
main()
g()
Stackmain()
g()
Compiler Construction 32/47
Call StackCall stack corresponds to a single path in the calltree1 class Main {2 g() : Int {1};3 f() : Int {g()};4 main() : Int {{ g(); f(); }};5 };
main()
g()
Stackmain()
Compiler Construction 32/47
Call StackCall stack corresponds to a single path in the calltree1 class Main {2 g() : Int {1};3 f() : Int {g()};4 main() : Int {{ g(); f(); }};5 };
main()
g() f()
Stackmain()
f()
Compiler Construction 32/47
Call StackCall stack corresponds to a single path in the calltree1 class Main {2 g() : Int {1};3 f() : Int {g()};4 main() : Int {{ g(); f(); }};5 };
main()
g() f()
g()
Stackmain()
f()g()
Compiler Construction 32/47
Memory Layout
Compiler Construction 33/47
Call StacksÉ Languages that support recursion
É C, Pascal, Java, CoolÉ Code must be reentrant
É Multiple simultaneous instances of a single procedureÉ Need some place to store state of each instance
É ArgumentsÉ LocalsÉ Return pointer
É Stack DisciplineÉ State for given procedure needed for limited time
É i.e., the lifetime of the procedure
É Callee returns before caller doesÉ Stack allocated in frames
É Each frame is a single procedure instanceÉ More recent procedures higher up in stack
Compiler Construction 34/47
Activation RecordsÉ Each invocation of a method corresponds to a
frame or activation recordÉ If Procedure F calls G, then G’s activation
record contains a mix of information fromboth F and G
É When F calls G:É F is “suspended” (at the call G instruction) until G
completes, at which point F resumes. G’sactivation record contains information needed toresume execution of F .
É G’s AR Also contains:É Parameters to G (supplied by F )É G’s return value (needed by F )É Space for G’s local variables
Compiler Construction 35/47
Activation Records1 class Main {2 g() : Int {1};3 f(x:Int): Int{4 if x = 0 then g() else f(x-1) fi5 };6 main (): Int {{ f(3); }};7 };
AR for f return addresscontrol linkargumentspace for result
Compiler Construction 36/47
Activation Records1 class Main {2 g() : Int {1};3 f(x:Int): Int{4 if x = 0 then g() else f(x-1) (**) fi5 };6 main (): Int {{ f(3); (*) }};7 };
Compiler Construction 37/47
Notes
É main has no argument or local variables and itsresult is never used; its AR is uninterestingÉ (*) and (**) represent return addresses of the
activations of fÉ The return address is where execution resumes
after a procedure call finishes
É We often call this the “C calling convention.”There are other ways to design activations
Compiler Construction 38/47
x86-64 Stack
Compiler Construction 39/47
Discussion
É The compiler must determine and adhere to aconsistent stack discipline. It must layoutactivation records so that emitted code cancorrectly access locations in the activationrecord
É You codesign the AR layout with the compiler!
Compiler Construction 40/47
Discussion
É The advantage of placing the return value firstin a frame is that the caller can find it at a fixedoffset from its own frameÉ The caller must write the return address there
É There is nothing magic about this organizationÉ Can rearrange order of frame elementsÉ Can divide caller/callee responsibilities differentlyÉ Organization is better if it improves execution
speed or simplifies code generation
Compiler Construction 41/47
Discussion
É Real compilers use as many registers as possibleÉ Especially for method result and arguments
Compiler Construction 42/47
Memory Layout with GlobalsÉ All references to a global variable point to the
same objectÉ Can’t store a global in an activation recordÉ Globals assigned fixed addresses (statically
allocated)
Compiler Construction 43/47
Looking Forward: PA5
É Decide: Cool ASM or Intel x86-64
Compiler Construction 44/47
Heap Storage
É A value that outlives the procedure that createsit cannot be kept in the ARÉ method foo() new Bar ;
É The Bar value must survive deallocation offoo’s AR
Languages with dynamically allocated data use aheap to store dynamic data
É Must rely on the OS to give you space atruntime!É malloc(), sbrk, ...
Compiler Construction 45/47
Memory with Heap
Compiler Construction 46/47
Heap
You must support code like:1 let x = new Counter (5) in2 let y = x in {3 x.increment (1);4 out_int( y.getCount () );5 }
É You need an explicit heap that maps addresses(integers) to values
Compiler Construction 47/47