1 / 24

Java Subtype Tests in Real-Time

Java Subtype Tests in Real-Time. Krzysztof Palacz, Jan Vitek University of Purdue Presented by: Itay Maman. Outline. Subtyping tests Previous work R&B Overview Ranges (SI test) Buckets (MI test) Results Conclusions & Future Research. Subtyping tests. Does a type extend a given class?

zorina
Télécharger la présentation

Java Subtype Tests in Real-Time

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. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Java Subtype Tests in Real-Time Krzysztof Palacz, Jan Vitek University of Purdue Presented by: Itay Maman

  2. Outline • Subtyping tests • Previous work • R&B Overview • Ranges (SI test) • Buckets (MI test) • Results • Conclusions & Future Research

  3. Subtyping tests Does a type extend a given class? Does a type implement a given interface? • Given a hierarchy (T,≺) • T is a set of types • ≺ is a partial order over T (reflexive, transitive and anti-symmetric) called subtype relation • The query c ≺ p is a subtype test • In the above test, C is the Client type, while P is the Provider type • Java: • Class inheritance test (“extends”) is an SI subtype test • Interface inheritance test (“implements”) is an MI subtype test

  4. Subtyping tests - Requirements • Queries must run in constant time • Space overhead must not significantly increase system footprint • Size of emitted code • Memory needed for the data structure • Support for dynamic loading of classes • Ideally, should be able to load a class without blocking concurrent subtype queries, invoked by other threads

  5. Naïve solution subtypeOf(type_info cl, type_info pr) { if(cl == pr || cl.cache == pr) return true; if(pr.isInterface return implements(cl, pr); else return extends(cl, pr); } implements(type_info cl, type_info pr) { for(int i = 0; i < pr.interfaces.length; ++i) if(cl == pr.interfaces[i]) { cl.cache = pr; return true; } return false; } extends(type_info cl, type_info pr) { for(type_info t = cl.parent; t != null; t = t.parent) if(t == pr) { cl.cache = pr; return true; } return false; }

  6. Previous Work • SI (single inheritance) hierarchies • Bit matrix – Space inefficient • Relative numbering [Schubert ’83] • Cohen's algorithm [Cohen ’91] • MI (multiple inheritance) hierarchies • Packed Encoding (PE) - generalization of Cohen's algorithm [Krall, Vitek and Horspool ’97] • Bit-vectors [Krall, Vitek and Horspool ’97a] • PQ Encoding – Adapts Relative numbering to MI [Zibin, Gil ’01] • Incremental technique in production JVMs (HotSpot, Jalapeno) • SI: Cohen’s algorithm with arrays of a fixed size (inlined) • MI: Linear search over a list of displays

  7. [0,8] A B C [1,3] [4,7] D F E [2,0] [5,0] [6,0] Ranges (SI test): The basics • Based on Scubert’s technique • Ranges of children are subranges of their parents’ • Ranges of siblings are disjoint • Range assignment: Via a pre-order walk • c≺pp.low ≤ c.low < p.high

  8. The high bound can be calculated on-demand. When a type is loaded it is initialized with 0 Ranges (SI test): Refinements • Only the low bound is observed for the client • A leaf type can reuse its parent’s low bound Reminder: c≺pp.low ≤ c.low < p.high Conclusion: insert(type_info t) { t.high = 0; t.low = (t.parent == null) ? 1 : t.parent.low; }

  9. Ranges (SI test): extends() • extends() implements an SI test • If the provider’s high bound is not present, its value is computed by invoking promote() extends(type_info cl, type_info pr) { if(pr.low <= cl.low && cl.low < pr.high) return true; if(pr.high != 0) return false; promote(pr); return (pr.low <= cl.low && cl.low < pr.high); }

  10. A B C D F E Ranges (SI test): promote(), 1/3 Steps for computing range assignments: • Step 1. Place all type_info items in an array using a pre-order walk • Leaf types are stored once • Non-leaves are stored twice: once before all their subtypes, and once after type_info:

  11. A B C D F E Ranges (SI test): promote(), 2/3 • Step 2. Perform a left-to-right iteration over the array. Compute order[i] for each index • Start with 1 • Increase whenever a non-leaf type is encountered order: type_info:

  12. A C.h = 5 B.h = 3 E.l = 4 B.l = 2 B C A.l = 1 C.l = 4 F.l = 4 D.l = 2 A.h = 6 D F E Ranges (SI test): promote(), 3/3 • Perform a right-to-left iteration over the array (end to beginning) • Right position of a non-leaf type: assign order[i] to its high bound • Left position of a non-leaf type: assign order[i] to its low bound • Leaf type: assign order[i] to its low bound order: [1,6] [2,3] [4,5] [2,0] [4,0] [4,0] type_info:

  13. Promote() is thread-safe Ranges (SI test): Thread-safety Given the following properties of the promote() algorithm… • A type’s high bound is updated before its subtypes are processed • A type’s high bound is updated before its low bound • Sibling types are processed on a descending order of their low bounds … It is guaranteed that the invariants of Scubert’s technique are kept at any given point during its operation: • Ranges of children are subranges of their parents’ • Ranges of siblings are disjoint Conclusion:

  14. Ranges (SI test): Summary • Low, constant memory demands (32 bits per class) • Query time • Is constant in vast majority of the tests • In RT systems, promote() can be used eagerly (invoked on class load), to ensure constant query time • Code is thread-safe => can handle dynamically loaded classes. No need to “stop the world” • Performance improvement of: ** ??? **

  15. Buckets (MI test): The basics • Based on the Packed-Encoding algorithm (PE) • Each interface is assigned to a bucket, and receives a unique id (iid) within that bucket • Two interfaces in a bucket do not have a common subtype • c≺pc.display[p.bucket] ==p.iid type_info { … byte[] display; } interface_info { byte iid; byte bucket; }

  16. Buckets (MI test): assignment 1/3 Computing bucket assignments: • Case 1. Loading an interface. • If all buckets are full or no bucket exists, create a new bucket • Choose the bucket with the fewest interfaces among ‘M’ most recently created buckets. (Typically, M = 5) • Create a new iid value for the interface, which is unique within the bucket. • A bucket cannot reuse ‘old’ (i.e: previously used) iid-s

  17. Buckets (MI test): assignment 2/3 • Case 2. Loading a class. • If the interfaces implemented by the class are of different buckets, initialize the array of displays: cl.display[i.bucket] = i.iid; // for each implemented interface i • Otherwise, the class is a subtype of (at least) two interfaces of the same bucket. These interfaces must be reassigned to other buckets (Details on the next slide)

  18. Buckets (MI test): assignment 3/3 • Case 2 contd. Loading a class/Reassignment • For each bucket b, with k interfaces implemented by a class C: • Create k-1 new buckets • k-1 interfaces are assigned to the new buckets • Remaining interfaces from b are evenly spread among b and the new buckets An interface’s iid is not changed when the interface is reassigned A bucket cannot reuse an iid of an interfaces that was reassigned • Iterate over all loaded classes and update their display[] array: • Existing entries remain unchanged • New entries are added for the new buckets • Consequently, in a given class’s display[] an iid of the same interface may appear more than once. • Iterate over all reassigned interfaces, update their bucket value

  19. Buckets (MI test): Thread-safety Given the following properties of the Buckets algorithm… • An interface never changes its iid • A bucket cannot reuse an ‘old’iid • Updated display[] arrays contain the old entries as well as the new ones • An interface’s bucket value is changed only after display[] s are updated … It is guaranteed that an implements() query will always yield the correct result

  20. The END

  21. Definitions • ≺d is the transitive reduction of ≺ • ≺ is the transitive closure of ≺d • Formally, a≺d b iff a ≺ b and there is no c such that a ≺ c ≺ b, a≠c≠b. • Also, • ancestors(a)≡{b∈T| a ≺ b}, descendants(a)≡{b∈T| b ≺ a} • parents(a)≡{b∈T| a ≺d b}, children(a)≡{b∈T| b ≺d a} • roots≡{a∈T| parents(a)=∅}, leaves≡{a∈T| children(a)=∅} • level(a)≡1+max{level(b)| b∈parents(a)} • Single inheritance (SI) vs. multiple inheritance (MI) • In SI, for each a∈T, |parents(a)|≤1

  22. Cohen's algorithm • Partition the hierarchy into levels • a≺blb≤ la and ra[lb] =idb • lbis level(b), idb is a unique identifier within the level

  23. Range compression • Apply postorder on some spanning forest • a ≺ b  lb[i]≤ida ≤rb[i] , for some i {1,2,3} {2,5,6}

  24. Ranges (SI test): promote() Computes range assignments: • Place all types in an array using a pre-order walk • Leaf types are stored once • Non-leaves are stored twice: once before all their subtypes, and once after • Perform a left-to-right iteration over the array. Compute order[i] for each index • Start with 1 • Increase whenever a non-leaf type is encountered • Perform a right-to-left iteration over the array (end to beginning) • Leaf type: assign (order[i], 0) to (low, high) • Right position of a non-leaf type: assign order[i] to its high bound • Left position of a non-leaf type: assign order[i] to its low bound

More Related