| |
runtime0.abs
notation syntax rsyntax rels runtime ;
import syntax rsyntax statics1 wf ;
reserve C for :id;
reserve id for :id;
reserve prog for :cprog;
reserve mbody for :cmethodbody;
reserve stmts for :rstmt list;
reserve addr for :int;
reserve val for :rval;
reserve frames for :frames;
reserve heap for :heap;
reserve vt for :varType;
// --------------------------------------------------------------------------
// MethBodyC - search the program for the method body for a call
// to an object.
// --------------------------------------------------------------------------
lfp MethBodyC
Hit
(C,(Csupo,mbodies)) :: ELS(prog) &
(m,mbody) :: ELS(mbodies) &
mbody = ((Xord,Xtys),body) &
MAP(PAPPLY(Xtys))(Xord) = AT
// ---------------------------------------------------------
MethBodyC(m,AT,C,prog)(Xord,body)
Miss
(C,(SOME(Csup),mbodies)) :: ELS(prog) &
(!Xord Xtys body. (m,((Xord,Xtys),body)) :: ELS(mbodies) --> MAP(PAPPLY(Xtys))(Xord) <> AT) &
MethBodyC(m,AT,Csup,prog)(Xord,body)
// ---------------------------------------------------------
MethBodyC(m,AT,C,prog)(Xord,body)
// --------------------------------------------------------------------------
// MethBodyA - get the method body for a call to an array method.
// The special method clone() is not
// yet supported, so we just return the method body from Object.
// --------------------------------------------------------------------------
def MethBodyA
MethBodyA(m,AT,vt,prog)(Xord,body) <=> MethBodyC(m,AT,Object,prog)(Xord,body)
// --------------------------------------------------------------------------
// MethBody - get the method body for a call to an reference type.
// --------------------------------------------------------------------------
def MethBody
MethBody(m,AT,VT(st,dim),prog)(Xord,body) <=>
MATCH res.
( 0 < dim andalso res = MethBodyA(m,AT,VT(st,dim),prog)(Xord,body)) |
(?i. dim = 0 & st = Interface(i) andalso res = F) |
(?C. dim = 0 & st = Class(C) andalso res = MethBodyC(m,AT,C,prog)(Xord,body)) |
(?p. dim = 0 & st = PrimT(p) andalso res = F)

// Heap Objects (things that get stored on the heap)
//
// The varType stored in the array indicates the type of elements stored in the array,
// not the typ of the array itself

datatype OBJECT: ((id × id) -> rval option) × id -> heapobj
| ARRAY: (varType×rval list) -> heapobj
def hoType
hoType(heapobj) =
MATCH res.
(?fldvals C. heapobj = OBJECT(fldvals,C) andalso res = VT(Class(C),0)) |
(?st1 dim vec. heapobj = ARRAY(VT(st1,dim),vec) andalso res = VT(st1,dim+1));
def hoFieldSet
hoFieldSet(OBJECT(fldvals,C),C',fld,val) = OBJECT(fldvals <+ ((C',fld),val),C)

// axiomatize a fresh address function

constant freshi :(int)fset -> int
thm freshi ~(freshi(s) ::: s)

// Heap
//

def sFieldSet
sFieldSet(heap,addr,C,fld,val) =
heap <++ (addr,hoFieldSet(FPAPPLY(heap)(addr),C,fld,val))
def sAlloc
sAlloc(heap,heapobj) =
let addr = freshi(FPDOM(heap))
in (heap <++ (addr,heapobj),addr)

// Frames
//
// Local (stack) variables are allocated in frames. The frames are never deallocated
// in the small-step semantics.

def sGetStackVar
sGetStackVar(frames,fidx,id) = PLOOKUP(EL(fidx)(frames))(id)
def sSetStackVar
sSetStackVar(frames,fidx,id,val) =
REPLACE(fidx)(frames)(EL(fidx)(frames) <+ (id,val))
def sAddFrame sAddFrame(frames,frame) = frames ×! frame
def sNextFrame sNextFrame(frames) = LEN(frames)

// initial values during allocation
//

constant initial :varType -> rval
thm initial [exec,defn]
initial(VT(st,n)) =
if (0 < n) then RAddr(NONE)
else MATCH res.
( st = PrimT(boolT) andalso res = RPrim(Bool(F))) |
( st = PrimT(charT) andalso res = RPrim(Char(mk_uchar(32)))) |
( st = PrimT(byteT) andalso res = RPrim(Byte(mk_int8(0)))) |
( st = PrimT(shortT) andalso res = RPrim(Short(mk_int16(0)))) |
( st = PrimT(intT) andalso res = RPrim(Int(mk_int32(0)))) |
( st = PrimT(longT) andalso res = RPrim(Long(mk_int64(0)))) |
( st = PrimT(floatT) andalso res = RPrim(Float(mk_ieee32(0)))) |
( st = PrimT(doubleT) andalso res = RPrim(Double(mk_ieee64(0)))) |
(?i. st = Interface(i) andalso res = RAddr(NONE)) |
(?C. st = Class(C) andalso res = RAddr(NONE))

// A gross procedure to allocate up an array, or indeed any initial value.
// We recurse through dimensions, allocating loads of pointers,
// totalling dim1 x dim2 x ... dim(n-1), and then dim(n) non-allocated values
// for each of these.
//
// In the base case we drop through to initial which, if ext = 0,
// will actually give us a real primitive value, othesimpise will
// give us a null pointer.
//
// artificiality: not tail recursive to give an easier induction - think about this.

constant val_alloc :(heap × simpType × nat list × nat) -> (rval × heap)
thm val_alloc
val_alloc (heap,st,dims,ext) =
MATCH res.
(?dim dims'. dims = dim×dims' andalso
res =
let (vec,heap') =
REPEATN dim ([],heap) (LAM(vec,heap).
let (val,heap') = val_alloc(heap,st,dims',ext) in
(val×vec,heap')) in
let (heap'',addr) = sAlloc(heap',ARRAY(VT(st,LEN(dims')+ext),vec)) in
(RAddr(SOME(addr)),heap''))
| ( dims = [] andalso
res = (initial(VT(st,ext)),heap))
// --------------------------------------------------------------------------
// Define ground expressions, values, variables etc.
// What all good expressions aspire to be.
//
// RVar expressions are not ground even when the variable is.
// This is because field/array lookup is resolved at the expression level.
// --------------------------------------------------------------------------
def val_ground [exec,defn]
val_ground val =
MATCH res.
(?x1. val = RPrim(x1) andalso res = T)
| (?x2. val = RAddr(x2) andalso res = T)
| (?x3. val = RExn(x3) andalso res = F)
def exp_ground [exec,defn]
exp_ground exp =
MATCH res.
(?val. exp = RValue(val) andalso res = val_ground(val))
| ( exp = RVoid andalso res = T)
| (?x5. exp = RVar(x5) andalso res = F)
| (?x6. exp = RNewClass(x6) andalso res = F)
| (?x7. exp = RNewArray(x7) andalso res = F)
| (?x8. exp = RCall(x8) andalso res = F)
| (?x9. exp = RBody(x9) andalso res = F)
def var_ground [exec,defn]
var_ground var =
MATCH res.
(?fidx id. var = RStackVar(fidx,id)
andalso res = T)
| (?e1 e2. var = RAccess(e1,e2)
andalso res = (exp_ground(e1) andalso exp_ground(e2)))
| (?e1 C f. var = RField(e1,C,f)
andalso res = exp_ground(e1))
def stmts_ground [exec,defn]
stmts_ground(stmts) = NULL(stmts)
def stmt_ground [exec,defn]
stmt_ground(stmt) =
MATCH res.
(?e. stmt = RExpr(e) andalso
res = exp_ground(e) = T)
| (?g b1 b2. stmt = RIf(g,b1,b2) andalso
res = F)
| (?v1 e1. stmt = RAssign(v1,e1) andalso
res = F)
| (?stmts. stmt = RBlock(stmts) andalso
res = stmts_ground(stmts))
// -------------------------------------------------------------------------
// Runtime type checking. This *is* part of the runtime model, i.e. it must be executable.
// bug found be compilation analysis to ML: undeclared variable.
//
// Modelling error: we should not be able to check conformance of
// primitive values at runtime, e.g. in array assignment. The fact
// that the primitive value being assigned is well-typed should be enough.
//
// The old problem here was we are conflating runtime type checking with the
// inveriant we need to constrain the state changes by. Should have
// v wconforms_to t' iff v : t & t < t'
//
// Note that we check even in the primitive case, and for null pointers, unlike
// any real Java imlementation. It would be possible
// not to, but we would need to strengthen the invariant in the case
// of array assignments to assert that if the type being assigned into is primitive,
// then the assignment is always welltyped.
// --------------------------------------------------------------------------
def typecheck
typecheck((TE,heap),sval,vt) <=>
MATCH res.
(?pval. sval = RPrim(pval) andalso res = (?pt. vt = VT(PrimT(pt),0) & pval prim_hastype pt))
| ( sval = RAddr(NONE) andalso res = ((?C. vt = VT(Class(C),0)) |
(?i. vt = VT(Class(i),0)) |
(?st dim. 0 < dim & vt = VT(st,dim))))
| (?addr fldvals C.
sval = RAddr(SOME(addr)) andalso
FPLOOKUP(heap)(addr) = SOME(OBJECT(fldvals,C)) andalso
res = (TE |- VT(Class(C),0) varty_widens_to vt))
| (?addr st dim vec.
sval = RAddr(SOME(addr)) andalso
FPLOOKUP(heap)(addr) = SOME(ARRAY(VT(st,dim),vec)) andalso
res = (TE |- VT(st,dim+1) varty_widens_to vt))
|