Implementing Object-Oriented Languages Implementing single inheritance Key features: Key idea: prefixing • inheritance (possibly multiple) • layout of superclass is a prefix of layout of subclass + instance variable access is just a load or store • subtyping & subtype polymorphism + can add new instance variables in subclasses • message passing, dynamic binding − cannot override or undefine instance variables − multiple inheritance... Subtype polymorphism is the key problem class Point { • support uniform representation of data x int x; (analogous to boxing for polymorphic data) int y; y • e.g. every object has a class pointer, or a virtual fn table pointer, } at a known offset • organize layout of data to make instance variable access class ColorPoint x and method lookup & invocation fast extends Point { y • multiple inheritance complicates this Color color; • perform static analysis to bound polymorphism } color • perform transformations to reduce polymorphism // OK: subclass polymorphism Point p = new ColorPoint(3,4,Blue); // OK: x and y have same offsets in all Point subclasses int manhattan_distance = p.x + p.y; Craig Chambers 219 CSE 501 Craig Chambers 220 CSE 501 Implementing dynamic dispatching (virtual functions) Example of function tables class Point { Key idea: class-specific table of function pointers int x; • store pointer to table in each object int y; • assign table offset to method name, void draw(); just as instance variable offsets are assigned int distance2origin(); • exploit prefixing in function table layout: } superclass’s function table layout is a prefix of subclass’s function table layout table Point::draw draw x ... d2o Dynamically-dispatched call sequence: Point::d2o y ⇒ T obj = ...; ... obj.msg() ... load *(obj + offset T:: table ), table load *(table + offset T::msg ), method class ColorPoint extends Point { call *method Color color; void draw(); + dynamic dispatching is fast & constant-time void reverse_video(); + can add new methods, override old ones } (can undefine methods by leaving hole in function table) table − extra word of memory per object ColorPt::draw draw − loads, indirect calls can be slow on pipelined machine x ... d2o − no inlining y r_v ColorPt::r_v color Craig Chambers 221 CSE 501 Craig Chambers 222 CSE 501
Multiple inheritance Clever solution: embedding, not prefixing Problem: prefixing doesn’t work with multiple inheritance Embed layout of each superclass somewhere in object • e.g. concatenate layouts of immediate superclasses, class Point { then extend with subclass’s instance variables x int x; int y; y Trick: adjust object pointer to point to appropriate embedded } object whenever use subclass polymorphism, based on static type of pointer class ColoredThing { • perform pointer arithmetic on color Color color; assignments, type casts, parameter & result passing } if static type of l.h.s. differs from r.h.s. • must test for NULL pointer and not change, though x color class ColorPoint • constants to add/subtract determined by static types & ? extends Point, y x analysis of inheritance graph, at compile-time ColoredThing { color y } + fast access to instance variables − some type-casts (implicit or explicit) now do arithmetic − interior pointers complicate garbage collection ColorPoint cp = new ColorPoint(3, 4, Blue); − type-casts outside the class hierarchy break: Point p = cp; // OK void* p = new ColorPoint(...); ColoredThing t = cp; // OK ColoredThing t = (ColoredThing) p; // breaks: ... t.color ... // returns p.x ! ColorP cp2 = new ColorPoint(p.x, p.y, t.color); Craig Chambers 223 CSE 501 Craig Chambers 224 CSE 501 Example Multiple inheritance and dynamic dispatching class Point { x Extend embedding to implement dynamic dispatching, too int x; • replicate function tables for each immediate superclass, int y; y to avoid clashes in method offsets } − multiple function table pointers in object class ColoredThing { color Color color; } ColorPoint cp = new ColorPoint(3, 4, Blue); cp ... cp.distance2origin() ...; // works x p class ColorPoint ... cp.draw() ...; // works extends Point, y ColoredThing { t ColoredThing t = cp; // works; adds 12 to cp color } ... t.reverse_video() ...; // works ColorPoint cp = new ColorPoint(3, 4, Blue); Point p = cp; // OK ColoredThing t = cp; // OK: adds 8 to cp // now this works: ColorP cp2 = new ColorPoint(p.x, p.y, t.color); // this works, too: ColorP cp3 = (ColorPoint) t; // subtracts 8 from t Craig Chambers 225 CSE 501 Craig Chambers 226 CSE 501
Example of embedded function tables A problem class Point { class ColoredThing { Simple embedding doesn’t always work! int x; Color color; int y; void reverse_video() { ... cp.reverse_video() ...; void draw(); ... self.color ... // breaks: accesses self.x instead of self.color int d2o(); } // inside reverse_video method } } table table draw r_v x d2o color y class ColorPoint extends Point, ColoredThing { void draw(); } cp table draw ColorPt::draw x d2o y table t r_v color Craig Chambers 227 CSE 501 Craig Chambers 228 CSE 501 Analysis of the problem An implementation strategy Problem: Add an extra column to function table, implicit cast of actual receiver to formal receiver ignored containing required pointer adjustment for receiver • sometimes need to do pointer arithmetic Fetch and add adjustment to receiver pointer as part of call: ⇒ T obj = ...; ... obj.msg() ... How to fix it? load *(obj + offset T:: table ), table • caller can’t do it: load *(table + offset T::msg *2 ), method doesn’t know type of formal in callee load *(table + offset T::msg *2+4), delta • callee can’t do it: add obj, delta, obj; doesn’t know type of actual in caller call *method • function tables can do it: caller’s offset known, callee’s offset known − 5 instructions, not 3 • costs even if multiple inheritance not used! − some space cost − only works for receiver; need some other mechanism if argument or result types change via method overriding [Stroustrup 87] Craig Chambers 229 CSE 501 Craig Chambers 230 CSE 501
Example of function tables with offsets An alternate strategy class Point { class ColoredThing { Insert “trampoline” function to perform updates where necessary int x; Color color; • dispatch sequence is same 3 instructions int y; void reverse_video() { as for single inheritance case void draw(); ... self.color ... • callee may be an adjustment function, which forwards to int d2o(); } real function } } + no cost for potential multiple inheritance where not used table table draw 0 r_v 0 + invocations requiring adjustment may be faster, too x d2o 0 color y class ColorPoint extends Point, ColoredThing { void draw(); } cp table draw 0 ColorPt::draw x d2o 0 y r_v 12 table t 0 r_v color Craig Chambers 231 CSE 501 Craig Chambers 232 CSE 501 Example of function tables with trampolines Multiple inheritance with shared superclasses class Point { class ColoredThing { class Point { int x; Color color; int x; int y; void reverse_video() { int y; void draw(); ... self.color ... } int d2o(); } class ColorPoint extends Point { } } Color color; } table draw table r_v class Point3D extends Point { x d2o int z; color } y class ColorPoint3D extends ColorPoint, Point3D { class ColorPoint extends Point, ColoredThing { } void draw(); Point } x y cp table draw ColorPt::draw ColorPoint Point3D x d2o color z self = self + 12; y r_v jump CT::r_v; table t ColorPoint3D r_v color Craig Chambers 233 CSE 501 Craig Chambers 234 CSE 501
Recommend
More recommend