380 likes | 408 Views
Object-oriented Languages. Compiler Baojian Hua bjhua@ustc.edu.cn. OOP. So far, we ’ ve covered most imperative features Object-oriented languages are more and more popular, due to the industry push this time: compile the class-based OO languages Topics today: class and objects
E N D
Object-oriented Languages Compiler Baojian Hua bjhua@ustc.edu.cn
OOP • So far, we’ve covered most imperative features • Object-oriented languages are more and more popular, due to the industry push • this time: compile the class-based OO languages • Topics today: • class and objects • inheritance & virtual functions • RTTI & reflection • interface • later: garbage collection and exception handling
Class “Point” class P2 { int x; int y; P2 (int x, int y) { this.x = x; this.y = y; } void print () { println (this.x, this.y); } }
Compiling to C // Close all functions: class P2 { int x; int y; P2 (P2 this, int x, int y) { this.x = x; this.y = y; } void print (P2 this) { println (this.x, this.y); } }
Compiling to C // Hoisting: class P2 { int x; int y; } P2 (P2 this, int x, int y) { this.x = x; this.y = y; } void print (P2 this) { println (this.x, this.y); }
Compiling to C // In C’s syntax: struct P2 { int x; int y; }; typedef struct P2 *P2; P2 (P2 this, int x, int y) { this->x = x; this->y = y; } P2 x y
Client Code // Client code: P2 p = new P2 (3, 4); p.print (); // compiles to: P2 p = malloc (sizeof (*p)); P2(p, 3, 4); print(p); P2 x y
Moral • Inside OOP is imperative programming: • class = struct + function code • object = transparent memory chunk • In history, some compilers compile OO to C • e.g., Bjarne Stroustrup et.al’sCfront for C++ • Next we scale up to more interesting feathers: • inheritance and virtual functions
Single Inheritance & Prefixing // A technique called // prefixing: class P3 extends P2 { int z; void print3d () { … } } class P2 { P2 (int x, int y) { this.x = x; this.y = y; } } int x; int y; int x; int y; void print(){ println(this.x, this.y); } void print(){ println(this.x, this.y); }
Compiling to C struct P2 { int x; int y; }; struct P3 { int x; int y; int z; }; void P2_print (P2 this) {…} void P3_print (P2 this) {…} void print3d (P3 this) {…} P2 x y P3 x y z Q: can we put “z” before “x” or “y”?
Virtual functions and Overriding // What about super and sub-class contain same // methods? class P2 { …; void print () {…} } class P3 extends P2 { …; void print () {…} }
Dynamic dispatch class P2 { …; void print () {…} } class P3 extends P2 { …; void print () {…} } P2 p; p = new P2 (); p.print (); p = new P3 (); p.print ();
Compiling dynamic dispatch • Variable’s compile-time type is insufficient to determine the specific function to call • One need to store, in the object, auxiliary information to help make the decision • The data structure for this purpose is the virtual function table (vtable) • Function calls become indirections via vtables
Vtable vptr class P2 { …; void print () {…} } class P3 extends P2 { …; void print () {…} } P2_print x y vtable vptr P3_print x y vtable z
General Scheme vptr class A { int x1; …; int xn; void f1 (…){} … void fn (…){} }; A_f1 x1 … … A_fn xn vtable
Client Code vptr // Client code: P2 p; p = new P2 (3, 4); p.print (); // compiles to: P2 p; p = malloc (sizeof (*p)); // how many bytes? P2(p, 3, 4); ((p->vptr)[0]) (p); // indirection P2_print x y p
Client Code vptr // Client code: P2 p; p = new P2 (3, 4); p.print (); p = new P3 (7, 8, 9); p.print (); P2_print x y p vptr P3_print 7 8 9
Moral • Dynamic dispatch is subtyping polymorphism: • flexible and powerful • No free lunch: • extra space to store vtables • dynamic dispatch via indirection (slow?) • “All problems in computer science can be solved by another level of indirection!” • -- Butler Lampson • OO = Pointer + Virtual Functions
Multiple Inheritance class A {…} class B {…} class C extends A, B {…} A B C
Multiple Inheritance • Impossible to do prefixing: • inheritance are now DAGs, not trees • Several approaches to handle this: • topo-sort • used in both MS VS and GCC compilers • global graph coloring (Tiger book 14.3) • hash tables in objects
Topo-sort A B A vtable B vtable A, B, C C C class C extends A, B{ int k; void c () {} void g () {} void f () {} } class B{ int j; void b () {} void g () {} } class A{ int i; void a () {} void f () {} }
Topo-sort class A{ int i; void a () {} void f () {} } class C extends A, B{ int k; void c () {} void g () {} void f () {} } class B{ int j; void b () {} void g () {} }
Topo-sort class C extends A, B{ int k; void c () {} void g () {} void f () {} } class A{ int i; void a () {} void f () {} } vptr A_a i A_f class B{ int j; void b () {} void g () {} }
Topo-sort class A{ int i; void a () {} void f () {} } class C extends A, B{ int k; void c () {} void g () {} void f () {} } vptr A_a i A_f vptr class B{ int j; void b () {} void g () {} } j B_b B_g
Topo-sort vptr A_a class A{ int i; void a () {} void f () {} } vptr A_a i C_f i A_f vptr C_c j C_g k B_b class C extends A, B{ int k; void c () {} void g () {} void f () {} } vptr class B{ int j; void b () {} void g () {} } C_g j B_b B_g
vptr A_a Problem? p i C_f q vptr C_c j C_g k class A{ int i; void a () {} void f () {} } vptr B_b A_a class C extends A, B{ int k; void c () {} void g () {this.i=0;} void f () {} } i C_g A_f vptr class B{ int j; void b () {} void g () {} } j C *p = new C(); B *q = (B*)p; q->g(); // C_g(q); B_b B_g
vptr A_a 0 Solution1 p i C_f 0 q vptr C_c 0 j C_g 0 k class A{ int i; void a () {} void f () {} } vptr B_b 0 A_a class C extends A, B{ int k; void c () {} void g () {this.i=0;} void f () {} } i C_g -8 A_f vptr class B{ int j; void b () {} void g () {} } j C *p = new C(); B *q = (B*)p; q->g(); // C_g(q); B_b B_g
vptr A_a Solution2 p i C_f q vptr C_c j C_g k class A{ int i; void a () {} void f () {} } vptr B_b A_a class C extends A, B{ int k; void c () {} void g () {this.i=0;} void f () {} } i C_g’ A_f vptr class B{ int j; void b () {} void g () {} } C_g’(this){ this -= 8; C_g(this); } j This piece of code is called a thunk. B_b B_g
Global Graph Coloring class A {int a;} class B {int b; int c;} class C extends A {int d;} class D extends A, B, C {int e;} a Step #1: interference graph construction: For each pair of instance variable (x, y), draw an edge between x and y, if x and y can not be in same position. b e d c
Global Graph Coloring class A {int a;} class B {int b; int c;} class C extends A {int d;} class D extends A, B, C {int e;} 0 a Step #2: coloring: Assign a color for each node, adjacent nodes are of different colors. 1 4 b e d c 2 3
Global Graph Coloring Step #3: determining layout: Determine every object’s layout. class A {int a;} class B {int b; int c;} class C extends A {int d;} class D extends A, B, C {int e;} 0 a A B C D 1 4 a a b e b b c c d c d d 2 3 e
Moral • Can be further optimized • see figure 14.5 on Tiger book • Must take whole program • may be very expensive • graph coloring are slow and space inefficient • Problems: • hurt by dynamic linking and dynamic class loader • so C++ has multiple inheritance but not class loading; whereas Java has dynamic class loading but not multiple inheritance
Hash Table in Class Descriptor class A {int a;} class B {int b; int c;} class C extends A {int d;} class D extends A, B, C {int e;} A B C D a b a a a: 0 b: 0 a: 0 a: 0 c d b c: 1 d: 1 b: 1 c c: 2 d d: 3 e e: 4
RTTI & reflection • RTTI: Run Time Type Identification • Ability to identify the type (class) of an object at runtime • Reflection: • more powerful, can (almost) do anything at runtime • What are they used for? • Type identification • Inheritance hierarchy • string based method invocation • exception handling • …
RTTI P2 p; …; Class c = p.getClass (); println (c.getClassName()); meta name vptr “P2” P2_print … x … y
Reflection P2 p; …; Class c = p.getClass (); println (c.getClassName()); c.getMethod (“print”, null); meta name vptr “P2” P2_print “print”, p x … y
Interface • Read and discuss the assigned paper
vptr A_a Solution2 i C_f vptr C_c j C_g k class A{ int i; void a () {} void f () {} } vptr B_b A_a class C extends A, B{ int k; void c () {} void g () {this.i=0;} void f () {} } i C_g’ A_f vptr class B{ int j; void b () {} void g () {} } C_g’(this){ this -= 8; C_g(this); } j This piece of code is called a thunk. B_b B_g