Presentation is loading. Please wait.

Presentation is loading. Please wait.

Difficult Specifications in Javari Immutability Inference Jaime Quinonez Program Analysis Group April 20, 2007.

Similar presentations


Presentation on theme: "Difficult Specifications in Javari Immutability Inference Jaime Quinonez Program Analysis Group April 20, 2007."— Presentation transcript:

1 Difficult Specifications in Javari Immutability Inference Jaime Quinonez Program Analysis Group April 20, 2007

2 2 Overview Overview of Javari Java with reference immutability Overview of Javarifier Immutability reference algorithm Cases with specifications that are hard to interpret Closed-world assumption Subtyping Conflicting, legal specifications Correct specification depends on use

3 3 Reference Immutability in Java For convenience, use annotations as type qualifiers @ReadOnly on a type specifies a reference that cannot be used to modify an object @ReadOnly can annotate any use of a type For a type T, @ReadOnly T is a supertype of T @Mutable T is equivalent to T T can be used anywhere @ReadOnly T is expected @ReadOnly T cannot be used where T is expected

4 4 Example mutable class setTime() mutates object getTime() does not mutate object public class Date { private long time; public Date(long t) { this.time = time; } public long getTime() { return time; } public void setTime(long time) { this.time = time; }

5 5 @ReadOnly receiver annotates method getTime() does not mutate object receiver of getTime() is @ReadOnly public class Date { private long time; public Date(long t) { this.time = time; } public long getTime() @ReadOnly { return time; } public void setTime(long time) { this.time = time; }

6 6 Some fields not part of state hashCode() does not modify abstract state hashCode() modifies a field public class Date { private int hc; public int hashCode() @ReadOnly { if(hc == 0) { hc = … ; } return hc; }

7 7 @Assignable excludes fields from abstract state hc is not part of abstract state public class Date { private @Assignable int hc; public int hashCode() @ReadOnly { if(hc == 0) { hc = … ; } return hc; }

8 8 @ThisMutable gives fields mutability of containing reference @ThisMutable is the default for all fields @ReadOnly Cell ’s provide @ReadOnly Date references @Mutable Cell’s provide @Mutable Date references public class Cell { public @ThisMutable Date d; } @ReadOnly Cell roCell; @Mutable Cell muCell; roCell.d; // type: @ReadOnly Date muCell.d; // type: @Mutable Date

9 9 @RoMaybe templates methods over mutability All @RoMaybe ’s can be replaced with all @ReadOnly or @Mutable public class Cell { public @ThisMutable Date d; public @RoMaybe Date get() @RoMaybe { return d; } @ReadOnly Cell roCell; @Mutable Cell muCell; roCell.get(); // type: @ReadOnly Date, no rep exposure muCell.get(); // type: @Mutable Date, have rep exposure

10 10 Javarifier : Type Inference Algorithm Flow-insensitive and context-insensitive Generate a set of mutability constraints Unguarded constraint states unconditional mutability “x is mutable” Guarded constraint states conditional mutability “if x is mutable, then y is mutable” Solve set of constraints to see what types have to be mutable All other types can safely be declared immutable

11 11 Field reassignment mutates object Create unguarded constraint public class Date { private long time; public Date(long time) { this.time = time } public void setTime(long time) { this.time = time; } public long getTime() { return time; }

12 12 Field reassignment mutates object Create unguarded constraint public class Date { private long time; public Date(long time) { this.time = time } public void setTime(long time) { this.time = time; } public long getTime() { return time; }  Date.setTime().this is mutable

13 13 Calling methods on fields Create guarded constraint based on field’s type public class Cell { private Date d; public long get() { return d.getTime(); } public void reset() { d.setTime(0); }

14 14 Calling methods on fields Create guarded constraint based on field’s type public class Cell { private Date d; public long get() { return d.getTime(); } public void reset() { d.setTime(0); }

15 15 Calling methods on fields Create guarded constraint based on field’s type public class Cell { private Date d; public long get() { return d.getTime(); } public void reset() { d.setTime(0) } Date.getTime().this mutable -> Cell.d mutable Date.getTime().this mutable -> Cell.get().this mutable

16 16 Calling methods on fields Create guarded constraint based on field’s type public class Cell { private Date d; public long get() { return d.getTime(); } public void reset() { d.setTime(0); } Date.getTime().this mutable -> Cell.d mutable Date.getTime().this mutable -> Cell.get().this mutable

17 17 Calling methods on fields Create guarded constraint based on field’s type public class Cell { private Date d; public long get() { return d.getTime(); } public void reset() { d.setTime(0); } Date.getTime().this mutable -> Cell.d mutable Date.getTime().this mutable -> Cell.get().this mutable Date.setTime().this mutable -> Cell.d mutable Date.setTime().this mutable -> Cell.reset().this mutable

18 18 Javarifier propagates unguarded constraints Constraints 1. Date.setTime().this is mutable 2. Date.getTime().this mutable -> Cell.d mutable 3. Date.getTime().this mutable -> Cell.get().this mutable 4. Date.setTime().this mutable -> Cell.d mutable 5. Date.setTime().this mutable -> Cell.reset().this mutable New Constraints 6. Cell.reset().this is mutable 7. Cell.d is mutable Final unguarded constraints Date.setTime().this is mutable Cell.reset().this is mutable Cell.d is mutable All other types are @ReadOnly

19 19 Closed-world assumption causes ambiguity Javarifier assumes that all classes in the system are known All classes are implemented All interfaces and abstract classes have some implementation If any part of the system changes, all annotations become invalid If an implementation is missing, nothing can be done Whatever is inferred, programmer can claim the opposite should be true public class C { public void foo(Object o) { throw new RuntimeException(); } public interface A { Object void bar(); }

20 20 Subclasses must inherit mutability exactly Mutability is part of the method signature A defines method foo with no body, B and C extend A and provide implementation C.foo(List) modifies its argument, B.foo(List) does not public abstract class A { abstract void foo(List arg); } public class B extends A { void foo(List arg) { } } public class C extends A { void foo(List arg) { arg.clear(); }

21 21 Subclasses must inherit mutability exactly C.foo(List) must take a mutable parameter, so all definitions of foo must take a mutable parameter If you only examined output on class A and B, mutability wouldn’t make sense public abstract class A { abstract void foo(@Mutable List arg); } public class B extends A { void foo(@Mutable List arg) { } } public class C extends A { void foo(@Mutable List arg) { arg.clear(); }

22 22 Alternative annotations on a class Cell wraps around a Date object, which makes up its abstract state set() clearly modifies the abstract state of the object get() does not modify the abstract state, but does expose it public class Cell { private Date d; public void set(Date d) { this.d = d; } public Date get() { return d; }

23 23 Alternative annotations on a class Field d is this-mutable set() has a mutable ‘ this ’, so this.d is mutable and thus parameter is mutable get() returns a Date of the same mutability as what is passed in Can only insert mutable Date s public class Cell { private @ThisMutable Date d; public void set(@Mutable Date d) @Mutable { this.d = d; } public @RoMaybe Date get() @RoMaybe { return d; }

24 24 Alternative annotations on a class Field d is readonly set() still mutates its receiver, but now accepts a readonly Date get() can only return a readonly Date Can only get back readonly Date s public class Cell { private @ReadOnly Date d; public void set(@ReadOnly Date d) @Mutable { this.d = d; } public @ReadOnly Date get() @ReadOnly { return d; }

25 25 Alternative annotations on a class Field d is mutable set() still mutates its receiver, must take a mutable Date get() can return a mutable Date Can only insert mutable Date s public class Cell { private @Mutable Date d; public void set(@Mutable Date d) @Mutable { this.d = d; } public @Mutable Date get() @ReadOnly { return d; }

26 26 Field can be excluded from abstract state Field d is assignable and this-mutable set() does not change the abstract state of the object get() can only return mutable Date Can only return mutable Date s public class Cell { private @Assignable @ThisMutable Date d; public void set(@ReadOnly Date d) @ReadOnly { this.d = d; } public @ReadOnly Date get() @ReadOnly { return d; }

27 27 Field can be excluded from abstract state Field d is assignable and mutable, completely excluded from abstract state set() does not change the abstract state of the object get() can return a mutable Date Can only insert mutable Date s public class Cell { private @Assignable @Mutable Date d; public void set(@Mutable Date d) @ReadOnly { this.d = d; } public @Mutable Date get() @ReadOnly { return d; }

28 28 ‘this’ is mutable inside constructor If field d is this-mutable, then constructor must accept mutable parameter Can’t even construct a Cell without a mutable Date public class Cell { private @ThisMutable Date d; public Cell(@Mutable Date d) { this.d = d; } public void set(@Mutable Date d) @Mutable { this.d = d; } public @RoMaybe Date get() @RoMaybe { return d; }

29 29 Many possibilities can be correct All of the previous annotated classes are valid Javari Will type-check when compiling Cell.java The ‘correct’ set of annotations is that which satisfy the contract that other code requires Closed-world assumption: Know all uses of class If you don’t need to mutate the result of get(), can have every Date in Cell be @ReadOnly If you will only be inserting mutable Date s, can have every Date in Cell be @Mutable

30 30 Can excluding fields from state be inferred? Not likely

31 31 Excluding a field from state can break equals() Field d is assignable and mutable, completely excluded from abstract state Calling a readonly method changes which objects this is equal to public class Cell { private @Assignable @Mutable Date d; public void set(@Mutable Date d) @ReadOnly { this.d = d; } public boolean equals(Object o) { // true iff o is a Cell and this.d.equals(o.d) }

32 32 Can excluding fields from state be inferred? Not likely A feasible heuristic is to exclude fields not used in equals() Debug/log information can be read/modified in equals() Debug/log fields are the ones you can reasonably exclude Might also have variables not read in equals() that can change abstract state Counters decremented every method call that once they timeout, will change part of state A shallow equals() could omit information read in toString() User doesn’t want toString() to return different Strings between calls to readonly methods

33 33 Customizing Javarifier results User could annotate certain fields individually as not being part of the state of the class, and Javarifier can trust those annotations Presently, user can only annotate whole classes (unannotated elements take their default mutability) Can annotate all the methods in a Logger class to be readonly A general framework for specifying user versus inferred annotations is being investigated


Download ppt "Difficult Specifications in Javari Immutability Inference Jaime Quinonez Program Analysis Group April 20, 2007."

Similar presentations


Ads by Google