Compiler Construction

Slides:



Advertisements
Similar presentations
Code Generation.
Advertisements

CSI 3120, Implementing subprograms, page 1 Implementing subprograms The environment in block-structured languages The structure of the activation stack.
Prof. Necula CS 164 Lecture 141 Run-time Environments Lecture 8.
Chapter 10 Implementing Subprograms. Copyright © 2012 Addison- Wesley. All rights reserved. 1-2 Chapter 10 Topics The General Semantics of Calls and Returns.
CS 326 Programming Languages, Concepts and Implementation Instructor: Mircea Nicolescu Lecture 18.
ISBN Chapter 10 Implementing Subprograms.
1 Storage Registers vs. memory Access to registers is much faster than access to memory Goal: store as much data as possible in registers Limitations/considerations:
1 Chapter 7: Runtime Environments. int * larger (int a, int b) { if (a > b) return &a; //wrong else return &b; //wrong } int * larger (int *a, int *b)
CS 536 Spring Run-time organization Lecture 19.
ISBN Chapter 10 Implementing Subprograms.
3/17/2008Prof. Hilfinger CS 164 Lecture 231 Run-time organization Lecture 23.
ISBN Chapter 10 Implementing Subprograms.
Runtime Environments Source language issues Storage organization
1 Pertemuan 20 Run-Time Environment Matakuliah: T0174 / Teknik Kompilasi Tahun: 2005 Versi: 1/6.
Run time vs. Compile time
Semantics of Calls and Returns
The environment of the computation Declarations introduce names that denote entities. At execution-time, entities are bound to values or to locations:
Chapter 9: Subprogram Control
Run-time Environment and Program Organization
1 CSCI 360 Survey Of Programming Languages 9 – Implementing Subprograms Spring, 2008 Doug L Hoffman, PhD.
1 Run time vs. Compile time The compiler must generate code to handle issues that arise at run time Representation of various data types Procedure linkage.
Chapter 10 Implementing Subprograms. Copyright © 2007 Addison-Wesley. All rights reserved. 1–2 Semantics of Call and Return The subprogram call and return.
Presented by Dr Ioanna Dionysiou
1 Contents. 2 Run-Time Storage Organization 3 Static Allocation In many early languages, notably assembly and FORTRAN, all storage allocation is static.
Chapter 7: Runtime Environment –Run time memory organization. We need to use memory to store: –code –static data (global variables) –dynamic data objects.
ISBN Chapter 10 Implementing Subprograms.
Runtime Environments What is in the memory? Runtime Environment2 Outline Memory organization during program execution Static runtime environments.
Runtime Environments Compiler Construction Chapter 7.
Chapter 10 Implementing Subprograms. Copyright © 2012 Addison-Wesley. All rights reserved.1-2 Chapter 10 Topics The General Semantics of Calls and Returns.
CSc 453 Runtime Environments Saumya Debray The University of Arizona Tucson.
Chapter 7 Runtime Environments. Relationships between names and data objects As execution proceeds, the same name can denote different data objects Procedures,
CPSC 388 – Compiler Design and Construction Runtime Environments.
1 Run-Time Environments. 2 Procedure Activation and Lifetime A procedure is activated when called The lifetime of an activation of a procedure is the.
Basic Semantics Associating meaning with language entities.
Runtime Environments. Support of Execution  Activation Tree  Control Stack  Scope  Binding of Names –Data object (values in storage) –Environment.
CSC3315 (Spring 2008)1 CSC 3315 Subprograms Hamid Harroud School of Science and Engineering, Akhawayn University
ISBN Chapter 10 Implementing Subprograms.
Implementing Subprograms What actions must take place when subprograms are called and when they terminate? –calling a subprogram has several associated.
BİL 744 Derleyici Gerçekleştirimi (Compiler Design)1 Run-Time Environments How do we allocate the space for the generated target code and the data object.
Run-Time Storage Organization Compiler Design Lecture (03/23/98) Computer Science Rensselaer Polytechnic.
RUN-Time Organization Compiler phase— Before writing a code generator, we must decide how to marshal the resources of the target machine (instructions,
Runtime Organization (Chapter 6) 1 Course Overview PART I: overview material 1Introduction 2Language processors (tombstone diagrams, bootstrapping) 3Architecture.
國立台灣大學 資訊工程學系 薛智文 98 Spring Run Time Environments (textbook ch# 7.1–7.3 )
CSC 8505 Compiler Construction Runtime Environments.
Intermediate Representation II Storage Allocation and Management EECS 483 – Lecture 18 University of Michigan Wednesday, November 8, 2006.
7. Runtime Environments Zhang Zhizheng
1 Run-Time Environments Chapter 7 COP5621 Compiler Construction Copyright Robert van Engelen, Florida State University, 2005.
RUNTIME ENVIRONMENT AND VARIABLE BINDINGS How to manage local variables.
Chapter 10 Implementing Subprograms. Copyright © 2012 Addison-Wesley. All rights reserved.1-2 Chapter 10 Topics The General Semantics of Calls and Returns.
10-1 Chapter 10: Implementing Subprograms The General Semantics of Calls and Returns Implementing “Simple” Subprograms Implementing Subprograms with Stack-Dynamic.
ISBN Chapter 10 Implementing Subprograms.
Implementing Subprograms
ISBN Chapter 10 Implementing Subprograms.
1 Compiler Construction Run-time Environments,. 2 Run-Time Environments (Chapter 7) Continued: Access to No-local Names.
ISBN Chapter 10 Implementing Subprograms.
LECTURE 19 Subroutines and Parameter Passing. ABSTRACTION Recall: Abstraction is the process by which we can hide larger or more complex code fragments.
Runtime Environments Chapter 7. Support of Execution  Activation Tree  Control Stack  Scope  Binding of Names –Data object (values in storage) –Environment.
Run-Time Environments Presented By: Seema Gupta 09MCA102.
Run-Time Environments Chapter 7
Subject Name Compiler Design Subject Code: 10CS63
Run-time organization
Run-Time Storage Organization
Run-Time Storage Organization
Run-Time Environments
Run-Time Environments
Topic 3-b Run-Time Environment
UNIT V Run Time Environments.
Run Time Environments 薛智文
Runtime Environments What is in the memory?.
Presentation transcript:

Compiler Construction Runtime Environment

Run-Time Environments (Chapter 7)

Run-Time Environments (Chapter 7) A lot has to happen at run time to get your program running. At run time, we need a system to map NAMES (in the source program) to STORAGE on the machine. Allocation and deallocation of memory is handled by a RUN-TIME SUPPORT SYSTEM typically linked and loaded along with the compiled target code. One of the primary responsibilities of the run-time system is to manage ACTIVATIONS of procedures.

Procedures We assume in this lecture that a program is no more than a collection of PROCEDURES. A PROCEDURE DEFINTION associates an identifier with a statement (a statement could actually be a block of statements, of course). The identifier is called the PROCEDURE NAME. The statement is called the PROCEDURE BODY. A PROCEDURE CALL is an invocation of a procedure within an executable statement. Procedures that return values are normally called FUNCTIONS, but we’ll just use the name “procedure.”

Example program program sort( input, output ); var a: array [ 0..10 ] of integer; procedure readarray; var i: integer; begin for i := 1 to 9 do read( a[i] ) end; function partition( y, z: integer ) : integer; var i, j, x, v: integer; begin … procedure quicksort( m, n: integer ); if ( n > m ) then begin i := partition( m, n ); quicksort(m,i-1); quicksort(i+1,n) end a[0] := -9999; a[10] := 9999; readarray; quicksort(1,9); end.

Parameters of procedures The FORMAL PARAMETERS are special identifiers declared in the procedure definition. The formal parameters must correspond to the ACTUAL PARAMETERS in the function call. E.g. m and n are formal parameters of the quicksort procedure. The actual parameters in the call to quicksort in the main program are 1 and 9. Actual parameters can be a simple identifier, or more complex expressions.

Control flow Let’s assume, as in most mainstream programming languages, that we have SEQUENTIAL program flow. Procedure execution begins at the first statement of the procedure body. When a procedure returns, execution returns to the instruction immediately following the procedure call.

Activations Every execution of a procedure is called an ACTIVATION. The LIFETIME of an activation of procedure P is the sequence of steps between the first and last steps of P’s body, including any procedures called while P is running. Normally, when control flows from one activation to another, it must (eventually) return to the same activation. When activations are thusly nested, we can represent control flow with ACTIVATION TREES.

Activation trees Execution begins… enter readarray leave readarray enter quicksort(1,9) enter partition(1,9) leave partition(1,9) enter quicksort(1,3) … leave quicksort(1,3) enter quicksort(5,9) leave quicksort(5,9) leave quicksort(1,9) Execution terminated.

Control stacks We can use a stack to keep track of currently-active activations. We push a record onto the stack when a procedure is called, and pop that record off the stack when the procedure returns. At any point in time, the control stack represents a path from the root of the activation tree to one of the nodes.

Example control stack This partial activation tree corresponds to control stack (growing downward) s q(1,9) q(1,3) q(2,3)

Declarations Every DECLARATION associates some information with a name. In Pascal and C, declarations are EXPLICIT: var i : integer; assocates the TYPE integer with the NAME i. Some languages like Perl and Python have IMPLICIT declarations.

Scope of a declaration The SCOPING RULES of a language determine where in a program a declaration applies. The SCOPE of a declaration is the portion of the program where the declaration applies. An occurrence of a name in a procedure P is LOCAL to P if it is in the scope of a declaration made in P. If the relevant declaration is not in P, we say the reference is NON-LOCAL. During compilation, we use the symbol table to find the right declaration for a given occurrence of a name. The symbol table should return the entry if the name is in scope, or otherwise return nothing.

Environments and states The ENVIRONMENT is a function mapping from names to storage locations. The STATE is a function mapping storage locations to the values held in those locations. Environments map names to l-values. States map l-values to r-values.

Name binding When an environment maps name x to storage location s, we say “x is BOUND to s”. The association is a BINDING. Assignments change the state, but NOT the environment: pi := 3.14 changes the value held in the storage location for pi, but does NOT change the location (the binding) of pi. Bindings do change, however, during execution, as we move from activation to activation.

Run-time system design Static notion Dynamic counterpart definition of a procedure activations of the procedure declarations of a name bindings of the name scope of a declaration lifetime of a binding The run-time system keeps track of a program’s dynamic components. There are many relevant criteria for its design: Can procedures be recursive? What happens to values of local names when control returns from the activations of a procedure? Can a procedure refer to nonlocal names? How are parameters passed when procedures are called? Can procedures be passed as parameters? Can procedures be returned from procedures? Can programs dynamically allocate their own storage? Does storage get deallocated explicitly or implicitly?

Storage allocation

Organization of storage Fixed-size objects can be placed in predefined locations. The heap and the stack need room to grow, however.

Run-time stack and heap The STACK is used to store: Procedure activations. The status of the machine just before calling a procedure, so that the status can be restored when the called procedure returns. The HEAP stores data allocated under program control (e.g. by malloc() in C).

Activation records Any information needed for a single activation of a procedure is stored in the ACTIVATION RECORD (sometimes called the STACK FRAME). Today, we’ll assume the stack grows DOWNWARD, as on, e.g., the Intel architecture. The activation record gets pushed for each procedure call and popped for each procedure return. (the access link is the “dynamic link” in Sebesta’s terminology)

Compile-time layout of locals Usually the BYTE is the smallest addressable unit of storage. We lay out locals in the order they are declared. Each local has an OFFSET from the beginning of the activation record (or local data area of the record). Some data objects require alignment with machine words. Any resulting wasted space is called PADDING. Type Size (typical) Alignment (typical) char 8 8 short 16 16 int 32 32 float 32 32 double 64 32

Storage allocation strategies

Static allocation Statically allocated names are bound to storage at compile time. Storage bindings of statically allocated names never change, so even if a name is local to a procedure, its name is always bound to the same storage. The compiler uses the type of a name (retrieved from the symbol table) to determine storage size required. The required number of bytes (possibly aligned) is set aside for the name. The address of the storage is fixed at compile time.

Static allocation Limitations: The size required must be known at compile time. Recursive procedures cannot be implemented as all locals are statically allocated. No data structure can be created dynamicaly as all data is static.

Stack-dynamic allocation Storage is organized as a stack. Activation records are pushed and popped. Locals and parameters are contained in the activation records for the call. This means locals are bound to fresh storage on every call. If we have a stack growing downwards, we just need a stack_top pointer. To allocate a new activation record, we just increase stack_top. To deallocate an existing activation record, we just decrease stack_top.

Position in Activation Tree Activation Records on the Stack

Address generation in stack allocation The position of the activation record on the stack cannot be determined statically. Therefore the compiler must generate addresses RELATIVE to the activation record. If we have a downward-growing stack and a stack_top pointer, we generate addresses of the form stack_top + offset

Calling sequences The CALLING SEQUENCE for a procedure allocates an activation record and fills its fields in with appropriate values. The RETURN SEQUENCE restores the machine state to allow execution of the calling procedure to continue. Some of the calling sequence code is part of the calling procedure, and some is part of the called procedure. What goes where depends on the language and machine architecture.

Sample calling sequence Caller evaluates the actual parameters and places them into the activation record of the callee. Caller stores a return address and old value for stack_top in the callee’s activation record. Caller increments stack_top to the beginning of the temporaries and locals for the callee. Caller branches to the code for the callee. Callee saves all needed register values and status. Callee initializes its locals and begins execution.

Sample return sequence Callee places the return value at the correct location in the activation record (next to caller’s activation record) Callee uses status information previously saved to restore stack_top and the other registers. Callee branches to the return address previously requested by the caller. [Optional] Caller copies the return value into its own activation record and uses it to evaluate an expression.

Variable-length data In some languages, array size can depend on a value passed to the procedure as a parameter. This and any other variable-sized data can still be allocated on the stack, but BELOW the callee’s activation record. In the activation record itself, we simply store POINTERS to the to-be-allocated data.

Example of variable- length data All variable-length data is pointed to from the local data area.

Dangling pointers Stack dynamic allocation means that pointers might end up DANGLING. Every novice C programmer makes this mistake at least once: int main( void ) { int *dangle( void ) { int *p; int i = 23; p = dangle(); return &i; } }

Heap allocation Some languages do not have tree-structured allocations. In these cases, activations have to be allocated on the heap. This allows strange situations, like callee activations that live longer than their callers’ activations. This is not common.