Download presentation
Presentation is loading. Please wait.
Published byBridget Holmes Modified over 9 years ago
1
Chap 9 Run-time Storage Consider the C program : static int x; int abc(int y) { float z; static int w; abc(z); malloc(20) } main { abc(3) } placement of 1. static var x 2. constant 3 recursive 3. parameters y calls 4. return value 5. local variable z 6. dynamic allocation malloc() 7. static local variable w
2
Chap 9 Run-time Storage - evolution : 1. static allocation 2. stack 3. heap - Assume, we allocate/free one data area at a time. Each data area may contain one or more data objects.
3
Chap 9 Run-time Storage § 9.1 Static Allocation - In FORTRAN and assembly languages. - easy, originally - In order to save space, use overlay. e.g. equivalence classes in FORTRAN. potentially dangerous - static storage is for global variables (fixed size) literals own (in Algol 60) static and extern (in C) - Conceptually, bind objects to absolute addresses at compile time. - For separately compiled programs, binding can be delayed until link time.
4
Chap 9 Run-time Storage § 9.2 Stack Allocation - For recursive procedures, we need a run-time stack. - The stack contains several activation records(ARs). - Each AR contains the local variables of a procedure. push AR when a procedure is called. pop AR when a procedure returns. Ex. A B C B C C B C B A
5
Chap 9 Run-time Storage Contents of AR: 1. parameters/return values 2. local variables 3. some pointers Ex. proc P(a : integer) is b : real; c : array (1..10) of real; begin b := c(a) * 2.51; end c b a some pointers 28 8 6 5 0 - At compile time, we know the offset of each data object relative to the beginning of the AR. - The offset information is stored in the symbol table.
6
Chap 9 Run-time Storage - Literals are stored in a static literal pool. - How about dynamic arrays? procedure P(a : integer) is b : array[1..a] of integer; begin end We do not know the size of the array at compile time. Solution : Each array type is represented by a dope vector(containing size + bounds). Each dynamic array variable is represented by a pointer. Both and are uninitialized and on the stack. pointer to b dope vector a some pointers AR:
7
Chap 9 Run-time Storage At run time, when P is called, 1. initialize the dope vector; 2. allocate space just on top of stack; 3. initialize the pointer. P(9) ( b array ) ptr 9 1.. 9 a (=9) some pointers :::::: ::::::.............................. - The compiler needs to generate code for 1, 2, and 3. - The dynamic array is accessed indirectly through the pointer. stack:
8
Chap 9 Run-time Storage - How about ¢ static ¢ variables in C? Ex. int a; void xyz( ) { static int b = 0; b = b + 1; printf( b ); } main() { xyz( ); xyz( ); } (what values are printed?) Values of static variables are preserved across calls. - Solution: Static variables are treated like global variables.
9
Chap 9 Run-time Storage - Subroutine calls are last-call-first-return. So we can use a stack. - Other features such as coroutines, interacting processes, shared variables are much more difficult.
10
Chap 9 Run-time Storage § 9.2.1 Displays - How to address the AR? Ex. p q r q p s r :rspqrqp:rspqrqp Need pointers to the ARs. One register per AR not feasible.
11
Chap 9 Run-time Storage - Consider proc A proc B proc C proc D var x x ABCBCDABCBCD Note. At any instant, only the most recent ARs of the current procedure and the enclosing proc are needed. Consider proc D above - We don ’ t need pointers to B or old C. DCBCBADCBCBA D[3] D[2] D[1]
12
Chap 9 Run-time Storage This is called static nesting. The stack can grow very big but the static nesting is quite shallow for ordinary programs. We can allocate one register for each nesting level. This set of registers are called displays (D[1], D[2], ). See the previous slide. The display can be stored in memory, rather than registers.
13
Chap 9 Run-time Storage Upon procedure call/return, we need to adjust the display registers. How? 1st approach: Save the entire display in the AR when a procedure is called. Restore display upon return. – too much. 2nd approach: Save only the display register for the level of the called procedure. Upon return, restore that register. Who saves and restores? Caller saves display register in callee ’ s AR. Callee restores it.,
14
Chap 9 Run-time Storage Ex. proc A proc B proc C proc D ABCDBCABCDBC Show display.
15
Chap 9 Run-time Storage § 9.2.2 block-level vs. procedural-level AR - In Ada, Algol 60, C, and Ada/CS, we may declare variables within blocks as well as within procedures. Procedure A is a : integer; begin begin b : integer; end begin c : integer; end end - We may create a new AR for each block. (-) more displays (-) run-time overhead - Or we may use procedural-level ARs. We may even overlay variables.
16
Chap 9 Run-time Storage Ex. procedure XYZ ( A, B : integer) is C : integer begin begin D, E : integer; begin F : integer; end end begin G, H : integer; end end F E D C B A G H some pointers AR:
17
Chap 9 Run-time Storage § 9.3 Heap Allocation How to handle dynamic allocation? p = malloc( ) in C new(p) in Pascal The dynamically allocated storage does not possess the last-allocated, first-freed property. So we cannot use a stack. We have to use the heap. Allocation: 1. explicit allocation allocate in PL/1 new(p) in Pascal and Ada 2. implicit allocation cons in LISP ‘ abc ’ ‘ def ‘ in SNOBOL 3. no allocation (in the language itself) malloc(20) in C
18
Chap 9 Run-time Storage Ex. dangling pointer problem var p, q : real; new( p ); q := p; dispose( p ); q := 1.0;
19
Chap 9 Run-time Storage The real problem: How to manage the returned storage? 1. No deallocation - good if most heap objects stay useful. - good if there is a really big virtual memory. - user could maintain a private free-list. 2. explicit deallocation free( ) in C dispose( ) in Pascal - Users free space explicitly; heap manager keeps track of free space. - dangling pointer problem Should the implementation check dangling pointers? 3. implicit deallocation(garbage collection) - The useless space is automatically recovered.
20
Chap 9 Run-time Storage - Three approaches to garbage collection: 1. single reference At most one pointer to any heap object. e.g. strings. Not good for complex linked structures. 2. reference count For each object, keep a count of the number of pointers to the object. Free the object when its count is 0. Ref count object 3. mark-sweep-compact - Find all global pointers (including those in stack). - Mark all heap objects reachable from the global pointers. - Free all unmarked heap objects. - Compact remaining objects. cycles?
21
Chap 9 Run-time Storage global vars constants stackheap garbage ::::....
22
Chap 9 Run-time Storage Compiler must generate enough information concerning where global pointers are. Run-time routines perform marking, sweeping, and compaction. Garbage collection is activated only when heap space is exhausted, not whenever references are created or destroyed. Easy for uniform languages, e.g. LISP. Difficult for complex languages,e.g.Ada. Compaction is used to avoid fragmentation.
23
Chap 9 Run-time Storage garbage collection for single-reference objects (e.g. Ada/CS strings) hand-shaking convention pointers objects Sweep through heap objects. Keep the heap object if 1. it points to an AR in use. 2. the corresponding pointer in AR points back to the object. Slight chance for uncollected garbage
24
Chap 9 Run-time Storage Uninitialized pointers may be mistaken as a valid pointer. - initialize all pointers when they are created or - check validity when referencing Managing heap space - first-fit - best-fit - circular-first-fit boundary tag: for combining adajacent free chunks. status Usually, there are only a few different sizes of allocated chunks. Use different heaps for differently-sized chunks(bit map).
25
Chap 9 Run-time Storage § 9.4 Program Layout How to arrange object code in main memory? heap stack static data literals code static data literals code(read-only) reserved highest addr lowest addr library & separately compiled modules
26
Chap 9 Run-time Storage There is a danger of collision of stack and heap. So we need to check collision whenever stack and heap storage is allocated. VAX and 8086 support segmented memory. We can use 1 segment for code (read only) 1 segment for stack 1 segment for heap etc.
27
Chap 9 Run-time Storage operand stack Ex. a + b * c + d / e push a push b push c mul add push d push e div add operand stack
28
Chap 9 Run-time Storage operand stack Some stack-oriented architectures use an operand stack, rather than registers, to evaluate expressions. 1. Can we use the run-time stack as operand stack? No. Because we might invoke functions when evaluating expressions. 2. Allocate operand stack to a separate segment or to the reserved locations. Sometimes, it is possible to determine the max depth of the operand stack.
29
Chap 9 Run-time Storage In load-and-go compilers, there is no explicit linking. How can we call a library routine? 1. Make the library routine self-relocating. All addressing within the library routines is base-relative or PC-relative. 2. Use transfer vector for cross-module reference. There is one entry for each library routine in the transfer vector. All calls to library routines are made indirectly through the transfer vector. (in literal pool) log routine........................ log addr........................ call log main program transfer vector
30
Chap 9 Run-time Storage 3. Load the whole set of library routines into fixed location, before compilation! Applicable when the set of library routines is small. The compiler can maintain a table of entry-point addresses. No indirection. Due to the lack of relocation in load- and-go compilers, program layout is different. static data literals heap stack code library modules reserved highest addr lowest addr
31
Chap 9 Run-time Storage § 9.5 static and dynamic chains Ex. proc A var X; proc B var Y; proc C begin X + Y end begin call C end proc D begin call B end begin call D end ADBCADBC CBDACBDA dynamic chain static chain AP
32
Chap 9 Run-time Storage A D B C For returning from a procedure, we need a chain of call sequence. (dynamic chain) For referencing variables, we need a chain of scope nesting. (static chain) Ex. Show how to reference X and Y in C. We also need an AP(activation pointer) that point to the topmost AR.
33
Chap 9 Run-time Storage If we cannot use display registers, then we need to maintain the static chain. static chain » display To reference variables through static chain is slower than through display. But the performance is acceptable because 80% : local (AP) or global data (fixed) 17% : immediately enclosing scope
34
Chap 9 Run-time Storage § 9.6 formal procedures A proc may be passed as a parameter and is later activated. Ex. proc E( ); proc A ( F: proc ) var x : integer; begin x := 1; F( ); end proc B( ); var x : integer proc D( ) begin write(x); end begin x := 2; A( D ); end begin B( ); end what is printed?
35
Chap 9 Run-time Storage EBADEBAD D A B E x=1 x=2 dynamic chain static chain If we follow dynamic chain to find x, 1 is printed. This is called dynamic binding. In dynamic binding, we use the environment where D is activated. If we follow static chain to find x, 2 is printed. This is called static binding. In static binding, we use the environment where the instance of D is created. :............. : :
36
Chap 9 Run-time Storage - Only early LISP implementations use dynamic binding. Modern descendants of LISP use static binding. - Algol 60 and its descendants all use static binding.
37
Chap 9 Run-time Storage How to implement static binding? When A passes B to C, we need to pass two things : 1. a pointer to B ’ s code 2. a pointer to A ’ s AR closure C B A
38
Chap 9 Run-time Storage For the previous example E E BE B A E stack B B E E A x=2 x=1 :....... : : : E B A D D A B E This pointer is obtained from the closure of D.
39
Chap 9 Run-time Storage goto out of a formal procedure proc E( ) proc A( F:proc ) begin F( ); end proc B( ) proc D( ) begin goto L; which L? end begin A(D); L:..... end begin B( ) end E B A D At run time, 1. Use static chain to determine B ’ s AR. 2. Follow dynamic chain to pop all ARs above B ’ s AR. D A B E
40
Chap 9 Run-time Storage A more complicated example : proc E proc A( F : proc ) begin if then B(F) else F( ) end proc B ( F: proc ) proc D( ) begin end begin if then A(D) else F( ) end begin B( ) end E B A(D) B(D) D DBABEDBABE NB!
41
Chap 9 Run-time Storage § 9.6.2 Use display to implement formal procedure closure = code addr + display registers Need a pointer to the caller ’ s AR. – restore_AR When proc A calls formal proc B, 1. Save restore_AR in A ’ s AR. 2. Save display registers in A ’ s AR. 3. restore_AR := pointer to A ’ s AR 4. Set display registers from B ’ s closure. 5. Jump to B ’ s addr. When formal proc. B returns, 1. Use restore_AR to restore all display registers from A ’ s AR. 2. Restore restore_AR from A ’ s AR.
42
Chap 9 Run-time Storage B ¢ s AR A ¢ s AR old display registers old restore_AR :::: (new) restore_AR A B run-time stack
43
Chap 9 Run-time Storage No extra cost for normal procedure calls. difficult to handle non-local goto ’ s. However, non-local goto ’ s are rare.
44
Chap 9 Run-time Storage § 9.6.3 perspective Formal procedures are hard to understand. formal procedures in C C is very flat. so closure = addr of code (in C) Ada allows no formal procedures al all. Formal procedures are useful in certain situations.
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.