compilation 0368 3133 semester a 2013 14 n.
Download
Skip this Video
Loading SlideShow in 5 Seconds..
Compilation 0368-3133 (Semester A, 2013/14) PowerPoint Presentation
Download Presentation
Compilation 0368-3133 (Semester A, 2013/14)

Loading in 2 Seconds...

play fullscreen
1 / 89

Compilation 0368-3133 (Semester A, 2013/14) - PowerPoint PPT Presentation


  • 48 Views
  • Uploaded on

Compilation 0368-3133 (Semester A, 2013/14). Lecture 14: Compiling Object O riented Programs Noam Rinetzky. Slides credit: Mooly Sagiv. Stages of compilation. Source code (program). Lexical Analysis. Syntax Analysis Parsing. Context Analysis. Code Generation. Target code

loader
I am the owner, or an agent authorized to act on behalf of the owner, of the copyrighted work described.
capcha
Download Presentation

PowerPoint Slideshow about 'Compilation 0368-3133 (Semester A, 2013/14)' - radwan


An Image/Link below is provided (as is) to download presentation

Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.


- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -
Presentation Transcript
compilation 0368 3133 semester a 2013 14

Compilation 0368-3133 (Semester A, 2013/14)

Lecture 14: Compiling Object Oriented Programs

Noam Rinetzky

Slides credit: MoolySagiv

stages of compilation
Stages of compilation

Source code

(program)

LexicalAnalysis

Syntax Analysis

Parsing

ContextAnalysis

CodeGeneration

Target code

(executable)

Portable/Retargetable code generation

Assembly

Text

AST + Sym. Tab.

Token stream

AST

IR

compilation execution
Compilation  Execution

Executing program

Source code

(program)

LexicalAnalysis

Syntax Analysis

Parsing

ContextAnalysis

CodeGeneration

Target code

(executable)

Portable/Retargetable code generation

Assembler

Text

AST + Sym. Tab.

Token stream

AST

IR

Loader

Linker

Runtime System

Symbolic Addr

Object File

Executable File

image

compilation execution1
Compilation  Execution

Executing program

Loading

Source code

(program)

LexicalAnalysis

Syntax Analysis

Parsing

ContextAnalysis

CodeGeneration

Linking

Portable/Retargetable code generation

Text

AST + Sym. Tab.

Token stream

AST

IR

Image

Runtime System

Executable File

“Hello World”

Object File

oo compilation execution
OO: Compilation  Execution

Executing program

Loading

Source code

(program)

LexicalAnalysis

Syntax Analysis

Parsing

ContextAnalysis

CodeGeneration

Linking

Portable/Retargetable code generation

Text

AST + Sym. Tab.

Token stream

AST

IR

Image

Runtime System

Executable File

“Hello World”

Object File

runtime environment
Runtime Environment
  • Mediates between the OS and the programming language
  • Hides details of the machine from the programmer
    • Ranges from simple support functions all the way to a full-fledged virtual machine
  • Handles common tasks
    • Runtime stack (activation records)
    • Memory management
  • Runtime type information
    • Method invocation
    • Type conversions
memory layout
Memory Layout

stack grows down

(towards lower addresses)

stack

Heap

heap grows up

(towards higher addresses)

static data

code

memory layout1
Memory Layout

stack grows down

(towards lower addresses)

stack

Heap

heap grows up

(towards higher addresses)

Runtime type information

static data

code

object oriented programs
Object Oriented Programs
  • Simula, Smalltalk, Modula 3, C++, Java, C#, Python
  • Objects (usually of type called class)
    • Code
    • Data
  • Naturally supports Abstract Data Type implementations
  • Information hiding
  • Evolution & reusability
a simple example
A Simple Example

class Vehicle extends object {

intpos= 10;

void move(int x) {

position = position + x ;

}

}

class Truck extends Vehicle {

void move(int x){

if (x < 55)

pos= pos + x;

}

}

class Car extends Vehicle {

int passengers = 0;

void await(vehicle v){

if (v.pos< pos)

v.move(pos - v.pos);

else

this.move(10);

}

}

class main extends object {

void main() {

Truck t = new Truck();

Car c = new Car();

Vehicle v = c;

c.move(60);

v.move(70);

c.await(t);

}

}

a simple example1

Truck

pos =10

A Simple Example

class Vehicle extends object {

intpos = 10;

void move(int x) {

position = position + x ;

}

}

class Truck extends Vehicle {

void move(int x){

if (x < 55)

pos = pos + x;

}

}

class Car extends Vehicle {

int passengers = 0;

void await(vehicle v){

if (v.pos < pos)

v.move(pos - v.pos);

else

this.move(10);

}

}

class main extends object {

void main() {

Truck t = new Truck();

Car c = new Car();

Vehicle v = c;

c.move(60);

v.move(70);

c.await(t);

}

}

t

a simple example2

Truck

pos=10

A Simple Example

class Vehicle extends object {

intpos = 10;

void move(int x) {

pos = pos + x ;

}

}

class Truck extends Vehicle {

void move(int x){

if (x < 55)

pos = pos + x;

}

}

class Car extends Vehicle {

int passengers = 0;

void await(vehicle v){

if (v.pos < pos)

v.move(pos - v.pos);

else

this.move(10);

}

}

class main extends object {

void main() {

Truck t = new Truck();

Car c = new Car();

Vehicle v = c;

c.move(60);

v.move(70);

c.await(t);

}

}

t

Car

position=10

c

passengers=0

a simple example3

Truck

pos=10

A Simple Example

class Vehicle extends object {

intpos = 10;

void move(int x) {

pos= pos+ x ;

}

}

class Truck extends Vehicle {

void move(int x){

if (x < 55)

pos = pos + x;

}

}

class Car extends Vehicle {

int passengers = 0;

void await(vehicle v){

if (v.pos < pos)

v.move(pos - v.pos);

else

this.move(10);

}

}

class main extends object {

void main() {

Truck t = new Truck();

Car c = new Car();

Vehicle v = c;

c.move(60);

v.move(70);

c.await(t);

}

}

t

Car

position=10

v,c

passengers=0

a simple example4

Truck

pos=10

A Simple Example

class Vehicle extends object {

intpos = 10;

void move(int x) {

pos = pos + x;

}

}

class Truck extends Vehicle {

void move(int x){

if (x < 55)

pos = pos + x;

}

}

class Car extends Vehicle {

int passengers = 0;

void await(vehicle v){

if (v.pos < pos)

v.move(pos - v.pos);

else

this.move(10);

}

}

class main extends object {

void main() {

Truck t = new Truck();

Car c = new Car();

Vehicle v = c;

c.move(60);

v.move(70);

c.await(t);

}

}

t

Car

position=70

v,c

passengers=0

a simple example5

Truck

pos=10

A Simple Example

class Vehicle extends object {

intpos = 10;

void move(int x) {

position = position + x ;

}

}

class Truck extends Vehicle {

void move(int x){

if (x < 55)

pos = pos + x;

}

}

class Car extends Vehicle {

int passengers = 0;

void await(vehicle v){

if (v.pos < pos)

v.move(pos - v.pos);

else

this.move(10);

}

}

class main extends object {

void main() {

Truck t = new Truck();

Car c = new Car();

Vehicle v = c;

c.move(60);

v.move(70);

c.await(t);

}

}

t

Car

position=140

v,c

passengers=0

a simple example6

Truck

pos=10

A Simple Example

class Vehicle extends object {

intpos = 10;

void move(int x) {

position = position + x ;

}

}

class Truck extends Vehicle {

void move(int x){

if (x < 55)

pos = pos + x;

}

}

class Car extends Vehicle {

int passengers = 0;

void await(vehicle v){

if (v.pos < pos)

v.move(pos - v.pos);

else

this.move(10);

}

}

class main extends object {

void main() {

Truck t = new Truck();

Car c = new Car();

Vehicle v = c;

c.move(60);

v.move(70);

c.await(t);

}

}

t

Car

position=140

v,c

passengers=0

a simple example7

Truck

pos=10

A Simple Example

class Vehicle extends object {

intpos = 10;

void move(int x) {

position = position + x ;

}

}

class Truck extends Vehicle {

void move(int x){

if (x < 55)

pos = pos + x;

}

}

class Car extends Vehicle {

int passengers = 0;

void await(vehicle v){

if (v.pos < pos)

v.move(pos - v.pos);

else

this.move(10);

}

}

class main extends object {

void main() {

Truck t = new Truck();

Car c = new Car();

Vehicle v = c;

c.move(60);

v.move(70);

c.await(t);

}

}

t

Car

position=140

v,c

passengers=0

translation into c vehicle
Translation into C (Vehicle)

class Vehicle extends object {

intpos= 10;

void move(int x) {

pos= pos+ x ;

}

}

struct Vehicle {

intpos;

}

translation into c vehicle1
Translation into C (Vehicle)

class Vehicle extends object {

intpos = 10;

void move(int x) {

pos = pos + x ;

}

}

typedefstruct Vehicle {

intpos;

} Ve;

translation into c vehicle2
Translation into C (Vehicle)

class Vehicle extends object {

intpos = 10;

void move(int x) {

pos = pos + x ;

}

}

typedefstruct Vehicle {

intpos;

} Ve;

void NewVe(Ve*this){

thispos= 10;

}

void moveVe(Ve*this, intx){

thispos = thispos+ x;

}

translation into c truck
Translation into C (Truck)

class Truck extends Vehicle {

void move(int x){

if (x < 55)

pos= pos + x;

}

}

typedefstructTruck {

intpos;

} Tr;

void NewTr(Tr *this){

thispos= 10;

}

void moveTr(Ve*this, intx){

if (x<55)

thispos = thispos+ x;

}

na ve translation into c car
Naïve Translation into C (Car)

class Car extends Vehicle {

intpassengers = 0;

void await(vehicle v){

if (v.pos< pos)

v.move(pos – v.pos);

else

this.move(10);

}

}

typedefstructCar{

intpos;

intpassengers;

} Ca;

void NewCa (Ca *this){

thispos = 10;

thispassengers = 0;

}

void awaitCa(Ca *this, Ve *v){

if (vpos < thispos)

moveVe(thispos - vpos)

else

MoveCa(this, 10)

}

na ve translation into c main
Naïve Translation into C (Main)

class main extends object {

void main() {

Truck t = new Truck();

Car c = new Car();

Vehicle v = c;

c.move(60);

v.move(70);

c.await(t);

}

}

void mainMa(){

Tr *t = malloc(sizeof(Tr));

Ca*c = malloc(sizeof(Ca));

Ve*v = (Ve*) c;

moveVe(Ve*) c, 60);

moveVe(v, 70);

awaitCa(c,(Ve*) t);

}

na ve translation into c main1
Naïve Translation into C (Main)

class main extends object {

void main() {

Truck t = new Truck();

Car c = new Car();

Vehicle v = c;

c.move(60);

v.move(70);

c.await(t);

}

}

void mainMa(){

Tr *t = malloc(sizeof(Tr));

Ca*c = malloc(sizeof(Ca));

Ve*v = (Ve*) c;

moveVe(Ve*) c, 60);

moveVe(v, 70);

awaitCa(c,(Ve*) t);

}

void moveCa() ?

na ve translation into c main2
Naïve Translation into C (Main)

class main extends object {

void main() {

Truck t = new Truck();

Car c = new Car();

Vehicle v = c;

c.move(60);

v.move(70);

c.await(t);

}

}

void mainMa(){

Tr *t = malloc(sizeof(Tr));

Ca*c = malloc(sizeof(Ca));

Ve*v = (Ve*) c;

moveVe(Ve*) c, 60);

moveVe(v, 70);

awaitCa(c,(Ve*) t);

}

void moveCa() ?

void moveVe(Ve*this, intx){

thispos = thispos+ x;

}

compiling simple classes

Runtime object

a1

a2

Compile-Time Table

m1A

m2A

Compiling Simple Classes
  • Fields are handled as records
  • Methods have unique names

class A {

field a1;

field a2;

method m1() {…}

method m2(inti) {…}

}

void m2A(classA*this, inti) {

// Body of m2 with any object

// field f as thisf

}

compiling simple classes1

Runtime object

a1

a2

Compile-Time Table

m1A

m2A

Compiling Simple Classes
  • Fields are handled as records
  • Methods have unique names

class A {

field a1;

field a2;

method m1() {…}

method m2(inti) {…}

}

void m2_A(classA*this, inti) {

// Body of m2 with any object

// field f as thisf

}

a.m2(5)

m2A(a,5)

//m2A(&a,5)

features of oo languages
Features of OO languages
  • Inheritance
  • Method overriding
  • Polymorphism
  • Dynamic binding
handling single inheritance
Handling Single Inheritance
  • Simple type extension
  • Type checking module checks consistency
  • Use prefixing to assign fields in a consistent way

class B extends A {

field b1;

method m3() {…}

}

class A {

field a1;

field a2;

method m1() {…}

method m2() {…}

}

method overriding
Method Overriding
  • Redefines functionality
    • More specific
    • Can access additional fields

class B extends A {

field b1;

method m2() {

… b1 …

}

method m3() {…}

}

class A {

field a1;

field a2;

method m1() {…}

method m2() {…}

}

method overriding1
Method Overriding
  • Redefines functionality
    • More specific
    • Can access additional fields

class B extends A {

field a3;

method m2() {

… a3 …

}

method m3() {…}

}

class A {

field a1;

field a2;

method m1() {…}

method m2() {…}

}

m2 is redefined

m2 is declared and defined

method overriding2

Runtime object

a1

a2

Method Overriding
  • Redefines functionality
  • Affects semantic analysis

class B extends A {

field a3;

method m2() {

… a3 …

}

method m3() {…}

}

class A {

field a1;

field a2;

method m1() {…}

method m2() {…}

}

Runtime object

Compile-Time Table

a1

m1A_A

Compile-Time Table

a2

m2A_B

m1A_A

b1

m3B_B

m2A_A

method overriding3

Runtime object

a1

a2

Method Overriding
  • Redefines functionality
  • Affects semantic analysis

class B extends A {

field b1;

method m2() {

… b1 …

}

method m3() {…}

}

class A {

field a1;

field a2;

method m1() {…}

method m2() {…}

}

Runtime object

Compile-Time Table

a1

m1A_A

Compile-Time Table

a2

m2A_B

m1A_A

b1

m3B_B

m2A_A

declared

defined

method overriding4
Method Overriding

Runtime object

a1

a2

a.m2(5) // class(a) = A

b.m2(5) // class(b) = B

m2A_A(a, 5)

m2A_B(b, 5)

class B extends A {

field b1;

method m2() {

… b1 …

}

method m3() {…}

}

class A {

field a1;

field a2;

method m1() {…}

method m2() {…}

}

Runtime object

Compile-Time Table

a1

m1A_A

Compile-Time Table

a2

m2A_B

m1A_A

b1

m3B_B

m2A_A

method overriding5
Method Overriding

Runtime object

a1

a2

class B extends A {

field b1;

method m2() {

… b1 …

}

method m3() {…}

}

class A {

field a1;

field a2;

method m1() {…}

method m2() {…}

}

typedefstruct {

field a1;

field a2;

field b1;

} B;

void m2A_B(B* this) {…}

void m3B_B(B* this) {…}

typedefstruct{

field a1;

field a2;

} A;

void m1A_A(A* this){…}

void m2A_A(A* this){…}

Runtime object

Compile-Time Table

a1

m1A_A

Compile-Time Table

a2

m2A_B

m1A_A

b1

m3B_B

m2A_A

method overriding6
Method Overriding

Runtime object

a1

a2

a.m2(5) // class(a) = A

b.m2(5) // class(b) = B

m2A_A(a, 5)

m2A_B(b, 5)

typedefstruct {

field a1;

field a2;

field b1;

} B;

void m2A_B(B* this) {…}

void m3B_B(B* this) {…}

typedefstruct{

field a1;

field a2;

} A;

void m1A_A(A* this){…}

void m2A_A(A* this){…}

Runtime object

Compile-Time Table

a1

m1A_A

Compile-Time Table

a2

m2A_B

m1A_A

b1

m3B_B

m2A_A

abstract methods
Abstract Methods
  • Declared separately
    • Defined in child classes
    • E.g., Java abstract classes
      • Abstract classes cannot be instantiated
  • Handled similarly
  • Textbook uses “virtual” for abstract
handling polymorphism
Handling Polymorphism
  • When a class B extends a class A
    • variable of type pointer to A may actually refer to object of type B
  • Upcasting from a subclass to a superclass
  • Prefixing guarantees validity

class B *b = …;

class A *a = b ;

classA*a = convert_ptr_to_B_to_ptr_A(b) ;

Pointer to B

a1

A

Pointer to A inside B (also)

a2

B

b1

dynamic binding
Dynamic Binding
  • An object (“pointer”) o declared to be of class A can actually be (“refer”) to a class B
  • What does ‘o.m()’ mean?
    • Static binding
    • Dynamic binding
  • Depends on the programming language rules
  • How to implement dynamic binding?
    • The invoked function is not known at compile time
    • Need to operate on data of the B and A in consistent way
conceptual impl of dynamic binding

Runtime object

a1

a2

Conceptual Impl. of Dynamic Binding

class B extends A {

field b1;

method m2() {

… a3 …

}

method m3() {…}

}

class A {

field a1;

field a2;

method m1() {…}

method m2() {…}

}

typedefstruct {

field a1;

field a2;

field b1;

} B;

void m2A_B(B* this) {…}

void m3B_B(B* this) {…}

typedefstruct{

field a1;

field a2;

} A;

void m1A_A(A* this){…}

void m2A_A(A* this){…}

Runtime object

Compile-Time Table

a1

m1A_A

Compile-Time Table

a2

m2A_B

m1A_A

b1

m3B_B

m2A_A

conceptual impl of dynamic binding1

Runtime object

a1

a2

Conceptual Impl. of Dynamic Binding

switch(dynamic_type(p)) {

case Dynamic_class_A: m2_A_A(p, 3);

case Dynamic_class_B:m2_A_B(convert_ptr_to_A_to_ptr_B(p), 3);

}

typedefstruct {

field a1;

field a2;

field b1;

} B;

void m2A_B(B* this) {…}

void m3B_B(B* this) {…}

typedefstruct{

field a1;

field a2;

} A;

void m1A_A(A* this){…}

void m2A_A(A* this){…}

Runtime object

Compile-Time Table

a1

m1A_A

Compile-Time Table

a2

m2A_B

m1A_A

b1

m3B_B

m2A_A

conceptual impl of dynamic binding2

Runtime object

a1

a2

Conceptual Impl. of Dynamic Binding

?

switch(dynamic_type(p)) {

case Dynamic_class_A: m2_A_A(p, 3);

case Dynamic_class_B:m2_A_B(convert_ptr_to_A_to_ptr_B(p), 3);

}

typedefstruct {

field a1;

field a2;

field b1;

} B;

void m2A_B(B* this) {…}

void m3B_B(B* this) {…}

typedefstruct{

field a1;

field a2;

} A;

void m1A_A(A* this){…}

void m2A_A(A* this){…}

Runtime object

Compile-Time Table

a1

m1A_A

Compile-Time Table

a2

m2A_B

m1A_A

b1

m3B_B

m2A_A

more efficient implementation
More efficient implementation
  • Apply pointer conversion in sublasses
    • Use dispatch table to invoke functions
    • Similar to table implementation of case

void m2A_B(classA*this_A) {Class_B *this = convert_ptr_to_A_ptr_to_A_B(this_A); …}

more efficient implementation1
More efficient implementation

typedefstruct{

field a1;

field a2;

} A;

void m1A_A(A* this){…}

void m2A_A(A* this, int x){…}

typedefstruct {

field a1;

field a2;

field b1;

} B;

void m2A_B(A* thisA, int x){

Class_B*this =

convert_ptr_to_A_to_ptr_to_B(thisA);

}

void m3B_B(B* this){…}

more efficient implementation2
More efficient implementation

typedefstruct{

field a1;

field a2;

} A;

void m1A_A(A* this){…}

void m2A_A(A* this, int x){…}

typedefstruct {

field a1;

field a2;

field b1;

} B;

void m2A_B(A* thisA, int x){

Class_B*this =

convert_ptr_to_A_to_ptr_to_B(thisA);

}

void m3B_B(B* this){…}

classA *p;

(Runtime) Dispatch Table

Runtime object

p

m1A_A

vtable

m2A_A

a1

a2

more efficient implementation3
More efficient implementation

typedefstruct{

field a1;

field a2;

} A;

void m1A_A(A* this){…}

void m2A_A(A* this, int x){…}

typedefstruct {

field a1;

field a2;

field b1;

} B;

void m2A_B(A* thisA, int x){

Class_B*this =

convert_ptr_to_A_to_ptr_to_B(thisA);

}

void m3B_B(B* this){…}

classA *p;

(Runtime) Dispatch Table

Runtime object

Code

p

m1A

m1A_A

vtable

m2A

m2A_A

a1

a2

more efficient implementation4
More efficient implementation

typedefstruct{

field a1;

field a2;

} A;

void m1A_A(A* this){…}

void m2A_A(A* this, int x){…}

typedefstruct {

field a1;

field a2;

field b1;

} B;

void m2A_B(A* thisA, int x){

Class_B*this =

convert_ptr_to_A_to_ptr_to_B(thisA);

}

void m3B_B(B* this){…}

p.m2(3);

pdispatch_tablem2A(p, 3);

classA *p;

(Runtime) Dispatch Table

Runtime object

p

m1A_A

vtable

m2A_A

a1

a2

more efficient implementation5
More efficient implementation

typedefstruct{

field a1;

field a2;

} A;

void m1A_A(A* this){…}

void m2A_A(A* this, int x){…}

typedefstruct {

field a1;

field a2;

field b1;

} B;

void m2A_B(A* thisA, int x){

Class_B*this =

convert_ptr_to_A_to_ptr_to_B(thisA);

}

void m3B_B(B* this){…}

classB *p;

(Runtime) Dispatch Table

Runtime object

p

m1A_A

vtable

m2A_B

a1

m3B_B

a2

b1

more efficient implementation6
More efficient implementation

typedefstruct{

field a1;

field a2;

} A;

void m1A_A(A* this){…}

void m2A_A(A* this, int x){…}

typedefstruct {

field a1;

field a2;

field b1;

} B;

void m2A_B(A* thisA, int x){

Class_B*this =

convert_ptr_to_A_to_ptr_to_B(thisA);

}

void m3B_B(B* this){…}

p.m2(3);

classB *p;

(Runtime) Dispatch Table

Runtime object

p

m1A_A

vtable

m2A_B

a1

m3B_B

a2

b1

more efficient implementation7
More efficient implementation

typedefstruct{

field a1;

field a2;

} A;

void m1A_A(A* this){…}

void m2A_A(A* this, int x){…}

typedefstruct {

field a1;

field a2;

field b1;

} B;

void m2A_B(A* thisA, int x){

Class_B*this =

convert_ptr_to_A_to_ptr_to_B(thisA);

}

void m3B_B(B* this){…}

p.m2(3);

pdispatch_tablem2A(p, 3);

(Runtime) Dispatch Table

Runtime object

p

m1A_A

vtable

m2A_B

a1

m3B_B

a2

b1

more efficient implementation8
More efficient implementation

typedefstruct{

field a1;

field a2;

} A;

void m1A_A(A* this){…}

void m2A_A(A* this, int x){…}

typedefstruct {

field a1;

field a2;

field b1;

} B;

void m2A_B(A* thisA, int x){

Class_B*this =

convert_ptr_to_A_to_ptr_to_B(thisA);

}

void m3B_B(B* this){…}

convert_ptr_to_B_to_ptr_to_A(p)

p.m2(3);

pdispatch_tablem2A( , 3);

(Runtime) Dispatch Table

Runtime object

p

m1A_A

vtable

m2A_B

a1

m3B_B

a2

b1

multiple inheritance
Multiple Inheritance

class C {

field c1;

field c2;

method m1(){…}

method m2(){…}

}

class D {

field d1;

method m3() {…}

method m4(){…}

}

class E extends C, D {

field e1;

method m2() {…}

method m4() {…}

method m5(){…}

}

multiple inheritance1
Multiple Inheritance
  • Allows unifying behaviors
  • But raises semantic difficulties
    • Ambiguity of classes
    • Repeated inheritance
  • Hard to implement
    • Semantic analysis
    • Code generation
      • Prefixing no longer work
      • Need to generate code for downcasts
  • Hard to use
a simple implementation
A simple implementation
  • Merge dispatch tables of superclases
  • Generate code for upcasts and downcasts
a simple implementation1
A simple implementation

class D {

field d1;

method m3() {…}

method m4(){…}

}

class E extends C, D {

field e1;

method m2() {…}

method m4() {…}

method m5(){…}

}

class C {

field c1;

field c2;

method m1(){…}

method m2(){…}

}

Pointer to

- E

- C inside E

Runtime object

(Runtime) Dispatch Table

vtable

m1C_C

a1

m2C_E

a2

Pointer to

- D inside E

m3D_D

vtable

m4D_E

a1

m5E_E

a2

downcasting e c d
Downcasting (EC,D)

class D {

field d1;

method m3() {…}

method m4(){…}

}

class E extends C, D {

field e1;

method m2() {…}

method m4() {…}

method m5(){…}

}

class C {

field c1;

field c2;

method m1(){…}

method m2(){…}

}

convert_ptr_to_E_to_ptr_to_C(e) = e;

convert_ptr_to_E_to_ptr_to_D(e) = e + sizeof(C);

Pointer to

- E

- C inside E

Runtime object

(Runtime) Dispatch Table

vtable

m1C_C

a1

m2C_E

a2

Pointer to

- D inside E

m3D_D

vtable

m4D_E

a1

m5E_E

a2

upcasting c d e
Upcasting (C,DE)

class D {

field d1;

method m3() {…}

method m4(){…}

}

class E extends C, D {

field e1;

method m2() {…}

method m4() {…}

method m5(){…}

}

class C {

field c1;

field c2;

method m1(){…}

method m2(){…}

}

convert_ptr_to_C_to_ptr_to_E(c) = c;

convert_ptr_to_D_to_ptr_to_E(d) = d - sizeof(C);

Pointer to

- E

- C inside E

Runtime object

(Runtime) Dispatch Table

vtable

m1C_C

a1

m2C_E

a2

Pointer to

- D inside E

m3D_D

vtable

m4D_E

a1

m5E_E

a2

multiple inheritance2
Multiple Inheritance

class A{

field a1;

field a2;

method m1(){…}

method m3(){…}

}

class D extends A {

field d1;

method m3(){…}

method m4(){…}

}

class C extends A {

field c1;

field c2;

method m1(){…}

method m2(){…}

}

class E extends C, D {

field e1;

method m2() {…}

method m4() {…}

method m5(){…}

}

multiple inheritance3
Multiple Inheritance

class A{

field a1;

field a2;

method m1(){…}

method m3(){…}

}

class D extends A {

field d1;

method m3(){…}

method m4(){…}

}

class C extends A {

field c1;

field c2;

method m1(){…}

method m2(){…}

}

class E extends C, D {

field e1;

method m2() {…}

method m4() {…}

method m5(){…}

}

dependent multiple inheritance
Dependent Multiple Inheritance

class A{

field a1;

field a2;

method m1(){…}

method m3(){…}

}

class D extends A {

field d1;

method m3(){…}

method m4(){…}

}

class C extends A {

field c1;

field c2;

method m1(){…}

method m2(){…}

}

class E extends C, D {

field e1;

method m2() {…}

method m4() {…}

method m5(){…}

}

dependent inheritance
Dependent Inheritance
  • The simple solution does not work
  • The positions of nested fields do not agree
independent inheritance
Independent Inheritance

class A{

field a1;

field a2;

method m1(){…}

method m3(){…}

}

class C

extends A{

field c1;

field c2;

method m1(){…}

method m2(){…}

}

class D

extends A{

field d1;

method m3(){…}

method m4(){…}

}

class E

extends C,D{

field e1;

method m2() {…}

method m4() {…}

method m5(){…}

}

  • Multiple copies of shared superclasses

Runtime E object

Pointer to

- E

- C inside E

(Runtime) Dispatch Table

vtable

a1

m1A_C

a2

m3A_A

c1

m2C_E

c2

m1A_A

Pointer to

- D inside E

vtable

m3A_D

a1

m4D_E

a2

m5E_E

d1

e1

implementation
Implementation
  • Use an index table to access fields
  • Access offsets indirectly
implementation1
Implementation

class A{

field a1;

field a2;

method m1(){…}

method m3(){…}

}

class C

extends A{

field c1;

field c2;

method m1(){…}

method m2(){…}

}

class D

extends A{

field d1;

method m3(){…}

method m4(){…}

}

class E

extends C,D{

field e1;

method m2() {…}

method m4() {…}

method m5(){…}

}

(Runtime) Dispatch Table

Runtime E object

vtable

Index tab

m1A_C

a1

m3A_A

Pointer to

- E

- C inside E

a2

m2C_E

c1

m1A_A

c2

m3A_D

vtable

m4D_E

Pointer to

- D inside E

Index tab

m5E_E

Index tables

d1

2

3

4

5

8

9

-4

-3

2

e1

64

class descriptors
Class Descriptors
  • Runtime information associated with instances
  • Dispatch tables
    • Invoked methods
  • Index tables
  • Shared between instances of the same class
  • Can have more (reflection)
interface types
Interface Types
  • Java supports limited form of multiple inheritance
  • Interface consists of several methods but no fields
  • A class can implement multiple interfacesSimpler to implement/understand/use
  • Implementation: record with 2 pointers:
    • A separate dispatch table per interface
    • A pointer to the object

public interface Comparable {

public int compare(Comparable o);}

dynamic class loading
Dynamic Class Loading
  • Supported by some OO languages (Java)
  • At compile time
    • the actual class of a given object at a given program point may not be known
  • Some addresses have to be resolved at runtime
  • Compiling c.f() when f is dynamically loaded:
    • Fetch the class descriptor d at offset 0 from c
    • Fetch the address of the method-instance f from (constant) f offset at d into p
    • Jump to the routine at address p (saving return address)
other oo features
Other OO Features
  • Information hiding
    • private/public/protected fields
    • Semantic analysis (context handling)
  • Testing class membership
optimizing oo languages
Optimizing OO languages
  • Hide additional costs
    • Replace dynamic by static binding when possible
    • Eliminate runtime checks
    • Eliminate dead fields
  • Simultaneously generate code for multiple classeså
  • Code space is an issue
summary
Summary
  • OO is a programming/design paradigm
  • OO features complicates compilation
    • Semantic analysis
    • Code generation
    • Runtime
    • Memory management
  • Understanding compilation of OO can be useful for programmers
what is a compiler
What is a compiler?

“A compiler is a computer program that transforms source code written in a programming language (source language) into another language (target language).

The most common reason for wanting to transform source code is to create an executable program.” --Wikipedia

conceptual structure of a compiler

Source

text

txt

Executable

code

exe

Conceptual Structure of a Compiler

Compiler

Frontend

Semantic

Representation

Backend

LexicalAnalysis

Syntax Analysis

Parsing

Semantic Analysis

IntermediateRepresentation

(IR)

Code

Generation

conceptual structure of a compiler1

Source

text

txt

Executable

code

exe

Conceptual Structure of a Compiler

Compiler

Frontend

Semantic

Representation

Backend

LexicalAnalysis

Syntax Analysis

Parsing

Semantic Analysis

IntermediateRepresentation

(IR)

Code

Generation

from scanning to parsing

Op(*)

Op(+)

Id(b)

Num(23)

Num(7)

From scanning to parsing

program text

((23 + 7) * x)

Lexical Analyzer

token stream

Grammar: E ... | Id

Id  ‘a’ | ... | ‘z’

Parser

valid

syntaxerror

Abstract Syntax Tree

from scanning to parsing1

Op(*)

Op(+)

Id(b)

Num(23)

Num(7)

From scanning to parsing

program text

((23 + 7) * x)

Lexical Analyzer

token stream

Grammar: E ... | Id

Id  ‘a’ | ... | ‘z’

Parser

valid

syntaxerror

Abstract Syntax Tree

conceptual structure of a compiler2

Source

text

txt

Executable

code

exe

Conceptual Structure of a Compiler

Compiler

Frontend

Semantic

Representation

Backend

LexicalAnalysis

Syntax Analysis

Parsing

Semantic Analysis

IntermediateRepresentation

(IR)

Code

Generation

context analysis

E1 : int

E2 : int

E1 + E2 : int

Op(*)

Op(+)

Id(b)

Num(23)

Num(7)

Context Analysis

Abstract Syntax Tree

Type rules

Semantic Error

Valid + Symbol Table

code generation

Op(*)

Op(+)

Id(b)

Num(23)

Num(7)

Code Generation

Valid Abstract Syntax Tree

Symbol Table

cgen

Frame Manager

Verification (possible runtime)

Errors/Warnings

Intermediate Representation (IR)

input

Executable Code

output

optimization
Optimization

sourcecode

Frontend

Codegenerator

targetcode

IR

Program Analysis

Abstract interpretation

Can appear in later stages too

conceptual structure of a compiler3

Source

text

txt

Executable

code

exe

Conceptual Structure of a Compiler

Compiler

Frontend

Semantic

Representation

Backend

LexicalAnalysis

Syntax Analysis

Parsing

Semantic Analysis

IntermediateRepresentation

(IR)

Code

Generation

register allocation
Register Allocation

Target code

(executable)

LexicalAnalysis

Inter.Rep.(IR)

CodeGeneration

Source code

(program)

Syntax Analysis

Parsing

AST

SymbolTableetc.

  • The process of assigning variables to registers and managing data transfer in and out of registers
  • Using registers intelligently is a critical step in any compiler
    • A good register allocator can generate code orders of magnitude better than a bad register allocator
register allocation goals
Register Allocation: Goals

Target code

(executable)

LexicalAnalysis

Inter.Rep.(IR)

CodeGeneration

Source code

(program)

Syntax Analysis

Parsing

AST

SymbolTableetc.

  • Reduce number of temporaries (registers)
    • Machine has at most K registers
    • Some registers have special purpose
      • E.g., pass parameters
  • Reduce the number of move instructions
    • MOVE R1,R2 // R1  R2
code generation1
Code generation

Source code

(program)

LexicalAnalysis

Syntax Analysis

Parsing

ContextAnalysis

CodeGeneration

Target code

(executable)

Portable/Retargetable code generation

Assembly

Text

AST + Sym. Tab.

Token stream

AST

IR

code generation2
Code generation

Source code

(program)

LexicalAnalysis

Syntax Analysis

Parsing

ContextAnalysis

CodeGeneration

Target code

(executable)

Portable/Retargetable code generation

Assembly

register allocation

IR (TAC) generation

Instruction selection

IR Optimization

Text

AST + Sym. Tab.

Token stream

AST

IR

Peephole optimization

“Assembly”

(symbolic registers)

“Naive” IR

Assembly

runtime system gc
Runtime System (GC)

Executing program

Source code

(program)

LexicalAnalysis

Syntax Analysis

Parsing

ContextAnalysis

CodeGeneration

Target code

(executable)

Portable/Retargetable code generation

Assembler

Text

AST + Sym. Tab.

Token stream

AST

IR

Loader

Linker

Runtime System

Symbolic Addr

Object File

Executable File

image

compilation execution2
Compilation  Execution

Source code

(program)

LexicalAnalysis

Syntax Analysis

Parsing

ContextAnalysis

Portable/Retargetable code generation

CodeGeneration

Linking

Loading

Executing program

Text

Token stream

AST

Image

“Hello World”

AST + Sym. Tab.

IR

Object File

Executable File

Runtime System

the end
The End

And advanced course next semester

And workshop on detecting malicious JavaScripts

the end1
The End

And advanced course next semester

And workshop on detecting malicious JavaScripts (using static analysis)

And thanks you & good luck!