nested refinement types for javascript ravi chugh dissertation defense − september 3, 2013

Post on 13-Dec-2015

219 Views

Category:

Documents

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

Nested RefinementTypes for JavaScript

Ravi Chugh

Dissertation Defense − September 3, 2013

Types for JavaScript

“Dynamic” or UntypedFatures Enable

Rapid Prototyping

2

Types for JavaScript

“Dynamic” or UntypedFatures Enable

Rapid Prototyping

http://stackoverflow.com/tags02-03-13

Count Tag411,345 C#361,080 Java337,896 PHP321,757 JavaScript175,765 C++160,768 Python

83,486 C64,345 Ruby

9,827 Haskell1,347 OCaml

3

Types for JavaScript

“Dynamic” or UntypedFatures Enable

Rapid Prototyping

1. Development Tools2. Reliability & Security

3. Performance

4

5

1. Development Tools

optional “type systems”unsound but provide

some IDE support

6

2. Reliability & Securitylightweight static checkers

run-time invariant checkers

secure language subsets

7

3. Performancefast language subset

to facilitate optimizations

Just-In-Time (JIT) enginesperform static/dynamic analysis to predict types

8

Types for JavaScript

Why So Hard?

9

implicit global object

scope manipulationJavaScript

var lifting

‘,,,’ == new Array(4)

“The Good Parts”

objects

reflection

arrays

eval()*

lambdas

JavaScript

implicit global object

scope manipulation

var lifting

‘,,,’ == new Array(4)

10

“The Good Parts”

objects

reflection

arrays

eval()*

lambdas

JavaScript

11

12Expressiveness

Usability Idioms ofDynamic Languages

Types

VerificationHoare Logics

Model CheckingAbstract Interpretation

Theorem Proving…

+ Logic

Thesis Statement:

“Refinement typescan reason about

dynamic languages to verify the absence of

run-time errors …

13Expressiveness

Usability Idioms ofDynamic Languages

Types

VerificationHoare Logics

Model CheckingAbstract Interpretation

Theorem Proving…

+ Logic

Thesis Statement:

… without resortingto undecidable

logics”

14Expressiveness

Usability Idioms ofDynamic Languages

Types

VerificationHoare Logics

Model CheckingAbstract Interpretation

Theorem Proving…

+ LogicDependent

JavaScript (DJS)[POPL 2012, OOPSLA 2012]

15

OutlineMotivation and Thesis

Challenges of Dynamic LanguagesTour of Dependent JavaScript

Technical ContributionsEvaluation

Looking Ahead

“The Good Parts”

objects

reflection

arrays

eval()*

lambdas

JavaScript

16

Core Technical Challenges

reflection

17

objects

Core Technical Challenges

JavaJavaScript

vs.

18

JavaScriptfunction negate(x) {

if (typeof x == “number”) {

return 0 - x;

} else {

return !x;

} }

run-timetype-test

19

JavaScriptfunction negate(x) {

if (typeof x == “number”) {

return 0 - x;

} else {

return !x;

} }

but booleanon else-branch

x should numbericon then-branch…

20

JavaScriptfunction negate(x) {

if (typeof x == “number”) {

return 0 - x;

} else {

return !x;

} }Java

✗21

Javainterface NumOrBool { NumOrBool negate(); }

class Bool implements NumOrBool { boolean data; Bool(boolean b) { this.data = b; }

Bool negate() { return new Bool(!this.data);} }

class Num implements NumOrBool { … }

declared union type

22

JavaScriptfunction negate(x) {

if (typeof x == “number”) {

} else {

} }Javainterface NumOrBool {

NumOrBool negate(); }

class Bool implements NumOrBool { boolean data; Bool(boolean b) { this.data = b; }

Bool negate() { return new Bool(!this.data);} }

class Num implements NumOrBool { … }

ad-hoc union type

declared union type

23

JavaScript

ML, Haskell a

function negate(x) {

if (typeof x == “number”) {

} else {

} }

24

datatype NumOrBool = | Num (n:number) | Bool (b:boolean)

let negate x = match x with | Num n Num (0 – n) | Bool b Bool (!b)

declared union type

ad-hoc union type

JavaScriptfunction negate(x) {

if (typeof x == “number”) {

} else {

} }

Lightweight Reflection

25

ad-hoc union type

Javaclass Person {

String first; String last;

Person (String s1, String s2) { this.first = s1; this.last = s2; }

void greeting(…) { … }}

var john = new Person(“John”, “McCarthy”);

var s = john.first + “…”;

var john = { “first” : “John”, “last” : “McCarthy”, “greeting” : … };

var s = john.first + “…”;

JavaScript

field names are declared

keys are arbitrary computed strings

26

var john = { “first” : “John”, “last” : “McCarthy”, “greeting” : … };

var s = john.first + “…”;

JavaScript

john[“first”]

obj.f means obj[“f”]

Objects are Dictionaries

27

Javaclass Person {

String first; String last;

Person (String s1, String s2) { this.first = s1; this.last = s2; }

void greeting(…) { … }}

var john = new Person(“John”, “McCarthy”);

var s = john.first + “…”;

Javaclass Person {

String first; String last;

Person (String s1, String s2) { this.first = s1; this.last = s2; }

void greeting(…) { … }}

var john = new Person(“John”, “McCarthy”);

var s = john.first + “…”;

var john = {};

john.first = “John”;john.last = “McCarthy”;john.greeting = …;

JavaScript

incrementally extend object

“sealed” after initialization

28

var john = {};

john.first = “John”;john.last = “McCarthy”;john.greeting = …;

// much later in the codejohn.anotherKey = …;

addMoreKeys(john);

if (…) { addEvenMoreKeys(john);}

JavaScript

Objects are Extensible

29

Javaclass Person {

String first; String last;

Person (String s1, String s2) { this.first = s1; this.last = s2; }

void greeting(…) { … }}

var john = new Person(“John”, “McCarthy”);

var s = john.first + “…”;

Java

30

class Person {

String first; String last;

Person (String s1, String s2) { this.first = s1; this.last = s2; }

void greeting(…) { … }}

var john = new Person(“John”, “McCarthy”);

var s = john.first + “…”;

class TuringWinner extends Person {

int year; TuringWinner (…) { … }}

var twJohn = new TuringWinner(…);

twJohn.greeting();

inherit fromsuperclass

Java

31

class Person {

String first; String name;

Person (String s1, String s2) { this.first = s1; this.last = s2; }

void greeting(…) { … }}

var john = new Person(“John”, “McCarthy”);

...... s = john.first + “…”;

class TuringWinner extends Person {

int year; TuringWinner (…) { … }}

var twJohn = new TuringWinner(…);

twJohn.greeting();

inheritance chaindeclared

JavaScriptvar john = { “first” : “John”, “last” : “McCarthy”, “greeting” : … };

var twJohn = { “year” : 1971, “__proto__” : john};

twJohn.greeting();

inheritance chaincomputed

Objects Inherit from Prototypes

var john = { “first” : “John”, “last” : “McCarthy”, “greeting” : … };

var twJohn = { “year” : 1971, “__proto__” : john};

twJohn.greeting();

JavaScript

32

Objects Inherit from Prototypes

Objects are Extensible

Objects are Dictionaries

Lightweight Reflection

Core Technical Challenges

33

Refinement Types

Dependent JavaScript

(DJS)[POPL ’12, OOPSLA ’12]

C#

✓✓✓✓

✓*✓

✗✗

✗✗✗✗

Java

Haskell

Scala

lightweight reflection

objects are dictionaries

objects are extensible

prototype inheritance

34

35

OutlineMotivation and Thesis

Challenges of Dynamic LanguagesTour of Dependent JavaScript

Technical ContributionsEvaluation

Looking Ahead

36

typeof true // “boolean”

typeof 0.1 // “number”typeof 0 // “number”

typeof {} // “object”typeof [] // “object”typeof null // “object”

37

typeof returns run-time “tags”

Tags are very coarse-grained types

“undefined”

“boolean”

“string”

“number”

“object”

“function”

38

Refinement Types{x|p}

“set of values x s.t. formula p is true”

{n|tag(n) = “number” }Num

{v|tag(v) = “number” ∨ tag(v) = “boolean” }NumOrBool

{i|tag(i) = “number” integer(i) }Int

{x|true }Any

39

{n|tag(n) = “number” }Num

{v|tag(v) = “number” ∨ tag(v) = “boolean” }NumOrBool

{i|tag(i) = “number” integer(i) }Int

{x|true }Any

Syntactic Sugarfor Common Types

Refinement Types

3 :: {n|n = 3}

{n|n > 0} 3 ::{n|tag(n) = “number” integer(n)} 3 ::{n|tag(n) = “number”} 3 ::

Refinement Types

40

{n|n = 3}

{n|n > 0} {n|tag(n) = “number” integer(n)} {n|tag(n) = “number” }

<:...

Subtyping is Implication

Refinement Types

41

{n|n = 3}

{n|n > 0} {n|tag(n) = “number” integer(n)} {n|tag(n) = “number” }

Subtyping is Implication

Refinement Types

42

Refinement Types

SMT Solveror Theorem

Prover

RefinementType

Checker

p q ?

Yes / No

43

Subtyping is Implication

44

Mutable ObjectsDictionary ObjectsTag-Tests Prototypes

45

Mutable ObjectsDictionary ObjectsTag-Tests Prototypes

function negate(x) {

if (typeof x == “number”) {

return 0 - x;

} else {

return !x;

} }

Type Annotation in Comments

//: negate :: (x:NumOrBool) NumOrBool

{v|tag(v) = “number” ∨ tag(v) = “boolean” }

NumOrBool

Syntactic Sugarfor Common Types

46

Mutable ObjectsDictionary ObjectsTag-Tests Prototypes

function negate(x) {

if (typeof x == “number”) {

return 0 - x;

} else {

return !x;

} }

//: negate :: (x:NumOrBool) NumOrBool

{x|tag(x) = “number” }

“expected args”

{x|tag(x) = “number” }

{x|tag(x) = “number” }

{x|tag(x) = “number” }✓

47

Mutable ObjectsDictionary ObjectsTag-Tests Prototypes

function negate(x) {

if (typeof x == “number”) {

return 0 - x;

} else {

return !x;

} }

//: negate :: (x:NumOrBool) NumOrBool

“expected args”

{x|tag(x) = “boolean” }

✓{x|not(tag(x) = “number”)

{x| ∧ (tag(x) = “number” ∨

{x| tag(x) = “boolean”) }

48

Mutable ObjectsDictionary ObjectsTag-Tests Prototypes

function negate(x) {

if (typeof x == “number”) {

return 0 - x;

} else {

return !x;

} }

//: negate :: (x:NumOrBool) NumOrBool ✓

Refinement Types Enable Path Sensitivity

49

Mutable ObjectsDictionary ObjectsTag-Tests Prototypes

function negate(x) {

if (typeof x == “number”) {

return 0 - x;

} else {

return !x;

} }

Output typedepends on input

value

//: negate :: (x:NumOrBool) { y|tag(y) = tag(x) }

50

if (“quack” in duck)

return “Duck says ” + duck.quack();

else

return “This duck can’t quack!”;

What is “Duck Typing”?

Mutable ObjectsTag-Tests Dictionary Objects Prototypes

51

if (“quack” in duck)

return “Duck says ” + duck.quack();

else

return “This duck can’t quack!”;

What is “Duck Typing”?

(+) :: (Num,Num) Num

(+) :: (Str,Str) Str

Mutable ObjectsTag-Tests Dictionary Objects Prototypes

52

if (“quack” in duck)

return “Duck says ” + duck.quack();

else

return “This duck can’t quack!”;

What is “Duck Typing”?

Can dynamically testthe presence of a method

but not its type

Mutable ObjectsTag-Tests Dictionary Objects Prototypes

53

if (“quack” in duck)

return “Duck says ” + duck.quack();

else

return “This duck can’t quack!”;

{d|tag(d) = “object”∧

{v|has(d,“quack”)

{v| sel(d,“quack”) :: ()Str }

Operators from McCarthy theory of arrays

Mutable ObjectsTag-Tests Dictionary Objects Prototypes

54

if (“quack” in duck)

return “Duck says ” + duck.quack();

else

return “This duck can’t quack!”;

{d|tag(d) = “object”∧

{v|has(d,“quack”)

{v| sel(d,“quack”) :: () Str }

Call produces Str, so concat well-typed

Mutable ObjectsTag-Tests Dictionary Objects Prototypes

55

var x = {};

x.f = 7;

x.f + 2;

x0:Empty

x1:{d|d = upd(x0,“f”,7)}

DJS is Flow Sensitive

McCarthy operatorDJS verifies that x.f is definitely a number

Dictionary ObjectsTag-Tests Mutable Objects Prototypes

56

var x = {};

x.f = 7;

x.f + 2;

x0:Empty

x1:{d|d = upd(x0,“f”,7)}

DJS is Flow Sensitive

Strong updates to singleton objects

Weak updates to collections of objects

Dictionary ObjectsTag-Tests Mutable Objects Prototypes

child

parent

...

grandpa

null

Upon construction, each object links to a

prototype object

57

Dictionary ObjectsTag-Tests PrototypesMutable Objects

If child contains k, then Read k from child

Else if parent contains k, then Read k from parent

Else if grandpa contains k, then Read k from grandpa

Else if …

Else Return undefined

child

parent

...

grandpa

null

var k = “first”; child[k];Semantics of Key Lookup

58

Dictionary ObjectsTag-Tests PrototypesMutable Objects

...

child

parent

grandpa

null

H(Rest of Heap)

var k = “first”; child[k];Semantics of Key Lookup

If child contains k, then Read k from child

Else if parent contains k, then Read k from parent

Else if grandpa contains k, then Read k from grandpa

Else if …

Else Return undefined

{v|if has(child,k) then

{v|ifv=sel(child,k)

59

Dictionary ObjectsTag-Tests PrototypesMutable Objects

...

child

parent

grandpa

null

H(Rest of Heap)

var k = “first”; child[k];Semantics of Key Lookup

If child contains k, then Read k from child

Else if parent contains k, then Read k from parent

Else if grandpa contains k, then Read k from grandpa

Else if …

Else Return undefined

{v|if has(child,k) then

{v|ifv=sel(child,k)

{v|else if has(parent,k) then

{v|ifv=sel(parent,k)

60

Dictionary ObjectsTag-Tests PrototypesMutable Objects

If child contains k, then Read k from child

Else if parent contains k, then Read k from parent

Else if grandpa contains k, then Read k from grandpa

Else if …

Else Return undefined

...

{v|if has(child,k) then

{v|ifv=sel(child,k)

{v|else if has(parent,k) then

{v|ifv=sel(parent,k)

child

parent

grandpa ???

null

H(Rest of Heap)

var k = “first”; child[k];Semantics of Key Lookup

61

Dictionary ObjectsTag-Tests PrototypesMutable Objects

...

{v|if has(child,k) then

{v|ifv=sel(child,k)

{v|else if has(parent,k) then

{v|ifv=sel(parent,k)

{v|else

{v|ifv=HeapSel(H,grandpa,k)) }

child

parent

grandpa ???

null

H(Rest of Heap)

var k = “first”; child[k];Semantics of Key Lookup

Abstract predicateto summarize theunknown portion

of the prototype chain

62

Dictionary ObjectsTag-Tests PrototypesMutable Objects

...

{v|if has(child,k) then

{v|ifv=sel(child,k)

{v|else if has(parent,k) then

{v|ifv=sel(parent,k)

{v|else

{v|ifv=HeapSel(H,grandpa,k)) }

{ “first” : “John” }child

parent{ “first” : “Ida”, “last” : “McCarthy” }

grandpa ???

null

H(Rest of Heap)

<:

{v|v=“John”}

var k = “first”; child[k];

63

Dictionary ObjectsTag-Tests PrototypesMutable Objects

...

{v|if has(child,k) then

{v|ifv=sel(child,k)

{v|else if has(parent,k) then

{v|ifv=sel(parent,k)

{v|else

{v|ifv=HeapSel(H,grandpa,k)) }

{ “first” : “John” }child

parent{ “first” : “Ida”, “last” : “McCarthy” }

grandpa ???

null

H(Rest of Heap)

var k = “last”; child[k];

<:

{v|v=“McCarthy”}

64

Dictionary ObjectsTag-Tests PrototypesMutable Objects

Key Idea:

Reduce prototypesemantics to decidable

theory of arrays

Prototype Chain Unrolling

65

Dictionary ObjectsTag-Tests PrototypesMutable Objects

“The Good Parts”

reflection

arrays

eval()*

lambdas

JavaScript

66

objects

✓✓

EXTRA SLIDES

67

OutlineMotivation and Thesis

Challenges of Dynamic LanguagesTour of Dependent JavaScript

Technical ContributionsEvaluation

Looking Ahead

68

lambdasdictionariestag tests

mutation

prototypes

Translation à la Guha et al. (ECOOP 2010)

Dependent JavaScript (DJS)

Our Strategy:

Build an expressive type system forcore language

69

lambdasdictionariestag tests

mutation

prototypes

(POPL 2012)

(OOPSLA 2012)

System D

System !D

System DJS (OOPSLA 2012)

Dependent JavaScript (DJS)Dependent JavaScript (DJS)

70

Prior Refinement Types

TypesT ::= {x:B|p }

| x:T1 T2

| [f1:T1; … ]

| Map[A,B]

| Ref(T)

base type (e.g. Int, Bool, Str)

dependent function type

object type (a.k.a. record, struct)

dictionary type (a.k.a. map, hash table)

reference type (a.k.a. pointer)

Predicates refine only base types

71

PriorRefinement

Types

C#System DJS

✓✓✓✓

✓*✓

✗✗

✗✗✗✗

Java

Haskell

Scala

lightweight reflection

objects are dictionaries

objects are extensible

prototype inheritance

72

JavaScript EncodingsFlow-Sensitive RefinementsNested Refinements

*✓✗✗

objects are dictionaries

objects are extensible

prototype inheritance

✓✓✓

73

Key Challenge:

Function Subtypingas Logical Implication

JavaScript EncodingsFlow-Sensitive RefinementsNested Refinements

74

42 + negate (17)

{f|f :: }(x:Num) Num “expected function”

{f|f :: } (x:NumOrBool) { y|tag(y) = tag(x) }

JavaScript EncodingsFlow-Sensitive RefinementsNested Refinements

{f|f :: }

75

(x:NumOrBool) { y|tag(y) = tag(x) }

{f|f :: }(x:Num) Num

How to Prove

?How to Encode Type System Inside Logic?

Prior Refinement SystemsDisallow Function Types Inside Logic!

JavaScript EncodingsFlow-Sensitive RefinementsNested Refinements

76

T ::= {x|p }

| T1 T2

Types Refinement Logic

Satisfiability Modulo Theories (SMT)

SAT + Decidable Theories

p q✓✗

SMT Solver(e.g. Z3)

[Prior State-of-the-Art]

JavaScript EncodingsFlow-Sensitive RefinementsNested Refinements

77

T ::= {x|p }

| T1 T2

p ::= p ∧ q | p ∨ q | p

| x = y | x > y | …

| tag(x) = “number” | …

| sel(x,k) = 17 | …

Types Refinement Logic

• Boolean Connectives• Equality• Linear Arithmetic• Uninterpreted Functions• McCarthy Arrays

JavaScript EncodingsFlow-Sensitive RefinementsNested Refinements

78

T ::= {x|p }

| T1 T2

p ::= p ∧ q | p ∨ q | p

| x = y | x > y | …

| tag(x) = “number” | …

| sel(x,k) = 17 | …

Types Refinement Logic

{v|tag(v) = “number” ∨ tag(v) = “boolean” }NumOrBool

Enables Union Types and Lightweight Reflection

JavaScript EncodingsFlow-Sensitive RefinementsNested Refinements

79

T ::= {x|p }

| T1 T2

p ::= p ∧ q | p ∨ q | p

| x = y | x > y | …

| tag(x) = “number” | …

| sel(x,k) = 17 | …

Types Refinement Logic

Enables Dictionary Types with Dynamic Keys …{d|tag(sel(d,k)) = “boolean” ∧

{d|tag(sel(d,“f”)) = “function” ∧

{d|sel(d,“f”) ??? }

But DisallowsFunctions inDictionaries!

JavaScript EncodingsFlow-Sensitive RefinementsNested Refinements

80

p ::= p ∧ q | p ∨ q | p

| x = y | x > y | …

| tag(x) = “number” | …

| sel(x,k) = 17 | …

| sel(x,k) :: T1 T2 | …

Types Refinement Logic

Goal: Refer to Type System Inside LogicGoal: Without Giving up Decidability

T ::= {x|p }

| T1 T2

Solution: Nested Refinements!

JavaScript EncodingsFlow-Sensitive RefinementsNested Refinements

81

T ::= {x|p } p ::= p ∧ q | p ∨ q | p

| x = y | x > y | …

| tag(x) = “number” | …

| sel(x,k) = 17 | …

| sel(x,k) :: T1 T2 | …

Nested Refinements [POPL ’12]1. Decidable Encoding2. Precise Subtyping3. Type Soundness Proof

Types Refinement LogicJavaScript EncodingsFlow-Sensitive RefinementsNested Refinements

82

{f|f :: } (x:NumOrBool) { y|tag(y) = tag(x) }

{f|f :: }(x:Num) Num

Decidable Encoding

Uninterpreted Predicate in Logic

Distinct UninterpretedConstants in Logic…

JavaScript EncodingsFlow-Sensitive RefinementsNested Refinements

{f|f :: }

83

(x:NumOrBool) { y|tag(y) = tag(x) }

{f|f :: }(x:Num) Num

Decidable Encoding

Uninterpreted Predicate in Logic

w/ Types Nested Inside

Distinct UninterpretedConstants in Logic…

JavaScript EncodingsFlow-Sensitive RefinementsNested Refinements

84

Decidable Encoding

{f|f :: } (x:NumOrBool) { y|tag(y) = tag(x) }

{f|f :: }(x:Num) Num

✗SMTSolver

Trivially Decidable, but Imprecise

JavaScript EncodingsFlow-Sensitive RefinementsNested Refinements

85

p f :: (x:S1) S2

{f|f :: }(x:T1) T2

{f|p }

Precise Subtyping

Step 1:

Step 2:

Find such that(x:S1) S2

SMTSolver✓

T1 S1 ✓✓S2 T2x:T1

Compare and(x:S1) S2 (x:T1) T2

“contra-variance”

“co-variance”

JavaScript EncodingsFlow-Sensitive RefinementsNested Refinements

86

{f|f :: }(x:Num) Num{f|f = negate }

Precise Subtyping

Step 1:

Step 2:

f = negate

f :: (x:NumOrBool) { y|tag(y) = tag(x) }SMTSolver✓

JavaScript EncodingsFlow-Sensitive RefinementsNested Refinements

87

{f|f :: }(x:Num) Num{f|f = negate }

Precise Subtyping

Step 1:

Step 2:

f = negate

f :: (x:NumOrBool) { y|tag(y) = tag(x) }

Num

NumOrBool ✓✓{y|tag(y) = tag(x) } Nu

mx:Num

✓SMT

Solver✓

JavaScript EncodingsFlow-Sensitive RefinementsNested Refinements

88

Precise Subtyping

Step 1:

Step 2:

Decidable Reasoningvia SMT

Precise Function Subtypingvia Syntactic Techniques

+

{f|f :: }{f|f = negate } ✓(x:Num) Num

JavaScript EncodingsFlow-Sensitive RefinementsNested Refinements

89

Type Soundness Proof

Logic 0

Conventional ProofsRequire Logic to be an Oracle …

… but Nesting Introduces CircularityThat Prevents Typical Inductive Proofs

Type System 0

JavaScript EncodingsFlow-Sensitive RefinementsNested Refinements

90

Type System ∞

Type Soundness Proof

Logic 0

Logic 1

Logic 2

Type System 1

Type System 2

Type System 0

… …

Proof Technique:Stratify into Infinite Hierarchy

JavaScript EncodingsFlow-Sensitive RefinementsNested Refinements

91

Key to Encode Dictionary Objects(Even in Statically Typed Languages!)

T ::= {x|p } p ::= p ∧ q | p ∨ q | p

| x = y | x > y | …

| tag(x) = “number” | …

| sel(x,k) = 17 | …

| sel(x,k) :: T1 T2 | …

Nested Refinements [POPL ’12]

Types Refinement LogicJavaScript EncodingsFlow-Sensitive RefinementsNested Refinements

92

JavaScript EncodingsFlow-Sensitive RefinementsNested Refinements

var x = {};

x.f = 7;

x.f + 2;

let x = new {} in

(*x).f = 7;

(*x).f + 2;

Allocates ptr x :: Ref(Dict)

Heap update doesn’t affect type

So key lookup doesn’t type check!

Key Issue:

“Invariant”Reference Types

93

JavaScript EncodingsFlow-Sensitive RefinementsNested Refinements

let x = new {} in

(*x).f = 7;

(*x).f + 2;

Lx |-> d0:{d|d =empty}

Lx |-> d1:{d|d = upd(d0,“f”,7)}

Allocates heap location Lx and x :: Ref(Lx)

Type of pointer doesn’t change …

But types of heap locations can!

94

JavaScript EncodingsFlow-Sensitive RefinementsNested Refinements

x:T1 / h1 T2 / h2

outputtype

inputtype

95

JavaScript EncodingsFlow-Sensitive RefinementsNested Refinements

x:T1 / h1 T2 / h2

outputtype

inputtype

inputheap

outputheap

96

JavaScript EncodingsFlow-Sensitive RefinementsNested Refinements

x:T1 / h1 T2 / h2

Our Formulation Extends:

Alias Types (Smith et al., ESOP 2000)syntactic types for higher-order programs

Low-Level Liquid Types (Rondon et al., POPL 2010)refinement types for first-order programs

97

JavaScript EncodingsFlow-Sensitive RefinementsNested Refinements

let swap (x, y) =

let tmp = *x in

*x = *y;

*y = tmp in …

//: swap :: (x:Ref(Lx), y:Ref(Ly))

//: / H + (Lx |-> a:Any) + (Ly |-> b:Any)

//: Void//: / H + (Lx |-> a’:Any{a’= b})

//: + (Ly |-> b’:Any{b’= a})

98

JavaScript EncodingsFlow-Sensitive RefinementsNested Refinements

//: getKey :: (x:Ref(Lx), k:Str)

//: / H + (Lx |-> d:Dict > Lx’)

//: { y | if has(d,k)//: then y = sel(d, k)//: else y = HeapHas(H, Lx’, k)}

//: / H + (Lx |-> d’:Dict{d’= d} > Lx’)

Prototype Inheritance

x[k] getKey(*x, k)

99

JavaScript EncodingsFlow-Sensitive RefinementsNested Refinements

Primitive Operators(Avoid Implicit Coercion)

JavaScript Arrays(Several Unusual Issues)

Prototype Inheritance

100

OutlineMotivation and Thesis

Challenges of Dynamic LanguagesTour of Dependent JavaScript

Technical ContributionsEvaluation

Looking Ahead

101

313a

421(+35%)

LOCbefore/after

14 Excerpts from: JavaScript, Good Parts SunSpider Benchmark Suite Google Closure Library

Benchmarks

Chosen to Stretch the Limits of DJS

102

313a

421(+35%)

LOCbefore/after

14 Excerpts from: JavaScript, Good Parts SunSpider Benchmark Suite Google Closure Library

Benchmarks

9 Browser Extensions from: [Guha et al. Oakland ’11]

321a

383(+19%)

1,003a

1,027(+2%)

2 Examples from: Google Gadgets

1,637

1,831(+12%)

TOTALS

103

LOCbefore/after

14 Excerpts from: JavaScript, Good Parts SunSpider Benchmark Suite Google Closure Library

313a

421(+35%)

Benchmarks

9 Browser Extensions from: [Guha et al. Oakland ’11]

321a

383(+19%)

2 Examples from: Google Gadgets

1,003a

1,027(+2%)

1,637

1,831(+12%)

11 sec

Running Time

3 sec

19 sec

33 sec

TOTALS

1,831(+12%)

33 sec

>>> Skip Optimizations >>>

104

Reducing Annotation Burden• Bidirectional (local) type inference– Several aspects unique to this setting

• Optional var declaration invariants– Auto add to types of subsequent closures

var i /*: Int */ = 0;

//: f :: T1 / H1 + (Li |-> i1:Int)

//: T2 / H2 + (Li |-> i2:Int)

var f(…) { … i … }

function refers to mutable variable i, so heaps must describe

the location

105

Reducing Annotation Burden• Bidirectional (local) type inference– Several aspects unique to this setting

• Optional var declaration invariants– Auto add to types of subsequent closures

var i /*: Int */ = 0;

//: f :: T1 / H1

//: T2 / H2

var f(…) { … i … }

copy the annotation, if any

106

Reducing Annotation Burden• Bidirectional (local) type inference– Several aspects unique to this setting

• Optional var declaration invariants– Auto add to types of subsequent closures

var i /*: Int */ = 0;

//: f :: T1 / H1 + (Li |-> i1:Int)

//: T2 / H2 + (Li |-> i2:Int)

var f(…) { … i … }

copy the annotation, if any

107

Reducing Annotation Burden• Bidirectional (local) type inference– Several aspects unique to this setting

• Optional var declaration invariants– Auto add to types of subsequent closures

no annotation means “do not modify”var i = 0;

//: f :: T1 / H1 + (Li |-> i1:{x | x = 0})

//: T2 / H2 + (Li |-> i2:{x | x = 0})

var f(…) { … i … }

108

Improving Performance

17 :: {x:Int|x = 17 }

if b then “hi” else 17 :: {x|b = true x = “hi”

if b then 17 else “hi” :: {x∧b = false x = 17 }

track syntactic types for specialized cases …

… fall back on refinement types for general case

• Avoid making SMT queries when possible

109

Improving Performance• Can reduce precision for if-expressions

var n = 0;

if (b) {

n = n + 1;

else {

n = n + 2;

} Ln |-> m:{ x | b = true x = 1Ln |-> m: {x ∧ b = false x = 2 }

“exact joins” by default …

… annotation on var triggers “inexact joins”

110

Improving Performance• Can reduce precision for if-expressions

var n /*: Int */ = 0;

if (b) {

n = n + 1;

else {

n = n + 2;

}

Ln |-> m:Int

“exact joins” by default …

… annotation on var triggers “inexact joins”

111

Plenty of Room for Improvement

1,637

TOTALS

33 sec

1,831(+12%)

Relatively Modest OptimizationsHave Made Significant Impact

112

OutlineMotivation and Thesis

Challenges of Dynamic LanguagesTour of Dependent JavaScript

Technical ContributionsEvaluation

Looking Ahead

113

Immediate Directions• Type Soundness– proven for System D, but not for !D or DJS

• Expressiveness– e.g. mutual recursion, recursion through heap

• Usability– annotation burden, performance, error messages

• Integration with Run-Time Contracts– invariants before and after eval()

114

Expressiveness

Usability

Verification

Dependent JavaScript (DJS)

TypeScriptLightweight (unsound) static checking tools becoming popular

Translate for additional checking

and IDE support

“Gradual Gradual Typing”

115

Way Behind Tools for Java, etc.

• Static Types in DJS Enable Refactoring,• Documentation Tools, Code Completion

• Web-Based Interfaces to Collect Statistics• about Programming Patterns, Errors

Web Development Tools

116

candidateannotations

User or

Test Cases or

Heuristics

Iterative InferenceGlobal inference (e.g. via Liquid Types) would be nice,but no basic type structure to start with

unannotatedprogram

Verification Condition

Generation

Coarsen Types

117

Browser Extension Security

Security =Refinement

Type Checkingà la Swamy et al. (ESOP 2010)

and Guha et al. (Oakland 2011)

Dependent JavaScript (DJS)

Third-PartyCode

Policy

Browser APIs

Secure Reference Monitorvia Refinements

118

Thanks!

Nested Refinements +Dependent JavaScript

Ranjit JhalaPat Rondon

Dave HermanPanos Vekris

OtherProjects

Sorin LernerJan Voung

Jeff MeisterNikhil Swamy

Juan Chen

119

EXTRA SLIDES

“The Good Parts”

reflection

arrays

eval()*

lambdas

JavaScript

120

objects

121

var nums = [0,1,2];while (…) { nums[nums.length] = 17;}

A finite tuple…

… extended to unbounded collection

122

var nums = [0,1,2];while (…) { nums[nums.length] = 17;}

delete nums[1];

for (i = 0; i < nums.length; i++) { sum += nums[i];}

A “hole” in the array

Missing element within “length”

123

Track types, “packedness,” and lengthof arrays where possible

{a |a :: Arr(T)

{a | packed(a)

{a | len(a) = 10}

X T T T T… X ……

T? T? T? T? T?… T? ……

T? { x | T(x) x = undefined }

-1 0 1 2 len(a)

X { x | x = undefined }

124

{a |a :: Arr(Any)

{a | packed(a) len(a) = 2

{a | Int(sel(a,0))

{a | Str(sel(a,1))}

Encode tuples as arrays

var tup = [17, “cacti”];

125

var tup = [17, “cacti”];

tup[tup.length] = true;

{a |a :: Arr(Any)

{a | packed(a) len(a) = 3

{a | …}

“The Good Parts”

reflection

arrays

eval()*

lambdas

JavaScript

126

objects

127

What About eval?

Arbitrary code loading

eval(“…”);

Old Types

128

What About eval?

eval(“…”);

//: #assume

Old Types

New TypesNew Types

Future Work: Integrate DJS with“Contract Checking” at Run-time

aka “Gradual Typing”

129Expressiveness

Usability Idioms ofDynamic Languages

VerificationHoare Logics

Model CheckingAbstract Interpretation

Theorem Proving…

130

Function Subtyping…{d|sel(d,“f”) :: }

(x:Any) { y|y = x }{d|sel(d,“f”) :: }(x:Num) Num<:

Higher-Order Refinements

131

Function Subtyping…

{d|sel(d,“f”) :: }(x:Num) Num

{d|sel(d,“f”) :: } (x:Any) { y|y = x }

Higher-Order Refinements

132

Function Subtyping…

{d|sel(d,“”)f :: }(x:Num) Num

{d|sel(d,“ ”f :: } (x:Any) { y|y = x }

… With Quantifiers∀x,y. true ∧ y = f(x) y = x

∀x,y. Num(x) ∧ y = f(x) Num(y)✓Valid, but First-Order Logic is Undecidable

Higher-Order Refinements

133

Heap Updates…

… With Quantifiers

var x = {};

x.f = 7;h1

h2

h0

∧ …

∧ sel(h1,x) = empty∧ ∀y. x ≠ y sel(h1,y) = sel(h0,y)

∧ sel(h2,x) = upd(sel(h1,x),“f”,7)∧ ∀y. x ≠ y sel(h2,y) = sel(h1,y)

Encode Heap w/ McCarthy Operators

Higher-Order Refinements

134

Subtyping with Nesting

e.g. tag(x) = tag(y)

e.g. tag(sel(d,k)) = “number”

1) Convert q to CNF clauses (q11 … ) … (qn1 … )

2) For each clause, discharge some literal qij as follows:

base predicate: p qij

anything except HasType(x,U)

135

Subtyping with Nesting

Implication

SMT Solver

Subtyping Arrow Rule

base predicate: p qij p x :: U

Implication

SMT Solver

Subtyping

p x :: U’

U’ <: U

p qij

1) Convert q to CNF clauses (q11 … ) … (qn1 … )

2) For each clause, discharge some literal qij as follows:

136

Type Soundness with Nesting

137

0 :: {|x.x+1:: IntInt }_|

x.x+1 :: {|:: IntInt }_|

f:{|:: IntInt }0 :: {|f:: IntInt }_|

SubstitutionLemma

_| v :: TxandIf x:Tx, Γ e[:: T_|

Γ[v/x] e[v/x] :: T[v/x]_|then

independent of 0, and just echoes the binding from the environment

138

0 :: {|x.x+1:: IntInt }_|

SMT =0 x.x+1:: IntInt✗{|=0 } < {|x.x+1:: IntInt }0 :: {|=0 }

SubstitutionLemma

_| v :: TxandIf x:Tx, Γ e[:: T_|

Γ[v/x] e[v/x] :: T[v/x]_|then

1st attempt

139

0 :: {|x.x+1:: IntInt }_|

{|=0 } < {|x.x+1:: IntInt }0 :: {|=0 }

SubstitutionLemma

_| v :: TxandIf x:Tx, Γ e[:: T_|

Γ[v/x] e[v/x] :: T[v/x]_|then✗SMT =0 :: U’

Arrow U’ <: IntInt

+2nd attempt✗

140

x.x+1:: IntInt|=I

x.x+1:: {|:: IntInt }|_

SMT Γ p q

Γ {|=p } < {|=q }_|

[S-Valid-Uninterpreted]

|=I Γ p q

Γ {|=p } < {|=q }_|

[S-Valid-Interpreted]

iff

• Rule not closed under substitution

• Interpret formulas by “hooking back” into type system

• Stratification to create ordering for induction

n

n-1

n

n

141

Type Soundness with NestingStratifiedSubstitutionLemma

_| v :: TxandIf x:Tx, Γ e[:: T_|

Γ[v/x] e[v/x] :: T[v/x]_|then n+1

n

n

StratifiedPreservation

e vandIf e[:: T_| 0

_|then v[:: Tm for some m

“Level 0” for type checking source programs,using only [S-Valid-Uninterpreted]

artifact of the metatheory

142

</Ph.D.>

top related