Difficult Specifications in Javari Immutability Inference Jaime Quinonez Program Analysis Group...

Post on 18-Jan-2016

214 views 0 download

Transcript of Difficult Specifications in Javari Immutability Inference Jaime Quinonez Program Analysis Group...

Difficult Specifications in Javari Immutability Inference

Jaime QuinonezProgram Analysis Group

April 20, 2007

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

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

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

@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

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

@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

@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 DatemuCell.d; // type: @Mutable Date

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 exposuremuCell.get(); // type: @Mutable Date, have rep exposure

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

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

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

Calling methods on fields Create guarded constraint based on field’s typepublic class Cell {

private Date d;

public long get() {return d.getTime();

}

public void reset() {d.setTime(0);

}}

14

Calling methods on fields Create guarded constraint based on field’s typepublic class Cell {

private Date d;

public long get() {return d.getTime();

}

public void reset() {d.setTime(0);

}}

15

Calling methods on fields Create guarded constraint based on field’s typepublic 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

Calling methods on fields Create guarded constraint based on field’s typepublic 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

Calling methods on fields Create guarded constraint based on field’s typepublic 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

Javarifier propagates unguarded constraints Constraints

1. Date.setTime().this is mutable2. Date.getTime().this mutable -> Cell.d mutable3. Date.getTime().this mutable -> Cell.get().this mutable4. Date.setTime().this mutable -> Cell.d mutable5. Date.setTime().this mutable -> Cell.reset().this

mutable1. New Constraints

1. Cell.reset().this is mutable2. Cell.d is mutable

Final unguarded constraints1. Date.setTime().this is mutable2. Cell.reset().this is mutable3. Cell.d is mutable4. All other types are @ReadOnly

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

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

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

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

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 Dates

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

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 Dates

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

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 Dates

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

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 Dates

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

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 Dates

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

‘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

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 Dates, can have

every Date in Cell be @Mutable

30

Can excluding fields from state be inferred?

Not likely

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

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

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