270 likes | 388 Views
CS 294-8 The Spec Language http://www.cs.berkeley.edu/~yelick/294. OLD SLIDES FROM LAST TIME. Overview of SPEC. SPEC is a language for writing specifications and “implementations” Like a conventional programming language: extended with nondeterministic constructs
E N D
CS 294-8The Spec Languagehttp://www.cs.berkeley.edu/~yelick/294
Overview of SPEC • SPEC is a language for writing specifications and “implementations” • Like a conventional programming language: • extended with nondeterministic constructs • high level notation for sets, etc. • not constrained by efficiency concerns • Syntax strongly influenced by Modula 3 • Module structure and some syntax • Might use different syntax for Java, C++, … • Semantics influenced by Dijkstra’s guarded command language and Nelson’s extension
Example: Topological Sort Spec MODULE TopologicalSort EXPORT V, G, Q, TopSort = TYPE V = IN 0 .. n G = (V,V) -> Bool Q = SEQ V PROC TopSort (g) -> Q RAISES {cyclic} = … FUNC IsTSorted(q, g) -> Bool = … END TopologicalSort
Example: Topological Sort Spec PROC TopSort (g) -> Q RAISES {cyclic} = IF VAR q | q IN (0 .. n).perms /\ IsTSorted(q,g) => RET q [*] RAISE cyclic FI FUNC IsTSorted(q, g) -> Bool = RET ~ (EXISTS v1 :IN q.dom, v2 :IN q.dom | v2 < v1 /\ g(q(v1), q(v2)) 5 2 2 5 v2 v1 …
Types in SPEC • Two basic notions of type equality: • Structural: Two types are equal if they have the same structure. • Name: Type types are equal only if they have the same name. • SPEC uses structural equality • “Equal types define the same value set. Ideally the reversed would also be true, … but set equality is intractable.” • Do structurally equal types define the same type set? • What is an example of a 2 types that are not equal, even though they have the same type set?
Type Fitting • For assignment x := e, the type of e must “fit” the declared type of x • Type T fits type U if they appear to have some value in common: • T = U • T = T’ SUCHTHAT F and T’ fits U (typechecker can’t tell) • T = (… + T’ + …) and T’ fits U • T = Int -> T’ or T = SEQ T’ and U = SEQ U’ and T’ fits U’ (sequences are functions) • Usual recursive defns for records, functions, … • Assignment can fail at runtime
Expressions and Commands • An execution is a sequence of states s1 s2 s3 “x*y+2” 14 • Two different notions: • A command is a relation on states: defines a set of possible next states. • An expression maps variables in a state to a value • Expressions are functions; commands may be nondeterministic
Expressions • Most expressions values can be determined by evaluating sub-expressions first • Expressions have no side effects, so order doesn’t matter • Usually, exceptions and “undefined” values propagate through expressions, except • (pred => e1 [*] e2) which means: if pred is true, then use the value of e1, if pred is false, use the value of e2 • Similarly for \/ /\ =>
Commands Define a State Relation Skip is the identity relation. SKIP X=0 => SKIP Adding guards subsets the next state relation.
The Next State Relation Assignment leaves produces a state that is almost identical, except at the assigned variable. y = 0 => y :=1 y :=1 Adding guards subsets the next state relation.
The Next State Relation Nondeterminism leads to union of next state relation. X=0 => SKIP [] y = 0 => y :=1 SKIP [] y = 0 => y :=1 What does the relation look like for HAVOC?
Nondeterminism and Failures • In general, there are two different kinds of nondeterminism: • Blind, also called committed choice or indeterminism • Angelic, also called backtracking • SPEC uses angelic nondeterminism • ( c1 [] c2) fails only if both c1 and c2 fail • If one fails, the result will be the other
Atomicity • Commands with <<…>> are atomic. • Commands without the angle brackets: • Things that can’t be reasonably split are still atomic: SKIP, HAVOC, RET, RAISE • An assignment is split between RHS evaluation and LHS assignment • A guarded command is split between guard eval and rest • Invocation is split after arg eval and at the end of the body • In either case, these atomic steps define the basic steps in the state machine.
Atomicity and Expressions • Expression are free of side effects • Evaluation of expression is always atomic • This does not match shared memory programming atomicity • Breaks expression evaluation into some sequence of “loads” defined by compiler • Writes may be interleaved between these loads
Modules • Modules are like classes, but they may define a set of types • Internal state may be needed in specifications • The externally visible types and procedures define the interface • We don’t look at the internal state for checking correctness of an implementation
Search Specification APROC search (q: SEQ T, x: T) -> Int RAISES {NotFound} = << IF VAR i: Int | (0 <= i /\ i < q.size /\ q(i) = x) => RET i [*] RAISE NotFound FI >> simpler VAR i:IN q.dom | q(i)=x • Doesn’t say anything about search algorithm • Does not assume q is sorted, e.g., could add: • IF ~Sorted(q) => HAVOC • What’s wrong with adding: • IF ~Sorted(q) => RAISE NotSORTED
Memory Spec Example MODULE Memory [A, D] EXPORT Read, Write, Reset, Swap = TYPE M = A -> D VAR m := Init() APROC Init() -> M = << VAR m’ | (ALL a | m’!a) => RET m’>> … END Memory % parameterized over address and data type (homogeneous) % internal state is m, which is a function (think “static”) % f!x means f is defined at x % memory defined everywhere
Memory Example continued % a implicitly type A % FUNC cannot have side effects % all operations are atomic % f{x->y} is a function constructor (H5, p3 has M{*->d} % memory defined everywhere FUNC Read(a) -> D = << RET m(a) >> APROC Write(a,d) = <<m(a) := d>> APROC Reset (d) = << m := m{* -> d} >> APROC Swap(a,d) -> D << VAR d’ := m(a) | m(a) := d; RET d’>>
Write-Back Cache Implementation MODULE WBCache [A, D] EXPORT Read, Write, Reset, Swap = TYPE M = A -> D C = A -> D CONST Csize : Int := … VAR m := InitM() VAR c := InitC() … END Memory % Same signature as Memory % New type C to represent the cache % fixed size (always defined everywhere) % Init implementations omitted here % m is main memory and c is the cache
Write-Back Cache Implementation % In the Spec, Read was a FUNC, here it’s an APROC % If the cache does not have a, make room. % Either way, write c. % Load the old value, read it, then write the new one APROC Read(a) -> D = << Load(a); RET c(a) >> APROC Write(a,d) = <<IF ~c!a => FlushOne(); [*] SKIP FI; c(a) := d >> APROC Swap(a,d) -> D << VAR d’ | Load(a); d’ = c(a); c(a) = d; RET d’>>
Write-Back Cache Implementation % Ensure address and value are in cache % If the cache does have a, make room. % Undefine cache at a % Do values differ? Is this efficient? APROC Load (a) = <<IF ~c!a => FlushOne(); c(a) := m(a) [*] SKIP FI; >> APROC FlushOne() = <<VAR a | c!a => IF Dirty(a) => m(a) := c(a) [*] SKIP FI; c := c{a -> } >> FUNC Dirty(a) -> Bool = << RET c!a /\ c(a) # m(a)>>
Abstraction Functions • A Spec Module defines a state machine • An execution fragment is s0 s1 s2 • An execution starts in an initial state p0 p1 p2
Some Executions of WBCache write(2,a) write(4,c) (read(2),a) (read(3),a) init
Abstraction Functions FUNC AF() -> M = RET (\ a | c!a => c(a) [*] m(a) ) • Note that abstraction function maps each state in previous WBCache execution to Memory state
Abstraction Functions • An abstraction function F: T -> S has: • If t is any initial state of T, the F(t) is an initial state of S • If t is reachable state of T and (t, p, t’) is a step of T, then there is a step of S from F(t) to F(t’) having the same trace • Same trace means externally visible values.
Administrivia • Thursday: Brendan Murphy • Papers online • No class next Tuesday • Extra makeup class this Friday afternoon in 405 (3:00pm) • Read sections 7,8 and 9 for Friday • Homework 3 online Thursday • Next Thursday: OceanStore • No post-coffee discussion