50
Javari: Java Reference Immutability Language and Inference Tool Jaime Quinonez November 14, 2006

Javari: Java Reference Immutability Language and Inference Tool

Embed Size (px)

DESCRIPTION

Javari: Java Reference Immutability Language and Inference Tool. Jaime Quinonez November 14, 2006. Reference Immutability. @ReadOnly on a type specifies a reference that cannot be used to modify an object @ReadOnly can annotate any use of a type - PowerPoint PPT Presentation

Citation preview

Page 1: Javari: Java Reference Immutability Language and Inference Tool

Javari: Java Reference Immutability Language and Inference Tool

Jaime QuinonezNovember 14, 2006

Page 2: Javari: Java Reference Immutability Language and Inference Tool

2

Reference Immutability

@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

T can be used anywhere @ReadOnly T is expected

@ReadOnly T cannot be used where T is expected

Page 3: Javari: Java Reference Immutability Language and Inference Tool

3

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;}

}

Page 4: Javari: Java Reference Immutability Language and Inference Tool

4

@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;}

}

Page 5: Javari: Java Reference Immutability Language and Inference Tool

5

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;

}}

Page 6: Javari: Java Reference Immutability Language and Inference Tool

6

@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;

}}

Page 7: Javari: Java Reference Immutability Language and Inference Tool

7

@ReadOnly on generic types

ArrayList<@ReadOnly Date> list; list is a mutable ArrayList

Contains immutable references to Dates The list can be mutated

list.get(0) - legal list.clear() - legal

Elements in the list cannot be mutated Return type of list.get() is @ReadOnly Date list.get(0).getTime() - legal list.get(0).setTime(2) - illegal @ReadOnly Date d = list.get(0) - legal Date d = list.get(0) - illegal

Page 8: Javari: Java Reference Immutability Language and Inference Tool

8

@ReadOnly doesn’t propagate to generics

@ReadOnly ArrayList<Date> list; list is an immutable ArrayList

Contains mutable references to Dates The list cannot be mutated

list.get(0) - legal list.clear() - illegal

Elements in the list can be mutated Return type of list.get() is Date list.get(0).getTime() - legal list.get(0).setTime(2) - legal @ReadOnly Date d = list.get(0) - legal Date d = list.get(0) - legal

Page 9: Javari: Java Reference Immutability Language and Inference Tool

9

Need to add @ReadOnly annotations

Date is an existing class Date.getTime() and Date.setTime() are not

annotated Javari defaults method receiver to mutable

unless @ReadOnly is specified It is tedious and error-prone for humans to

infer these annotations Need a tool to infer reference immutability

in existing code

Page 10: Javari: Java Reference Immutability Language and Inference Tool

10

@ReadOnly methods do not mutate fields

Given unannotated class file:

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;}

}

Page 11: Javari: Java Reference Immutability Language and Inference Tool

11

@ReadOnly methods do not mutate fields

Modify class file to contain appropriate @ReadOnly annotations:

public class Date {private long time;

public Date(long time) {this.time = time

}public void setTime(long time) {

this.time = time;}public long getTime() @ReadOnly {

return time;}

}

Page 12: Javari: Java Reference Immutability Language and Inference Tool

12

Type Inference Algorithm

Flow-insensitive and context-insensitive Generate a set of mutability constraints

Unguarded constraint states unconditional mutability

x = new Object(); “x is mutable”

Guarded constraint states conditional mutability y.x(); “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

Page 13: Javari: Java Reference Immutability Language and Inference Tool

13

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;}

}

Page 14: Javari: Java Reference Immutability Language and Inference Tool

14

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

Page 15: Javari: Java Reference Immutability Language and Inference Tool

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);

}}

Page 16: Javari: Java Reference Immutability Language and Inference Tool

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);

}}

Page 17: Javari: Java Reference Immutability Language and Inference Tool

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

Page 18: Javari: Java Reference Immutability Language and Inference Tool

18

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

Page 19: Javari: Java Reference Immutability Language and Inference Tool

19

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

Page 20: Javari: Java Reference Immutability Language and Inference Tool

20

Javarifier propagates unguarded constraints

Constraints1. 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

mutable

Page 21: Javari: Java Reference Immutability Language and Inference Tool

21

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.d is mutable

Page 22: Javari: Java Reference Immutability Language and Inference Tool

22

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.d is mutable2. Cell.reset().this is mutable

Page 23: Javari: Java Reference Immutability Language and Inference Tool

23

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

Page 24: Javari: Java Reference Immutability Language and Inference Tool

24

Parameters assigned to fields

Field mutability guards parameter mutability

public class Cell {private Date d;

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

}

public void setDate(Date newDate) {this.d = newDate;

}}

Page 25: Javari: Java Reference Immutability Language and Inference Tool

25

Parameters assigned to fields

Field mutability guards parameter mutability

public class Cell {private Date d;

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

}

public void setDate(Date newDate) {this.d = newDate;

}}

Page 26: Javari: Java Reference Immutability Language and Inference Tool

26

Parameters assigned to fields

Field mutability guards parameter mutability

public class Cell {private Date d;

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

}

public void setDate(Date newDate) {this.d = newDate;

}} Date.getTime().this mutable -> Cell.d mutable Date.getTime().this mutable -> Cell.getTime().this mutable

Page 27: Javari: Java Reference Immutability Language and Inference Tool

27

Parameters assigned to fields

Field mutability guards parameter mutability

public class Cell {private Date d;

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

}

public void setDate(Date newDate) {this.d = newDate;

}} Date.getTime().this mutable -> Cell.d mutable Date.getTime().this mutable -> Cell.getTime().this mutable

Page 28: Javari: Java Reference Immutability Language and Inference Tool

28

Parameters assigned to fields

Field mutability guards parameter mutability

public class Cell {private Date d;

public long getTime() {return this.d.getTime();}

public void setDate(Date newDate) {this.d = newDate;}

} Date.getTime().this mutable -> Cell.d mutable Date.getTime().this mutable -> Cell.getTime().this mutable Cell.setDate().this is mutable Cell.d mutable -> Cell.setDate().param:newDate mutable

Page 29: Javari: Java Reference Immutability Language and Inference Tool

29

Parameters assigned to fields

Field mutability guards parameter mutability

public class Cell {private Date d;

public long getTime() {return this.d.getTime();}

public void setDate(Date newDate) {this.d = newDate;}

} Date.getTime().this mutable -> Cell.d mutable Date.getTime().this mutable -> Cell.getTime().this mutable Cell.setDate().this is mutable Cell.d mutable -> Cell.setDate().param:newDate mutable

Page 30: Javari: Java Reference Immutability Language and Inference Tool

30

Javarifier propagates unguarded constraints

Constraintsn Date.setTime().this is mutablen Date.getTime().this mutable -> Cell.d mutablen Date.getTime().this mutable -> Cell.getTime().this

mutablen Cell.setDate().this is mutablen Cell.d mutable -> Cell.setDate().param:newDate is

mutable

Page 31: Javari: Java Reference Immutability Language and Inference Tool

31

Javarifier propagates unguarded constraints

Constraintsn Date.setTime().this is mutablen Date.getTime().this mutable -> Cell.d mutablen Date.getTime().this mutable -> Cell.getTime().this

mutablen Cell.setDate().this is mutablen Cell.d mutable -> Cell.setDate().param:newDate is

mutable1. No guards can be satisfied2. Finished with two unguarded constraints:

1. Date.setTime().this is mutable2. Cell.setDate().this is mutable3. All other types are @ReadOnly

Page 32: Javari: Java Reference Immutability Language and Inference Tool

32

Generic types have same inference

Place constraints on upper and lower boundpublic class Cell<T extends Date super SubDate> {

T t;

public void set(T t) { this.t = t; }

public void reset() { this.t.setTime(0); }

}

public class SubDate extends Date {

public void setTime(long time) { this.time = time; }

}

Page 33: Javari: Java Reference Immutability Language and Inference Tool

33

Generic types have same inference

Place constraints on upper and lower boundpublic class Cell<T extends Date super SubDate> {

T t;public void set(T t) { this.t = t; }public void reset() { this.t.setTime(0); }

}public class SubDate extends Date {

public void setTime(long time) { this.time = time; }} Cell.set().this is mutable

Page 34: Javari: Java Reference Immutability Language and Inference Tool

34

Generic types have same inference

Place constraints on upper and lower boundpublic class Cell<T extends Date super SubDate> {

T t;public void set(T t) { this.t = t; }public void reset() { this.t.setTime(0); }

}public class SubDate extends Date {

public void setTime(long time) { this.time = time; }} Cell.set().this is mutable Cell.t mutable -> Cell.set().param:t mutable

Page 35: Javari: Java Reference Immutability Language and Inference Tool

35

Generic types have same inference

Place constraints on upper and lower boundpublic class Cell<T extends Date super SubDate> {

T t;public void set(T t) { this.t = t; }public void reset() { this.t.setTime(0); }

}public class SubDate extends Date {

public void setTime(long time) { this.time = time; }} Cell.set().this is mutable Cell.t mutable -> Cell.set().param:t mutable Date.setTime().this mutable -> Cell.t mutable

Page 36: Javari: Java Reference Immutability Language and Inference Tool

36

Generic types have same inference

Place constraints on upper and lower boundpublic class Cell<T extends Date super SubDate> {

T t;public void set(T t) { this.t = t; }public void reset() { this.t.setTime(0); }

}public class SubDate extends Date {

public void setTime(long time) { this.time = time; }} Cell.set().this is mutable Cell.t mutable -> Cell.set().param:t mutable Date.setTime().this mutable -> Cell.t mutable Date.setTime().this mutable -> Cell.reset().this mutable

Page 37: Javari: Java Reference Immutability Language and Inference Tool

37

Generic types have same inference

Place constraints on upper and lower boundpublic class Cell<T extends Date super SubDate> {

T t;public void set(T t) { this.t = t; }public void reset() { this.t.setTime(0); }

}public class SubDate extends Date {

public void setTime(long time) { this.time = time; }} Cell.set().this is mutable Cell.t mutable -> Cell.set().param:t mutable Date.setTime().this mutable -> Cell.t mutable Date.setTime().this mutable -> Cell.reset().this mutable SubDate.setTime().this mutable -> Date.setTime().this

mutable Subtype can only be mutable if supertype is mutable

Page 38: Javari: Java Reference Immutability Language and Inference Tool

38

Javarifier propagates unguarded constraints

Constraints1. Date.setTime().this is mutable2. SubDate.setTime().this is mutable3. Cell.set().this is mutable4. Cell.t mutable -> Cell.set().param:t mutable5. Date.setTime().this mutable -> Cell.t mutable6. Date.setTime().this mutable -> Cell.reset().this

mutable7. SubDate.setTime().this mutable -> Date.setTime().this

mutable

Page 39: Javari: Java Reference Immutability Language and Inference Tool

39

Javarifier propagates unguarded constraints

Constraints1. Date.setTime().this is mutable2. SubDate.setTime().this is mutable3. Cell.set().this is mutable4. Cell.t mutable -> Cell.set().param:t mutable5. Date.setTime().this mutable -> Cell.t mutable6. Date.setTime().this mutable -> Cell.reset() mutable7. SubDate.setTime().this mutable -> Date.setTime().this

mutable1. New Constraints

1. Cell.t is mutable

Page 40: Javari: Java Reference Immutability Language and Inference Tool

40

Javarifier propagates unguarded constraints

Constraints1. Date.setTime().this is mutable2. SubDate.setTime().this is mutable3. Cell.set().this is mutable4. Cell.t mutable -> Cell.set().param:t mutable5. Date.setTime().this mutable -> Cell.t mutable6. Date.setTime().this mutable -> Cell.reset().this

mutable7. SubDate.setTime().this mutable -> Date.setTime().this

mutable1. New Constraints

1. Cell.t is mutable2. Cell.reset() is mutable

Page 41: Javari: Java Reference Immutability Language and Inference Tool

41

Javarifier propagates unguarded constraints

Constraints1. Date.setTime().this is mutable2. SubDate.setTime().this is mutable3. Cell.set().this is mutable4. Cell.t mutable -> Cell.set().param:t mutable5. Date.setTime().this mutable -> Cell.t mutable6. Date.setTime().this mutable -> Cell.reset().this

mutable7. SubDate.setTime().this mutable -> Date.setTime().this

mutable1. New Constraints

n Cell.t is mutablen Cell.reset() is mutablen Cell.set().param:t is mutable

Page 42: Javari: Java Reference Immutability Language and Inference Tool

42

Javarifier propagates unguarded constraints

Constraints1. Date.setTime().this is mutable2. SubDate.setTime().this is mutable3. Cell.set().this is mutable4. Cell.t mutable -> Cell.set().param:t mutable5. Date.setTime().this mutable -> Cell.t mutable6. Date.setTime().this mutable -> Cell.reset().this

mutable7. SubDate.setTime().this mutable -> Date.setTime().this

mutable1. New Constraints

1. Cell.t is mutable2. Cell.reset() is mutable3. Cell.set().param:t is mutable

2. No references can be marked @ReadOnly

Page 43: Javari: Java Reference Immutability Language and Inference Tool

43

Case study of Javarifier on scene library

6935 lines of code 1008 annotatable slots Hand-annotated by original author Matt McCutchen 126 annotations disagree with Javarifier results

5 differences due to bugs in Javarifier code 121 differences due to programmer error Type-checker would have caught most of the programmer's

errors

Page 44: Javari: Java Reference Immutability Language and Inference Tool

44

Javarifier inserts @ReadOnly wherever legal

Mutable is more restricting than @ReadOnly on a receiver

If code that uses a method is type-safe when the method has a @Mutable receiver, it is type-safe with a @ReadOnly receiver

Two viewpoints Programmers interpretation of Javari:

@Mutable is legal Javarifier: both @ReadOnly and @Mutable

satisfy constraints, so use @ReadOnly Javarifier finds mutations, propagates

mutable restriction, then assigns everything else @ReadOnly

Page 45: Javari: Java Reference Immutability Language and Inference Tool

45

Some specifications cannot be inferred

VivifyingMap<K,V> implements Map<K,V>

get(K k) returns the value that k is mapped to If k isn’t mapped to a value, adds mapping from k to a new “empty” value, and returns that value

prune() removes all mappings from keys to “empty” values

Abstract state of a VivifyingMap is the set of mappings (possibly to empty values)

The result of keySet() is in the abstract state Both get() and prune() modify abstract state

Page 46: Javari: Java Reference Immutability Language and Inference Tool

46

Abstract methods have no body to analyze

public abstract class VivifyingMap<K,V> extends HashMap<K,V> {

// Removes all mappings to empty values// Modifies receiver

public void prune() {// for each key in map:if(checkEmpty(super.getValue(key))) {

super.remove(key)}

}// Returns whether the parameter is empty// Modifies receiver

public abstract boolean checkEmpty(V v);}

Page 47: Javari: Java Reference Immutability Language and Inference Tool

47

Javarifier infers @ReadOnly on abstract methods

public abstract class VivifyingMap<@ReadOnly K, @ReadOnly V>extends HashMap<@ReadOnly K, @ReadOnly V> {

// prune() not @ReadOnly

public void prune() { … }

public abstract boolean checkEmpty(@ReadOnly V v) @ReadOnly;

}

checkEmpty() annotated as @ReadOnly No evidence that method modifies v Violates programmer specification

Page 48: Javari: Java Reference Immutability Language and Inference Tool

48

Valid subtype can cause Javarifier conflict

public class NamedMaps<K, V> extends VivifyingMap<String,VivifyingMap<K,V>> {

public boolean checkEmpty(VivifyingMap<K,V> vm) {

vm.prune();

return vm.keySet().isEmpty();

}

} checkEmpty() modifies parameter

Calls prune() on parameter Meets programmer specification of

VivifyingMap.checkEmpty() Javarifier does not annotate parameter as @ReadOnly

Page 49: Javari: Java Reference Immutability Language and Inference Tool

49

Javarifier can violate programmer’s specification

(abstract) VivifyingMap.checkEmpty(V v) Programmer: v modifiable Javari: @ReadOnly v

NamedMaps.checkEmpty(V v) Programmer: v modifiable Javari: v modifiable

Programmer of NamedMaps met programmer specification of VivifyingMap

In Javarifier’s specification, NamedMaps not a true subtype of VivifyingMap

Javarifier can’t infer programmer’s specification of abstract method without some implementation

Page 50: Javari: Java Reference Immutability Language and Inference Tool

50

Javarifier infers legal annotations

Javarifier is able to analyze code and infer reference immutability

Javarifier does not ensure consistency when classes are analyzed separately

Javarifier cannot truly capture programmer’s intent when this intent does not manifest itself in code

Sometimes formal specification comes from programmer intent and not necessarily code

Most errors in annotating a specification are simple errors that would be caught by a type-checker