Lecture24 26 Runtime Environment 2
Lecture24 26 Runtime Environment 2
Compiler Design
Lecture 23 - 25
Ahmed Ezzat
Runtime Environment
1 Ahmed Ezzat
Outline
⚫ Runtime Environment
--------- page 42
⚫ Implementing Objects
⚫ Implementing Dynamic Type Checking --------- page 84
⚫ Memory Management:
❑ Stack allocation
❑ Heap management: portion of the store used for data
that lives indefinitely
❑ Garbage collection: process of finding spaces within
the heap that are no longer used and reallocate them
to other data items
⚫ Memory Management:
Code
Stack Allocation: Static Data
❑ For managing procedure calls and
interrupt handling Heap
❑ Stack grows (stack frame) with each call
and shrinks with each procedure
Free Memory
return/terminate
❑ Each procedure call pushes an
activation record (stack frame) into Stack
the stack. Each return from a procedure
removes record (stack frame) from the
stack
9 CMPE 152 Ahmed Ezzat
Runtime Environment Overview
⚫ Code Generation:
❑ Calling sequence
– Code that allocates activation record / stack frame
– Code for entering information in it
❑ Return sequence
– Code to restore the state of the machine
⚫ Code Generation:
❑ Calling sequence
– Code that allocates activation record / stack frame
– Code for entering information in it
❑ Return sequence
– Code to restore the state of the machine
– …
– Heap (dynamic) Stack
⚫ C-style arrays:
int a[3][2];
a[0]
a[1]
a[2]
a[0]
a[2]
40 2 a[2][0] a[2][1]
CMPE 152 Ahmed Ezzat
Encoding Functions
⚫ Activation Tree:
❑ Model procedure activations
❑ The main() is the root
❑ Children of the same parent are executed in
sequence from left to right
❑ Sequence of procedure calls → preorder (Root →
left subtree → right subtree) traversal of activation
tree
❑ Sequence of procedure returns → postorder (left
subtree → right subtree → Root) traversal of
activation tree
45 CMPE 152 Ahmed Ezzat
Activation Records
⚫ Activation Records:
❑ What is pushed into the
stack for each procedure
activation / call
❑ Contents vary with the
language being implemented
int main() {
Fib(3);
}
int Fib(int n) {
if (n <= 1) return n;
return Fib(n – 1) + Fib(n – 2);
}
int main() {
Fib(3); main
}
int Fib(int n) {
if (n <= 1) return n;
return Fib(n – 1) + Fib(n – 2);
}
Fib
int main() {
Fib(3); n = 3
}
int Fib(int n) {
if (n <= 1) Fib Fib
return n; n = 2 n = 1
return Fib(n – 1) +
Fib(n – 2);
}
Fib Fib
n = 1 n = 0
function CreateCounter() {
var counter = 0;
return function() {
counter ++;
return counter;
}
}
function MyFunction() {
f = CreateCounter(); # returns a function address
print(f()); # print the counter value
print(f());
}
* On return from f(), the activation record that holds the counter value is
gone but with the above code we can access the counter variable across
55 function calls!
Closures
function CreateCounter() {
var counter = 0;
return function() {
counter ++; return counter;
}
}
function MyFunction() {
f = CreateCounter();
print(f());
print(f());
}
>
56 Ahmed Ezzat
MyFunction
Closures
function CreateCounter() {
var counter = 0;
return function() {
counter ++; return counter;
}
}
function MyFunction() {
f = CreateCounter();
print(f());
print(f());
}
>
57 Ahmed Ezzat
MyFunction
Closures
>
58 Ahmed Ezzat
MyFunction
Closures f = <fn>
>
59 Ahmed Ezzat
MyFunction
Closures f = <fn>
> 1
2
60 Ahmed Ezzat
Control and Access Links
struct MyStruct {
int x;
char y;
double z;
};
class Base {
int x;
int y;
};
class Derived extends Base {
4 Bytes 4 Bytes int z;
};
class Base {
int x;
int y;
};
class Derived extends Base {
4 Bytes 4 Bytes int z;
};
class Base {
int x;
int y;
};
class Derived extends Base {
4 Bytes 4 Bytes int z;
};
4 Bytes 4 Bytes
Base ms = new Derived;4 Bytes
ms.x = 137; store 137 0 bytes after ms
ms.y = 42; store 42 4 bytes after ms
78
this is tricky
class MyClass {
int x;
void myFunction(int arg) {
this.x = arg; # x belongs to MyClass
}
}
class MyClass {
int x;
}
# myFunction() belongs to MyClass but is implemented outside the class declaration
void MyClass::myFunction(MyClass this, int arg){
this.x = arg; # x belongs to MyClass
}
class MyClass {
int x;
}
# myFunction() belongs to MyClass but is implemented outside the class declaration
void MyClass::myFunction(MyClass this, int arg){
this.x = arg;
}
class MyClass {
int x;
}
void MyClass::myFunction(MyClass this, int arg){
this.x = arg;
}
●
This previous idea has several serious problems.
●
What are they?
● It's slow.
● Number of checks is O(C), where C is the number of
classes the dispatch might refer to.
● Gets slower the more classes there are.
● It's infeasible in most languages:
●
What if we link across multiple source files? What if
● we support dynamic class loading?
87 CMPE 152 Ahmed Ezzat
An Observation
Code for
Base.sayHi
Code for
Derived.sayHi
91 Ahmed Ezzat
Virtual Function Tables
● Advantages:
● Time to determine function to call is O(1)
(which is good!)
● What are the disadvantages?
● Object sizes are larger:
Each object needs to have space for O(M) pointers.
● Object creation is slower:
Each new object needs to have O(M) pointers set,
where M is the number of member functions.
95 CMPE 152 Ahmed Ezzat
A Common Optimization
Class descriptor
Vtable
Class descriptor
Vtable
B C
D E
B C
D E
B C
D E
B C
D E
B C
Simple Dynamic Type
D E
Checking
● Have each object's vtable store a pointer to its base
(not parent) class. Base class for object E is class A
● To check if an object is convertible to type S at
runtime, follow the parent pointers embedded in the
object's vtable upward until we find S or reach a type
with no parent (base class).
●
Runtime is O(d), where d is the depth of the class in
the hierarchy.
● Can we make this faster?
110 CMPE 152 Ahmed Ezzat
A
decreasing B C
A Marvelous Idea D E
B C
A Marvelous Idea D E F G
B C
A Marvelous Idea D E F G
Prime = 1, key =1
Prime = 5, key = 5x2 Prime = 7, key = 7x2 Prime = 11, key = 11x3 Prime = 13, key = 13x3
B C
A Marvelous Idea D E F G
C myObject = /* … */
if (myObject instanceof A) {
/* … */
}
116 CMPE 152 Ahmed Ezzat
A Marvelous Idea
Object F is an instance of C
Object G is an instance of C