160 likes | 377 Views
The Runtime Environment. After the analysis phases are complete, the compiler must generate executable code. The generated code must include routines for managing the changing data as the program executes. Depending on the language, the runtime environment may be:. fully static.
E N D
The Runtime Environment After the analysis phases are complete, the compiler must generate executable code. The generated code must include routines for managing the changing data as the program executes. Depending on the language, the runtime environment may be: fully static stack-based dynamic The type of environment determines whether we need to use a stack, a heap, or both.
code for function 1 code for function 2 . . . code for function n global / static area stack free space heap Runtime Storage Structure entry address entry address entry address
Procedure Activation Record activation record : functionX par1 (type) : <value> ... parN (type): <value> start code ptr: <ptr> current ptr: <ptr> return address: <ptr> var1 (type) : <value> ... varN (type): <value> Each time the flow of control enters a function or procedure, we update its procedure activation record. This maintains the values of the function arguments and all local variables defined inside the function, and pointers to the start of the code segment, the current location in the code segment, and the segment of code to which we return on exit.
Fully Static Environments A fully static environment (FORTRAN77) has no recursively-called procedures no pointers no dynamic memory allocation This means that only one copy of each procedure activation record can be active at any one time. Therefore, we store only one copy, and we can allocate storage at compile time. Each time we enter a procedure, we simply update the fields of its activation record. Fully static environments do not need a stack.
global area i (int) : activation record : main start code ptr: current ptr: return address: k (int) : activation record : f1 j (int) : start code ptr: current ptr: return address: k (int) : Static example 1 int i = 10; 2 int f1(int j) { 3 int k; 4 k = 3 * j; 5 if (k<i) print(i); 6 else print(j); 7 } 8 main() { 9 int k = 1; 10 while (k<5) { 11 f1(k); 12 k = k+1; 13 } 14 }
Stack-based Environment Stack-based languages do allow procedures to be called recursively. Typically, they also allow dynamic memory allocation and pointers to data locations. Since procedures can be called recursively, we may need to hold a number of different records for the same function, representing each invocation. Activation records will be created as required and placed on the stack. Each record will maintain a pointer to the record that activated it, and on completion, the current record will be deleted from the stack, and control passed back to the calling record. Most high-level imperative languages are stack-based - e.g. C, Pascal.
on 1st entry to gcd global area x (int): 15 y (int): 10 initial environment global area x (int): y (int): activation record: main start ptr: 6 current ptr: 8 activation record: main start ptr: 6 current ptr: fp activation record: gcd u (int): 15 v (int): 10 start ptr: 2 current ptr: 2 return ptr: return address: 8 fp sp sp Stack-based Example 1 int x, y; 2 int gcd(int u, int v) { 3 if (v == 0) return u; 4 else return gcd(v, u % v); 5 } 6 main() { 7 scanf("%d %d", &x, &y); 8 printf("%d\n", gcd(x, y)); 9 }
about to exit main on 3rd entry to gcd global area x (int): 15 y (int): 10 global area x (int): 15 y (int): 10 activation record: main start ptr: 6 current ptr: 9 activation record: main start ptr: 6 current ptr: 8 fp sp activation record: gcd u (int): 15 v (int): 10 start ptr: 2 current ptr: 4 return ptr: return address: 8 activation record: gcd u (int): 10 v (int): 5 start ptr: 2 current ptr: 4 return ptr: return address: 4 activation record: gcd u (int): 5 v (int): 0 start ptr: 2 current ptr: 2 return ptr: return address: 4 fp sp
Dangling References int *dangle() { int x = 3; return &x; } int inc(int y) { int z; z = y + 1; return z; } main() { int *w, t; w = dangle(); printf("w = %d\n", *w); t = inc(10); printf("w = %d\n", *w); } % a.out w = 3 w = 11 %
Dynamic Environments Returning the address of a local variable is defined to be a logical error in languages like C. In a dynamic environment there is no such restriction - all variables and activation records must be maintained for as long as there are references to them. It is also possible to return pointers to local functions. Dynamic environments must deallocate space when procedures and variables can no longer be reached - garbage collection . It is normal to use a heap to maintain such records. Two functions are required: allocate - returns the address of a memory block of the appropriate size free - marks a block as being free for re-use
Heap Management Stack-based languages like C also require a heap to maintain pointer allocation and dynamically allocated memory. C C++ Java new new allocate malloc free free delete • The two main challenges in heap management are: stopping the heap becoming fragmented, by combining successive freed blocks into one ensuring that free is only ever applied to the start of a block of the required size
a simple heap management scheme circular linked list of allocated memory blocks each block records its used size, the size of the free space after it, and points to the next block the block at the top of the heap points to a block with some free space after it to allocate a block find a block with enough free space after it jump to end of that block's used space insert the new block into the heap compute the reduced free space set the previous block's free space to 0 update the list to free a block move to top of the heap step through list of blocks until required address add the block's free size and used size to the free size of its previous block
0 header last next 5 next us:15 fs:0 used 20 next us:10 fs:0 next us:10 fs:0 used 30 next us:10 fs:20 next us:10 fs:0 used 40 free 60 Example allocation sequence allocate a block of size 15 0 header last next 5 next us:15 fs:0 used 20 used 30 used 40 next us:15 fs:5 used 55 free 60
next us:10 fs:0 Exampe sequence (cont) free block (size 10) at 35 - fails free block (size 10) at 20 free block (size 10) at 30 0 0 header header last next last next 5 5 next us:15 fs:10 next us:15 fs:20 used used 20 20 free free 30 30 used 40 40 next us:15 fs:5 next us:15 fs:5 used used 55 55 free free 60 60