compiler 2011-8-re1

35
1 Compiler Construction Compiler Construction Runtime Environment Runtime Environment

Upload: ganesh-amirineni

Post on 15-May-2015

438 views

Category:

Education


0 download

DESCRIPTION

storage allocation stratagies and storage organization

TRANSCRIPT

Page 1: Compiler 2011-8-re1

1

Compiler ConstructionCompiler Construction

Runtime Environment Runtime Environment

Page 2: Compiler 2011-8-re1

2

Run-Time Environments (Chapter 7)

Page 3: Compiler 2011-8-re1

3

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 sourc

e 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.

Page 4: Compiler 2011-8-re1

4

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.”

Page 5: Compiler 2011-8-re1

5

Example program

program sort( input, output );var a: array [ 0..10 ] of integer;procedure readarray;

var i: integer;beginfor i := 1 to 9 do read( a[i] )end;

function partition( y, z: integer ) : integer;var i, j, x, v: integer;begin …end;

procedure quicksort( m, n: integer );var i: integer;begin

if ( n > m ) then begin

i := partition( m, n );

quicksort(m,i-1);

quicksort(i+1,n)

endend;

begina[0] := -9999; a[10] := 9999;readarray;quicksort(1,9);

end.

Page 6: Compiler 2011-8-re1

6

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.

Page 7: Compiler 2011-8-re1

7

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.

Page 8: Compiler 2011-8-re1

8

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.

Page 9: Compiler 2011-8-re1

9

Activation treesExecution begins…enter readarrayleave readarrayenter 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.

Page 10: Compiler 2011-8-re1

10

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.

Page 11: Compiler 2011-8-re1

11

Example control stack

This partial activation

tree corresponds to

control stack (growing

downward)

sq(1,9)q(1,3)q(2,3)

Page 12: Compiler 2011-8-re1

12

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.

Page 13: Compiler 2011-8-re1

13

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.

Page 14: Compiler 2011-8-re1

14

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.

Page 15: Compiler 2011-8-re1

15

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.

Page 16: Compiler 2011-8-re1

16

Run-time system design

The run-time system keeps track of a program’s dynamic components. There are many relevant criteria for its design:

1. Can procedures be recursive?2. What happens to values of local names when control returns from th

e activations of a procedure?3. Can a procedure refer to nonlocal names?4. How are parameters passed when procedures are called?5. Can procedures be passed as parameters?6. Can procedures be returned from procedures?7. Can programs dynamically allocate their own storage?8. Does storage get deallocated explicitly or implicitly?

Static notion Dynamic counterpartdefinition of a procedure activations of the proceduredeclarations of a name bindings of the namescope of a declaration lifetime of a binding

Page 17: Compiler 2011-8-re1

17

Storage allocation

Page 18: Compiler 2011-8-re1

18

Organization of storage

Fixed-size objects can be placed in predefined locations.

The heap and the stack need room to grow, however.

Page 19: Compiler 2011-8-re1

19

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).

Page 20: Compiler 2011-8-re1

20

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 “dynamiclink” in Sebesta’s terminology)

Page 21: Compiler 2011-8-re1

21

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 8short 16 16int 32 32float 32 32double 64 32

Page 22: Compiler 2011-8-re1

22

Storage allocation strategies

Page 23: Compiler 2011-8-re1

23

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.

Page 24: Compiler 2011-8-re1

24

Static allocation

Limitations:− The size required must be known at compile time.− Recursive procedures cannot be implemented as all locals are st

atically allocated.− No data structure can be created dynamicaly as all data is static.

Page 25: Compiler 2011-8-re1

25

Stack-dynamic allocation

Storage is organized as a stack.Activation records are pushed and popped.Locals and parameters are contained in the activation recor

ds 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_t

op.To deallocate an existing activation record, we just decreas

e stack_top.

Page 26: Compiler 2011-8-re1

26

Position inActivation Tree

Activation Recordson the Stack

Page 27: Compiler 2011-8-re1

27

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

Page 28: Compiler 2011-8-re1

28

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.

Page 29: Compiler 2011-8-re1

29

Page 30: Compiler 2011-8-re1

30

Sample calling sequence

1. Caller evaluates the actual parameters and places them into the activation record of the callee.

2. Caller stores a return address and old value for stack_top in the callee’s activation record.

3. Caller increments stack_top to the beginning of the temporaries and locals for the callee.

4. Caller branches to the code for the callee.5. Callee saves all needed register values and status.6. Callee initializes its locals and begins execution.

Page 31: Compiler 2011-8-re1

31

Sample return sequence

1. Callee places the return value at the correct location in the activation record (next to caller’s activation record)

2. Callee uses status information previously saved to restore stack_top and the other registers.

3. Callee branches to the return address previously requested by the caller.

4. [Optional] Caller copies the return value into its own activation record and uses it to evaluate an expression.

Page 32: Compiler 2011-8-re1

32

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.

Page 33: Compiler 2011-8-re1

33

Example of variable- length data

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

Page 34: Compiler 2011-8-re1

34

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;

} }

Page 35: Compiler 2011-8-re1

35

Heap allocation

Some languages do not have tree-structured allocations.In these cases, activations have to be allocated on the hea

p.This allows strange situations, like callee activations that liv

e longer than their callers’ activations.This is not common.