3504 lines
134 KiB
Plaintext
3504 lines
134 KiB
Plaintext
//
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//
|
|
|
|
// Verified mark-sweep garbage collector
|
|
//
|
|
// medium term goal: support more Bartok array-of-struct and vector-of-struct object layouts
|
|
// long term goal: support various other features: threads, pinning, stack markers, etc.
|
|
|
|
// Imports:
|
|
// - Trusted.bpl
|
|
// - VerifiedBitVectors.bpl
|
|
// Includes:
|
|
// - VerifiedCommon.bpl
|
|
|
|
|
|
// \Spec#\bin\Boogie.exe /noinfer Trusted.bpl VerifiedBitVectors.bpl VerifiedCommon.bpl VerifiedMarkSweepCollector.bpl
|
|
|
|
/*****************************************************************************
|
|
******************************************************************************
|
|
**** VERIFIED
|
|
******************************************************************************
|
|
*****************************************************************************/
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// MARK-SWEEP COLLECTOR
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
// gc memory structure:
|
|
// ?gcLo [mark stack] ColorBase [color bit map] HeapLo [heap] HeapHi ?gcHi
|
|
|
|
function Unallocated(i:int) returns(bool) { i == 0 }
|
|
function White(i:int) returns(bool) { i == 1 }
|
|
function Gray(i:int) returns(bool) { i == 2 }
|
|
function Black(i:int) returns(bool) { i == 3 }
|
|
|
|
var $freshAbs:int;
|
|
var $color:[int]int;
|
|
var StackTop:int;
|
|
var $fs:[int]int; // size of free block
|
|
var $fn:[int]int; // next free block
|
|
var CachePtr:int;
|
|
var CacheSize:int;
|
|
var ColorBase:int;
|
|
var HeapLo:int;
|
|
var HeapHi:int;
|
|
var ReserveMin:int; // wilderness marker
|
|
|
|
function ObjectSeq(i1:int, i2:int, r:[int]int, $fs:[int]int, $fn:[int]int) returns (bool)
|
|
{
|
|
(forall i:int::{TV(i)} TV(i) ==> i1 <= i && i < i2 ==>
|
|
(r[i] != NO_ABS ==>
|
|
$fs[i] == 0
|
|
&& i + 4 * numFields(r[i]) <= i2
|
|
&& (forall ii:int::{TV(ii)} TV(ii) ==> i < ii && ii < i + 4 * numFields(r[i]) ==> r[ii] == NO_ABS && $fs[ii] == 0)
|
|
)
|
|
&& ($fs[i] != 0 ==>
|
|
r[i] == NO_ABS
|
|
&& i + 8 <= i + $fs[i] && i + $fs[i] <= i2
|
|
&& Aligned(i) && Aligned(i + $fs[i])
|
|
&& ($fn[i] != 0 ==> between(i + $fs[i], i2, $fn[i]) && $fs[$fn[i]] != 0)
|
|
&& (forall ii:int::{TV(ii)} TV(ii) ==> i < ii && ii < i + $fs[i] ==> r[ii] == NO_ABS && $fs[ii] == 0)
|
|
&& (forall ii:int::{TV(ii)} TV(ii) ==> i < ii && ii < $fn[i] && $fs[ii] != 0 ==> $fn[ii] == 0)
|
|
)
|
|
)
|
|
}
|
|
|
|
function Objects(i1:int, i2:int, r:[int]int, $fs:[int]int, $fn:[int]int) returns (bool)
|
|
{
|
|
(forall i:int::{TV(i)} TV(i) ==> i1 <= i && i < i2 ==>
|
|
(r[i] != NO_ABS ==>
|
|
$fs[i] == 0
|
|
&& Aligned(i)
|
|
&& i + 4 * numFields(r[i]) <= i2
|
|
&& (forall ii:int::{TV(ii)} TV(ii) ==> i < ii && ii < i + 4 * numFields(r[i]) ==> r[ii] == NO_ABS && $fs[ii] == 0)
|
|
)
|
|
&& ($fs[i] != 0 ==> Aligned(i))
|
|
)
|
|
}
|
|
|
|
function Disconnected(i1:int, ptr:int, $fs:[int]int, $fn:[int]int) returns(bool)
|
|
{
|
|
(forall i:int::{TV(i)} TV(i) ==> i1 <= i && i < ptr && $fs[i] != 0 ==> $fn[i] != ptr)
|
|
}
|
|
|
|
function FreeInvBase(i1:int, i2:int, $fs:[int]int, $fn:[int]int, data:[int]int, CachePtr:int, CacheSize:int) returns (bool)
|
|
{
|
|
i2 >= i1 + 8
|
|
&& $fs[i1] == 8
|
|
&& (CacheSize != 0 ==> between(i1, i2, CachePtr) && $fs[CachePtr] == CacheSize && Disconnected(i1, CachePtr, $fs, $fn))
|
|
}
|
|
|
|
function FreeInvI(i:int, i1:int, i2:int, $fs:[int]int, $fn:[int]int, data:[int]int, CachePtr:int, CacheSize:int) returns (bool)
|
|
{
|
|
data[i] == $fn[i]
|
|
&& data[i + 4] == $fs[i]
|
|
}
|
|
|
|
function FreeInv(i1:int, i2:int, $fs:[int]int, $fn:[int]int, data:[int]int, CachePtr:int, CacheSize:int) returns (bool)
|
|
{
|
|
FreeInvBase(i1, i2, $fs, $fn, data, CachePtr, CacheSize)
|
|
&& (forall i:int::{TV(i)} TV(i) ==> i1 <= i && i < i2 && $fs[i] != 0 ==>
|
|
FreeInvI(i, i1, i2, $fs, $fn, data, CachePtr, CacheSize))
|
|
}
|
|
|
|
// REVIEW: get rid of this?
|
|
function AllocInv2($toAbs:[int]int, min:int, max:int, $r1:[int]int, $r2:[int]int, r1Live:bool) returns (bool)
|
|
{
|
|
(forall i:int::{TV(i)} TV(i) ==> min <= i && i < max && r1Live ==> ($toAbs[i] == NO_ABS ==> $r1[i] == NO_ABS))
|
|
&& (forall i:int::{TV(i)} TV(i) ==> min <= i && i < max ==> ($toAbs[i] == NO_ABS ==> $r2[i] == NO_ABS))
|
|
}
|
|
|
|
function MsInvColorI(i:int, t:Time, $r1:[int]int, $r2:[int]int, $color:[int]int, r1Live:bool,
|
|
$GcMem:[int]int, $toAbs:[int]int, $AbsMem:[int][int]int, $gcSlice:[int]int) returns (bool)
|
|
{
|
|
(White($color[i]) ==> $r1[i] != NO_ABS && $r2[i] == NO_ABS
|
|
&& (r1Live ==> ObjInv(i, $r1, $r1, $toAbs, $AbsMem, $GcMem, $gcSlice))
|
|
)
|
|
&& (Gray($color[i]) ==> $r1[i] != NO_ABS && $r2[i] != NO_ABS
|
|
&& ObjInv(i, $r1, $r1, $toAbs, $AbsMem, $GcMem, $gcSlice)
|
|
&& reached($toAbs[i], t)
|
|
)
|
|
&& (Black($color[i]) ==> $r1[i] != NO_ABS && $r2[i] != NO_ABS
|
|
&& ObjInv(i, $r2, $r2, $toAbs, $AbsMem, $GcMem, $gcSlice)
|
|
&& reached($toAbs[i], t)
|
|
)
|
|
}
|
|
|
|
function MsInvBase(min:int, max:int, $r1:[int]int, $r2:[int]int, $color:[int]int,
|
|
r1Live:bool, $GcMem:[int]int, $toAbs:[int]int, $gcSlice:[int]int) returns (bool)
|
|
{
|
|
(forall i:int::{TV(i)} TV(i) ==> min <= i && i < max
|
|
&& r1Live && $r1[i] != NO_ABS && $r2[i] != NO_ABS ==> $r1[i] == $r2[i])
|
|
&& (forall i:int::{TV(i)} TV(i) ==> min <= i && i < max && $toAbs[i] != NO_ABS ==>
|
|
$toAbs[i] != NO_ABS && $toAbs[i] == $r1[i])
|
|
&& WellFormed($toAbs)
|
|
}
|
|
|
|
function MsGcInv(min:int, max:int, t:Time, $r1:[int]int, $r2:[int]int, $color:[int]int,
|
|
r1Live:bool, $GcMem:[int]int, $toAbs:[int]int, $AbsMem:[int][int]int, $gcSlice:[int]int) returns (bool)
|
|
{
|
|
MsInvBase(min, max, $r1, $r2, $color, r1Live, $GcMem, $toAbs, $gcSlice)
|
|
&& (forall i:int::{TV(i)} TV(i) ==> min <= i && i < max && $toAbs[i] != NO_ABS ==>
|
|
MsInvColorI(i, t, $r1, $r2, $color, r1Live, $GcMem, $toAbs, $AbsMem, $gcSlice)
|
|
)
|
|
}
|
|
|
|
function MsInv(min:int, max:int, $color:[int]int,
|
|
$GcMem:[int]int, $toAbs:[int]int, $AbsMem:[int][int]int, $gcSlice:[int]int) returns (bool)
|
|
{
|
|
(forall i:int::{TV(i)} TV(i) ==> min <= i && i < max ==> $toAbs[i] != NO_ABS ==>
|
|
$toAbs[i] != NO_ABS
|
|
&& ObjInv(i, $toAbs, $toAbs, $toAbs, $AbsMem, $GcMem, $gcSlice)
|
|
)
|
|
&& (forall i:int::{TV(i)} TV(i) ==> min <= i && i < max ==> (White($color[i]) <==> $toAbs[i] != NO_ABS))
|
|
&& WellFormed($toAbs)
|
|
}
|
|
|
|
function GcInv(ColorBase:int, HeapLo:int, HeapHi:int, $color:[int]int, $toAbs:[int]int, $r1:[int]int, $r2:[int]int, $GcMem:[int]int) returns(bool)
|
|
{
|
|
?gcLo <= ColorBase && ColorBase <= HeapLo && HeapLo <= HeapHi && HeapHi <= ?gcHi
|
|
&& Aligned(ColorBase) && Aligned(HeapLo) && Aligned(HeapHi)
|
|
&& bb2vec4($color, HeapLo, $GcMem, HeapLo, HeapLo, HeapHi, ColorBase, HeapLo)
|
|
&& (forall i:int::{TV(i)} TV(i) ==> i < HeapLo || i >= HeapHi ==>
|
|
$toAbs[i] == NO_ABS && $r1[i] == NO_ABS && $r2[i] == NO_ABS)
|
|
&& (forall i:int::{TV(i)} TV(i) ==> HeapLo <= i && i < HeapHi ==> between(0, 4, $color[i]))
|
|
&& (forall i:int::{TV(i)} TV(i) ==> HeapLo <= i && i < HeapHi ==> (Unallocated($color[i]) <==> $toAbs[i] == NO_ABS))
|
|
}
|
|
|
|
function BigGcInv($freshAbs:int, ColorBase:int, HeapLo:int, HeapHi:int, $color:[int]int, $fs:[int]int, $fn:[int]int,
|
|
$toAbs:[int]int, $r1:[int]int, $r2:[int]int, $AbsMem:[int][int]int, $GcMem:[int]int, $gcSlice:[int]int,
|
|
CachePtr:int, CacheSize:int, $Time:Time) returns(bool)
|
|
{
|
|
AllocInv2($toAbs, HeapLo, HeapHi, $r1, $r2, true)
|
|
&& MsGcInv(HeapLo, HeapHi, $Time, $r1, $r2, $color, true, $GcMem, $toAbs, $AbsMem, $gcSlice)
|
|
&& GcInv(ColorBase, HeapLo, HeapHi, $color, $toAbs, $r1, $r2, $GcMem)
|
|
&& ObjectSeq(HeapLo, HeapHi, $toAbs, $fs, $fn)
|
|
&& FreeInv(HeapLo, HeapHi, $fs, $fn, $GcMem, CachePtr, CacheSize)
|
|
&& (forall i:int::{TV(i)} TV(i) ==> gcAddr(i) ==> $toAbs[i] != $freshAbs && $r2[i] != $freshAbs)
|
|
}
|
|
|
|
function MutatorInv(ColorBase:int, HeapLo:int, HeapHi:int, $color:[int]int, $fs:[int]int, $fn:[int]int,
|
|
$toAbs:[int]int, $AbsMem:[int][int]int, $GcMem:[int]int, $gcSlice:[int]int,
|
|
CachePtr:int, CacheSize:int) returns(bool)
|
|
{
|
|
MsInv(HeapLo, HeapHi, $color, $GcMem, $toAbs, $AbsMem, $gcSlice)
|
|
&& GcInv(ColorBase, HeapLo, HeapHi, $color, $toAbs, $toAbs, $toAbs, $GcMem)
|
|
&& ObjectSeq(HeapLo, HeapHi, $toAbs, $fs, $fn)
|
|
&& FreeInv(HeapLo, HeapHi, $fs, $fn, $GcMem, CachePtr, CacheSize)
|
|
}
|
|
|
|
function MarkStack(s1:int, s2:int, $toAbs:[int]int, $color:[int]int, stack:[int]int, extra:int) returns(bool)
|
|
{
|
|
s1 <= s2
|
|
&& Aligned(s2)
|
|
&& (forall i:int::{TV(i)} TV(i) ==> gcAddr(i) ==> $toAbs[i] != NO_ABS && Gray($color[i]) && i != extra ==>
|
|
(exists s:int::{TV(s)} TV(s) && s1 <= s && s < s2 && Aligned(s) && stack[s] == i))
|
|
&& (forall s:int::{TV(s)} TV(s) ==> s1 <= s && s < s2 && Aligned(s) ==>
|
|
gcAddr(stack[s]) && $toAbs[stack[s]] != NO_ABS && Gray($color[stack[s]]) && stack[s] != extra)
|
|
&& (forall s:int,t:int::{TV(s),TV(t)} TV(s) && TV(t) ==>
|
|
s1 <= s && s < s2 ==> s1 <= t && t < s2 && Aligned(s) && Aligned(t) ==>
|
|
s != t ==> stack[s] != stack[t])
|
|
}
|
|
|
|
procedure BB4Zero2($a:[int]int, $aBase:int, $i0:int, $i1:int, $i2:int, $k:int, $g1:int, $g2:int, $_i0:int, $_g1:int)
|
|
requires eax == $g1;
|
|
requires ebx == $g2;
|
|
requires (forall i:int::{TV(i)} TV(i) && $i1 <= i && i < $i2 ==> $a[$aBase + (i - $i0)] == 0);
|
|
requires Aligned($g1) && Aligned($g2);
|
|
requires $i2 - $i1 == 16 * ($g2 - $g1);
|
|
requires word($i1 - $i0) && word($i2 - $i0);
|
|
requires ?gcLo <= $g1 && $g1 <= $g2 && $g2 <= ?gcHi;
|
|
requires $i1 == $i0;
|
|
modifies $GcMem;
|
|
modifies eax, ebx, esi, edi, ebp, esp;
|
|
ensures bb2vec4($a, $aBase, $GcMem, $i0, $i1, $i2, $g1, $g2);
|
|
ensures (forall i:int::{TV(i)} TV(i) && !between($g1, $g2, i) ==> $GcMem[i] == old($GcMem)[i]);
|
|
{
|
|
var $iter:int;
|
|
esi := eax;
|
|
$iter := $i1;
|
|
//while (esi < $g2)
|
|
loop:
|
|
assert Aligned(esi) && TV(esi);
|
|
assert $g1 <= esi && esi <= $g2;
|
|
assert $iter - $i1 == 16 * (esi - $g1);
|
|
assert bb2vec4($a, $aBase, $GcMem, $i0, $i1, $iter, $g1, $g2);
|
|
assert (forall i:int::{TV(i)} TV(i) && !between($g1, $g2, i) ==> $GcMem[i] == old($GcMem)[i]);
|
|
if (esi >= ebx) { goto loopEnd; }
|
|
|
|
call __notAligned(esi);
|
|
call __bb4Zero2($a, $aBase, $GcMem, $i0, $i1, $iter, $g1, $g2, esi);
|
|
call GcStore(esi, 0);
|
|
$iter := $iter + 64;
|
|
call esi := Add(esi, 4);
|
|
assert TO(1);
|
|
goto loop;
|
|
loopEnd:
|
|
|
|
assert esi == $g2;
|
|
assert $iter == $i2;
|
|
esp := esp + 4; return;
|
|
}
|
|
|
|
procedure bb4GetColor($a:[int]int, $aBase:int, $i0:int, $i1:int, $i2:int, $k:int, $g1:int, $g2:int)
|
|
requires bb2vec4($a, $aBase, $GcMem, $i0, $i1, $i2, $g1, $g2);
|
|
requires word($k - $i0) && $i1 <= $k && $k < $i2;
|
|
requires word($k) && word($i0) && Aligned($k) && Aligned($i0);
|
|
requires word($i2 - $i0);
|
|
requires eax == $g1;
|
|
requires ebx == $k - $i0;
|
|
requires Aligned($g1) && ?gcLo <= $g1 && $g2 <= ?gcHi;
|
|
requires word($i1 - $i0) && word($i2 - $i0);
|
|
modifies ebx, ecx, edx;
|
|
ensures ebx == $a[$aBase + ($k - $i0)];
|
|
{
|
|
var $idx:int;
|
|
var $bbb:int;
|
|
$idx := $g1 + 4 * shr($k - $i0, 6);
|
|
$bbb := and(shr($GcMem[$idx], and(shr($k - $i0, 1), 31)), 3);
|
|
call __subAligned($k, $i0);
|
|
call __bb4Get2Bit($a, $aBase, $GcMem, $i0, $i1, $i2, $k, $idx, $bbb, $g1, $g2);
|
|
|
|
assert TV($g1);
|
|
assert TO(shr(ebx, 6));
|
|
|
|
ecx := ebx;
|
|
call ecx := Shr(ecx, 6);
|
|
call edx := Lea(eax + 4 * ecx);
|
|
ecx := ebx;
|
|
call ecx := Shr(ecx, 1);
|
|
call ecx := And(ecx, 31);
|
|
call edx := GcLoad(edx);
|
|
ebx := edx;
|
|
call ebx := Shr(ebx, ecx);
|
|
call ebx := And(ebx, 3);
|
|
}
|
|
|
|
procedure bb4SetColor($a:[int]int, $val:int, $aBase:int, $i0:int, $i1:int, $i2:int, $k:int, $g1:int, $g2:int)
|
|
requires bb2vec4($a, $aBase, $GcMem, $i0, $i1, $i2, $g1, $g2);
|
|
requires word($k - $i0) && $i1 <= $k && $k < $i2;
|
|
requires word($k) && word($i0) && Aligned($k) && Aligned($i0);
|
|
requires word($i2 - $i0);
|
|
requires 0 <= $val && $val <= 3;
|
|
requires esi == $k - $i0;
|
|
requires edi == $g1;
|
|
requires edx == $val;
|
|
requires Aligned($g1) && ?gcLo <= $g1 && $g2 <= ?gcHi;
|
|
requires word($i1 - $i0) && word($i2 - $i0);
|
|
modifies eax, esi, edi, ecx, edx, $GcMem;
|
|
ensures bb2vec4($a[$aBase + ($k - $i0) := $val], $aBase, $GcMem, $i0, $i1, $i2, $g1, $g2);
|
|
ensures $GcMem == old($GcMem)[$g1 + ColorIndex($i0, $k) := esi];
|
|
ensures Aligned($k - $i0);
|
|
{
|
|
var $idx:int;
|
|
var $bbb:int;
|
|
var $_bbb:int;
|
|
$idx := $g1 + 4 * shr($k - $i0, 6);
|
|
$bbb := and($GcMem[$idx], neg(shl(3, and(shr($k - $i0, 1), 31))));
|
|
$_bbb := or($bbb, shl($val, and(shr($k - $i0, 1), 31)));
|
|
call __subAligned($k, $i0);
|
|
call __bb4Set2Bit($a, $val, $aBase, $GcMem, $i0, $i1, $i2, $k, $idx, $bbb, $_bbb, $GcMem[$idx := $_bbb], $g1, $g2);
|
|
assert TV($g1);
|
|
assert TO(shr(esi, 6));
|
|
|
|
ecx := esi;
|
|
call esi := Shr(esi, 6);
|
|
call edi := Lea(edi + 4 * esi);
|
|
//assert edi == $idx;
|
|
|
|
call ecx := Shr(ecx, 1);
|
|
call ecx := And(ecx, 31);
|
|
eax := 3;
|
|
call eax := Shl(eax, ecx);
|
|
call eax := Not(eax);
|
|
call esi := GcLoad(edi);
|
|
call esi := And(esi, eax);
|
|
//assert $bbb == esi;
|
|
|
|
call edx := Shl(edx, ecx);
|
|
call esi := Or(esi, edx);
|
|
assert $_bbb == esi;
|
|
call GcStore(edi, esi);
|
|
}
|
|
|
|
procedure visit($_ptr:int, $abs:int, $extra:int)
|
|
requires ecx == $_ptr;
|
|
requires AllocInv2($toAbs, HeapLo, HeapHi, $r1, $r2, true);
|
|
requires MsGcInv(HeapLo, HeapHi, $Time, $r1, $r2, $color, true, $GcMem, $toAbs, $AbsMem, $gcSlice);
|
|
requires GcInv(ColorBase, HeapLo, HeapHi, $color, $toAbs, $r1, $r2, $GcMem);
|
|
requires Value(true, $r1, $_ptr, $abs);
|
|
requires !gcAddrEx($_ptr) || reached($toAbs[$_ptr - 4], $Time);
|
|
requires TV($_ptr - 4);
|
|
requires MarkStack(?gcLo, StackTop, $toAbs, $color, $GcMem, $extra);
|
|
requires $extra != 0 ==> Gray($color[$extra]);
|
|
requires StackTop <= ColorBase;
|
|
requires gcAddrEx($_ptr);
|
|
|
|
modifies $r2, $color;
|
|
modifies eax, ebx, ecx, edx, esi, edi, ebp, esp;
|
|
modifies StackTop, $GcMem;
|
|
|
|
ensures old(StackTop) <= StackTop && StackTop <= ColorBase;
|
|
ensures (forall ss:int::{TV(ss)} TV(ss) ==> HeapHi <= ss && ss < old(StackTop) ==> $GcMem[ss] == old($GcMem)[ss]);
|
|
ensures MarkStack(?gcLo, StackTop, $toAbs, $color, $GcMem, $extra);
|
|
ensures GcInv(ColorBase, HeapLo, HeapHi, $color, $toAbs, $r1, $r2, $GcMem);
|
|
ensures AllocInv2($toAbs, HeapLo, HeapHi, $r1, $r2, true);
|
|
ensures MsGcInv(HeapLo, HeapHi, $Time, $r1, $r2, $color, true, $GcMem, $toAbs, $AbsMem, $gcSlice);
|
|
ensures RExtend(old($r2), $r2);
|
|
ensures Value(true, $r2, $_ptr, $abs);
|
|
ensures !gcAddrEx($_ptr) || !White($color[$_ptr - 4]);
|
|
ensures (forall i:int::{TV(i)} TV(i) ==> gcAddr(i) ==> Gray(old($color)[i]) ==> Gray($color[i]));
|
|
ensures ( ( old(StackTop < ColorBase) && $GcMem == old($GcMem)
|
|
[ColorBase + ColorIndex(HeapLo, $_ptr - 4) := $GcMem[ColorBase + ColorIndex(HeapLo, $_ptr - 4)]]
|
|
[old(StackTop) := $GcMem[old(StackTop)]])
|
|
&& between(ColorBase, HeapLo, ColorBase + ColorIndex(HeapLo, $_ptr - 4)))
|
|
|| $GcMem == old($GcMem);
|
|
{
|
|
// call ebp := Lea(ecx - 4); REVIEW: add support for negative offsets to MASM generator
|
|
ebp := ecx;
|
|
call ebp := Sub(ebp, 4);
|
|
|
|
ebx := ebp;
|
|
call ebx := Sub(ebx, HeapLo);
|
|
eax := ColorBase;
|
|
call bb4GetColor($color, HeapLo, HeapLo, HeapLo, HeapHi, ebp, ColorBase, HeapLo);
|
|
assert ebx == $color[ebp];
|
|
|
|
if (ebx != 1) { goto end; } // !white
|
|
eax := StackTop;
|
|
if (eax != ColorBase) { goto skip1; }
|
|
// stack overflow
|
|
call DebugBreak();
|
|
skip1:
|
|
esi := ebp;
|
|
call esi := Sub(esi, HeapLo);
|
|
edi := ColorBase;
|
|
edx := 2; // gray
|
|
call bb4SetColor($color, 2, HeapLo, HeapLo, HeapLo, HeapHi, ebp, ColorBase, HeapLo);
|
|
$color[ebp] := 2; // gray
|
|
|
|
$r2[ebp] := $r1[ebp];
|
|
eax := StackTop;
|
|
call GcStore(eax, ebp);
|
|
assert TV(StackTop) && TO(1);
|
|
call __notAligned(StackTop);
|
|
call StackTop := Add(StackTop, 4);
|
|
end:
|
|
}
|
|
|
|
procedure scanObjectDense($vt:int, $ptr:int, $abs:int)
|
|
requires ebx == $ptr;
|
|
requires ecx == $vt;
|
|
requires $vt == $AbsMem[$r1[$ptr]][1];
|
|
requires tag($vt) == ?DENSE_TAG;
|
|
requires $abs == $r1[$ptr];
|
|
requires BigGcInv($freshAbs, ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs, $r1, $r2,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize, $Time);
|
|
requires Pointer($r1, $ptr, $abs);
|
|
requires TV($ptr);
|
|
requires Gray($color[$ptr]);
|
|
requires MarkStack(?gcLo, StackTop, $toAbs, $color, $GcMem, $ptr);
|
|
requires StackTop <= ColorBase;
|
|
|
|
modifies $r2, $color;
|
|
modifies eax, ebx, ecx, edx, esi, edi, ebp, esp;
|
|
modifies StackTop, $GcMem;
|
|
|
|
ensures old(StackTop) <= StackTop && StackTop <= ColorBase;
|
|
ensures (forall ss:int::{TV(ss)} TV(ss) ==> HeapHi <= ss && ss < old(StackTop) ==> $GcMem[ss] == old($GcMem)[ss]);
|
|
ensures MarkStack(?gcLo, StackTop, $toAbs, $color, $GcMem, $ptr);
|
|
ensures BigGcInv($freshAbs, ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs, $r1, $r2,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize, $Time);
|
|
ensures RExtend(old($r2), $r2);
|
|
ensures (forall j:int::{TO(j)} TO(j) ==> 0 <= j && j < numFields($abs) ==>
|
|
Value(VFieldPtr($abs, j), $r2, $GcMem[$ptr + 4 * j], $AbsMem[$toAbs[$ptr]][j]));
|
|
|
|
{
|
|
var ptr:int;
|
|
var save1:int;
|
|
var save2:int;
|
|
var save3:int;
|
|
assert TO(numFields($r1[$ptr]));
|
|
ptr := ebx;
|
|
|
|
esi := 2;
|
|
assert TVT($r1[$ptr], $vt);
|
|
assert TVL($r1[$ptr]);
|
|
call ebp := RoLoad32(ecx + ?VT_BASE_LENGTH);
|
|
call edx := RoLoad32(ecx + ?VT_MASK);
|
|
edi := ebx;
|
|
call edi := Add(edi, 8);
|
|
call ebp := Add(ebp, ebx);
|
|
|
|
//while (edi < ebp)
|
|
loop:
|
|
assert TO(esi);// && 0 < esi;
|
|
assert edi == $ptr + 4 * esi && ebp == $ptr + 4 * numFields($r1[$ptr]) && edx == mask($vt);
|
|
assert 2 <= esi && esi <= numFields($r1[$ptr]);
|
|
assert Pointer($r2, $ptr, $r1[$ptr]);
|
|
assert BigGcInv($freshAbs, ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs, $r1, $r2,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize, $Time);
|
|
assert old(StackTop) <= StackTop && StackTop <= ColorBase;
|
|
assert (forall ss:int::{TV(ss)} TV(ss) ==> HeapHi <= ss && ss < old(StackTop) ==> $GcMem[ss] == old($GcMem)[ss]);
|
|
assert MarkStack(?gcLo, StackTop, $toAbs, $color, $GcMem, $ptr);
|
|
assert Gray($color[$ptr]);
|
|
assert RExtend(old($r2), $r2);
|
|
assert ObjInvPartial($ptr, 0, esi, $r2, $r2, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
assert ObjInvPartial($ptr, esi, numFields($r1[$ptr]), $r2, $r1, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
assert $toAbs[$ptr] != NO_ABS && $toAbs[$ptr] == $r1[$ptr];
|
|
if (edi >= ebp) { goto loopEnd; }
|
|
if (esi >= 30) { goto loopEnd; }
|
|
|
|
assert TO(0) && TO(1);
|
|
assert TVT($r1[$ptr], $vt);
|
|
assert TVL($r1[$ptr]);
|
|
call ecx := Lea(esi + 2);
|
|
ebx := edx;
|
|
call ebx := Shr(ebx, ecx);
|
|
call ebx := And(ebx, 1);
|
|
if (ebx != 1) { goto skip1; }
|
|
call ecx := GcLoad(edi);
|
|
|
|
//if (gcAddrEx(ecx))
|
|
if (ecx < ?gcLo) { goto skip2; }
|
|
if (ecx > ?gcHi) { goto skip2; }
|
|
assert TV(ecx - 4);
|
|
call reach($toAbs[$ptr], esi, $Time);
|
|
|
|
save1 := esi;
|
|
save2 := ebp;
|
|
save3 := edx;
|
|
call visit(ecx, $AbsMem[$toAbs[$ptr]][esi], $ptr);
|
|
esi := save1;
|
|
ebp := save2;
|
|
edx := save3;
|
|
edi := ptr;
|
|
call edi := Lea(edi + 4 * esi);
|
|
skip2:
|
|
skip1:
|
|
|
|
call esi := Add(esi, 1);
|
|
call edi := Add(edi, 4);
|
|
goto loop;
|
|
loopEnd:
|
|
|
|
assert TVT($r1[$ptr], $vt);
|
|
assert TVL($r1[$ptr]);
|
|
assert TO(1);
|
|
}
|
|
|
|
procedure scanObjectSparse($vt:int, $ptr:int, $abs:int)
|
|
requires ebx == $ptr;
|
|
requires ecx == $vt;
|
|
requires BigGcInv($freshAbs, ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs, $r1, $r2,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize, $Time);
|
|
requires MarkStack(?gcLo, StackTop, $toAbs, $color, $GcMem, $ptr);
|
|
requires StackTop <= ColorBase;
|
|
requires Pointer($r1, $ptr, $abs);
|
|
requires TV($ptr);
|
|
requires Gray($color[$ptr]);
|
|
requires $vt == $AbsMem[$r1[$ptr]][1];
|
|
requires tag($vt) == ?SPARSE_TAG;
|
|
modifies $r2, $color, StackTop, $GcMem;
|
|
modifies eax, ebx, ecx, edx, esi, edi, ebp, esp;
|
|
ensures BigGcInv($freshAbs, ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs, $r1, $r2,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize, $Time);
|
|
ensures MarkStack(?gcLo, StackTop, $toAbs, $color, $GcMem, $ptr);
|
|
ensures old(StackTop) <= StackTop && StackTop <= ColorBase;
|
|
ensures (forall ss:int::{TV(ss)} TV(ss) ==> HeapHi <= ss && ss < old(StackTop) ==> $GcMem[ss] == old($GcMem)[ss]);
|
|
ensures RExtend(old($r2), $r2);
|
|
ensures (forall j:int::{TO(j)} TO(j) ==> 0 <= j && j < numFields($abs) ==>
|
|
Value(VFieldPtr($abs, j), $r2, $GcMem[$ptr + 4 * j], $AbsMem[$toAbs[$ptr]][j]));
|
|
{
|
|
var save1:int;
|
|
var save2:int;
|
|
var save3:int;
|
|
var save4:int;
|
|
var ptr:int;
|
|
ptr := ebx;
|
|
assert TO(numFields($r1[$ptr]));
|
|
|
|
esi := 1;
|
|
|
|
assert TO(numFields($r1[$ptr]));
|
|
assert TVT($r1[$ptr], $vt);
|
|
call ebp := RoLoad32(ecx + ?VT_BASE_LENGTH);
|
|
call edx := RoLoad32(ecx + ?VT_MASK);
|
|
assert TVL($r1[$ptr]);
|
|
|
|
esi := 1;
|
|
//while (esi < 8)
|
|
loop:
|
|
assert edx == mask($vt) && ebp == 4 * numFields($r1[$ptr]);
|
|
assert TSlot(esi) && 0 < esi && esi <= 8;
|
|
assert Pointer($r2, $ptr, $r1[$ptr]);
|
|
assert BigGcInv($freshAbs, ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs, $r1, $r2,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize, $Time);
|
|
assert old(StackTop) <= StackTop && StackTop <= ColorBase;
|
|
assert (forall ss:int::{TV(ss)} TV(ss) ==> HeapHi <= ss && ss < old(StackTop) ==> $GcMem[ss] == old($GcMem)[ss]);
|
|
assert MarkStack(?gcLo, StackTop, $toAbs, $color, $GcMem, $ptr);
|
|
assert Gray($color[$ptr]);
|
|
assert RExtend(old($r2), $r2);
|
|
assert ObjInvBase($ptr, $r2, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
assert (forall j:int::{TO(j)} TO(j) ==> 0 <= j && j < numFields($r1[$ptr]) ==>
|
|
between(1, esi, fieldToSlot($vt, j - 2)) ==>
|
|
ObjInvField($ptr, j, $r2, $r2, $toAbs, $AbsMem, $GcMem, $gcSlice));
|
|
assert (forall j:int::{TO(j)} TO(j) ==> 0 <= j && j < numFields($r1[$ptr]) ==>
|
|
!between(1, esi, fieldToSlot($vt, j - 2)) ==>
|
|
ObjInvField($ptr, j, $r2, $r1, $toAbs, $AbsMem, $GcMem, $gcSlice));
|
|
assert $toAbs[$ptr] != NO_ABS && $toAbs[$ptr] == $r1[$ptr];
|
|
if (esi >= 8) { goto loopEnd; }
|
|
|
|
assert TO(0) && TO(1);
|
|
assert TVT($r1[$ptr], $vt);
|
|
assert TO(getNib(edx, 4 * esi) + 1);
|
|
|
|
//if (getNib(edx, 4 * esi) != 0)
|
|
ecx := 0;
|
|
call ecx := Lea(ecx + 4 * esi);
|
|
ebx := edx;
|
|
call ebx := Shr(ebx, ecx);
|
|
call ebx := And(ebx, 15);
|
|
if (ebx == 0) { goto skip1; }
|
|
eax := ptr;
|
|
call ecx := GcLoad(eax + 4 * ebx + 4);
|
|
|
|
//if (gcAddrEx(ecx))
|
|
if (ecx < ?gcLo) { goto skip2; }
|
|
if (ecx > ?gcHi) { goto skip2; }
|
|
assert TV(ecx - 4);
|
|
call reach($toAbs[$ptr], 1 + ebx, $Time);
|
|
|
|
save1 := esi;
|
|
save2 := ebp;
|
|
save3 := edx;
|
|
save4 := ebx;
|
|
call visit(ecx, $AbsMem[$toAbs[$ptr]][1 + getNib(edx, 4 * esi)], $ptr);
|
|
esi := save1;
|
|
ebp := save2;
|
|
edx := save3;
|
|
ebx := save4;
|
|
skip2:
|
|
skip1:
|
|
|
|
call esi := Add(esi, 1);
|
|
goto loop;
|
|
loopEnd:
|
|
|
|
assert TVT($r1[$ptr], $vt);
|
|
assert TVL($r1[$ptr]);
|
|
assert TO(1);
|
|
}
|
|
|
|
procedure scanObjectOtherVectorNoPointers($vt:int, $ptr:int, $abs:int)
|
|
requires ebx == $ptr;
|
|
requires ecx == $vt;
|
|
requires BigGcInv($freshAbs, ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs, $r1, $r2,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize, $Time);
|
|
requires MarkStack(?gcLo, StackTop, $toAbs, $color, $GcMem, $ptr);
|
|
requires StackTop <= ColorBase;
|
|
requires Pointer($r1, $ptr, $abs);
|
|
requires TV($ptr);
|
|
requires Gray($color[$ptr]);
|
|
requires $vt == $AbsMem[$r1[$ptr]][1];
|
|
requires tag($vt) == ?OTHER_VECTOR_TAG;
|
|
requires arrayOf($vt) != ?TYPE_STRUCT || (arrayOf($vt) == ?TYPE_STRUCT && mask(arrayElementClass($vt)) == ?SPARSE_TAG);
|
|
modifies $r2, $color, StackTop, $GcMem;
|
|
modifies eax, ebx, ecx, edx, esi, edi, ebp, esp;
|
|
ensures BigGcInv($freshAbs, ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs, $r1, $r2,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize, $Time);
|
|
ensures MarkStack(?gcLo, StackTop, $toAbs, $color, $GcMem, $ptr);
|
|
ensures old(StackTop) <= StackTop && StackTop <= ColorBase;
|
|
ensures (forall ss:int::{TV(ss)} TV(ss) ==> HeapHi <= ss && ss < old(StackTop) ==> $GcMem[ss] == old($GcMem)[ss]);
|
|
ensures RExtend(old($r2), $r2);
|
|
ensures (forall j:int::{TO(j)} TO(j) ==> 0 <= j && j < numFields($abs) ==>
|
|
Value(VFieldPtr($abs, j), $r2, $GcMem[$ptr + 4 * j], $AbsMem[$toAbs[$ptr]][j]));
|
|
{
|
|
assert TO(numFields($r1[$ptr]));
|
|
assert TVT($r1[$ptr], $vt);
|
|
}
|
|
|
|
procedure scanObjectOtherVectorPointersSparseFields($vt:int, $ptr:int, $abs:int, $jj:int, $index:int)
|
|
requires edx == mask(arrayElementClass($vt));
|
|
requires edi == $jj;
|
|
requires ebp == $ptr;
|
|
requires tag($vt) == ?OTHER_VECTOR_TAG;
|
|
requires arrayOf($vt) == ?TYPE_STRUCT && tag(arrayElementClass($vt)) == ?SPARSE_TAG;
|
|
requires TO($jj) && $jj == baseWords($vt) + Mult(arrayElementWords($vt), $index);
|
|
requires $jj < numFields($abs);
|
|
requires TO($index) && 0 <= $index; // && $index <= nElems;
|
|
requires Mult(arrayElementWords($vt), $index) >= 0;
|
|
requires reached($abs, $Time);
|
|
requires BigGcInv($freshAbs, ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs, $r1, $r2,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize, $Time);
|
|
requires MarkStack(?gcLo, StackTop, $toAbs, $color, $GcMem, $ptr);
|
|
requires StackTop <= ColorBase;
|
|
requires Pointer($r1, $ptr, $abs);
|
|
requires TV($ptr);
|
|
requires Gray($color[$ptr]);
|
|
requires $vt == $AbsMem[$r1[$ptr]][1];
|
|
requires ObjInvPartial($ptr, 0, $jj, $r2, $r2, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
requires ObjInvPartial($ptr, $jj, numFields($r1[$ptr]), $r2, $r1, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
requires $toAbs[$ptr] != NO_ABS && $toAbs[$ptr] == $r1[$ptr];
|
|
requires (forall j:int::{TO(j)} TO(j) ==>
|
|
between(0, arrayElementWords($vt), j - $jj) ==>
|
|
ObjInvField($ptr, j, $r2, $r1, $toAbs, $AbsMem, $GcMem, $gcSlice));
|
|
|
|
modifies $r2, $color, StackTop, $GcMem;
|
|
modifies eax, ebx, ecx, edx, esi, edi, ebp, esp;
|
|
|
|
ensures BigGcInv($freshAbs, ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs, $r1, $r2,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize, $Time);
|
|
ensures MarkStack(?gcLo, StackTop, $toAbs, $color, $GcMem, $ptr);
|
|
ensures old(StackTop) <= StackTop && StackTop <= ColorBase;
|
|
ensures (forall ss:int::{TV(ss)} TV(ss) ==> HeapHi <= ss && ss < old(StackTop) ==> $GcMem[ss] == old($GcMem)[ss]);
|
|
ensures Gray($color[$ptr]);
|
|
ensures RExtend(old($r2), $r2);
|
|
ensures ObjInvPartial($ptr, 0, $jj, $r2, $r2, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
ensures ObjInvPartial($ptr, $jj + arrayElementWords($vt), numFields($r1[$ptr]), $r2, $r1, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
ensures $toAbs[$ptr] != NO_ABS && $toAbs[$ptr] == $r2[$ptr];
|
|
ensures (forall j:int::{TO(j)} TO(j) ==>
|
|
between(0, arrayElementWords($vt), j - $jj) ==>
|
|
between(1, 8, fieldToSlot(arrayElementClass($vt), j - $jj)) ==>
|
|
ObjInvField($ptr, j, $r2, $r2, $toAbs, $AbsMem, $GcMem, $gcSlice));
|
|
ensures (forall j:int::{TO(j)} TO(j) ==>
|
|
between(0, arrayElementWords($vt), j - $jj) ==>
|
|
!between(1, 8, fieldToSlot(arrayElementClass($vt), j - $jj)) ==>
|
|
ObjInvField($ptr, j, $r2, $r1, $toAbs, $AbsMem, $GcMem, $gcSlice));
|
|
ensures edi == old(edi);
|
|
ensures edx == old(edx);
|
|
{
|
|
var save1:int;
|
|
var save2:int;
|
|
var save3:int;
|
|
var save4:int;
|
|
var save5:int;
|
|
|
|
assert TO(numFields($r2[$ptr]));
|
|
assert TO(2);
|
|
assert TVT($r2[$ptr], $vt);
|
|
assert TVL($r2[$ptr]);
|
|
|
|
esi := 1;
|
|
//while (esi < 8)
|
|
loop:
|
|
assert TSlot(esi) && 0 < esi && esi <= 8;
|
|
assert edx == mask(arrayElementClass($vt));
|
|
assert edi == $jj;
|
|
assert ebp == $ptr;
|
|
|
|
assert BigGcInv($freshAbs, ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs, $r1, $r2,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize, $Time);
|
|
assert MarkStack(?gcLo, StackTop, $toAbs, $color, $GcMem, $ptr);
|
|
assert old(StackTop) <= StackTop && StackTop <= ColorBase;
|
|
assert (forall ss:int::{TV(ss)} TV(ss) ==> HeapHi <= ss && ss < old(StackTop) ==> $GcMem[ss] == old($GcMem)[ss]);
|
|
|
|
assert Gray($color[$ptr]);
|
|
assert RExtend(old($r2), $r2);
|
|
assert ObjInvPartial($ptr, 0, $jj, $r2, $r2, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
assert ObjInvPartial($ptr, $jj + arrayElementWords($vt), numFields($r2[$ptr]), $r2, $r1, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
assert $toAbs[$ptr] != NO_ABS && $toAbs[$ptr] == $r2[$ptr];
|
|
assert (forall j:int::{TO(j)} TO(j) ==>
|
|
between(0, arrayElementWords($vt), j - $jj) ==>
|
|
between(1, esi, fieldToSlot(arrayElementClass($vt), j - $jj)) ==>
|
|
ObjInvField($ptr, j, $r2, $r2, $toAbs, $AbsMem, $GcMem, $gcSlice));
|
|
assert (forall j:int::{TO(j)} TO(j) ==>
|
|
between(0, arrayElementWords($vt), j - $jj) ==>
|
|
!between(1, esi, fieldToSlot(arrayElementClass($vt), j - $jj)) ==>
|
|
ObjInvField($ptr, j, $r2, $r1, $toAbs, $AbsMem, $GcMem, $gcSlice));
|
|
if (esi >= 8) { goto loopEnd; }
|
|
|
|
// ebx := getNib(mask(arrayElementClass($vt)), 4 * esi);
|
|
ecx := 0;
|
|
call ecx := Lea(ecx + 4 * esi);
|
|
ebx := edx;
|
|
call ebx := Shr(ebx, ecx);
|
|
call ebx := And(ebx, 15);
|
|
assert ebx == getNib(mask(arrayElementClass($vt)), 4 * esi);
|
|
|
|
// if (ebx != 0)
|
|
if (ebx == 0) { goto skip1; }
|
|
call ebx := Sub(ebx, 1);
|
|
call ebx := Add(ebx, edi);
|
|
assert TO(ebx);
|
|
|
|
eax := ebp;
|
|
call ecx := GcLoad(eax + 4 * ebx);
|
|
//if (gcAddrEx(ecx))
|
|
if (ecx < ?gcLo) { goto skip2; }
|
|
if (ecx > ?gcHi) { goto skip2; }
|
|
|
|
assert TV(ecx - 4);
|
|
call reach($toAbs[$ptr], ebx, $Time);
|
|
|
|
assert TO(0);
|
|
assert TO(1);
|
|
|
|
save1 := esi;
|
|
save2 := edi;
|
|
save3 := edx;
|
|
save4 := ebx;
|
|
save5 := ebp;
|
|
call visit(ecx, $AbsMem[$toAbs[$ptr]][ebx], $ptr);
|
|
esi := save1;
|
|
edi := save2;
|
|
edx := save3;
|
|
ebx := save4;
|
|
ebp := save5;
|
|
|
|
skip2:
|
|
skip1:
|
|
call esi := Add(esi, 1);
|
|
goto loop;
|
|
loopEnd:
|
|
}
|
|
|
|
procedure scanObjectOtherVectorPointers($vt:int, $ptr:int, $abs:int)
|
|
requires ebx == $ptr;
|
|
requires ecx == $vt;
|
|
requires BigGcInv($freshAbs, ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs, $r1, $r2,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize, $Time);
|
|
requires MarkStack(?gcLo, StackTop, $toAbs, $color, $GcMem, $ptr);
|
|
requires StackTop <= ColorBase;
|
|
requires Pointer($r1, $ptr, $abs);
|
|
requires TV($ptr);
|
|
requires Gray($color[$ptr]);
|
|
requires $vt == $AbsMem[$r1[$ptr]][1];
|
|
requires tag($vt) == ?OTHER_VECTOR_TAG;
|
|
requires arrayOf($vt) == ?TYPE_STRUCT && tag(arrayElementClass($vt)) == ?SPARSE_TAG;
|
|
modifies $r2, $color, StackTop, $GcMem;
|
|
modifies eax, ebx, ecx, edx, esi, edi, ebp, esp;
|
|
ensures BigGcInv($freshAbs, ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs, $r1, $r2,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize, $Time);
|
|
ensures MarkStack(?gcLo, StackTop, $toAbs, $color, $GcMem, $ptr);
|
|
ensures old(StackTop) <= StackTop && StackTop <= ColorBase;
|
|
ensures (forall ss:int::{TV(ss)} TV(ss) ==> HeapHi <= ss && ss < old(StackTop) ==> $GcMem[ss] == old($GcMem)[ss]);
|
|
ensures RExtend(old($r2), $r2);
|
|
ensures (forall j:int::{TO(j)} TO(j) ==> 0 <= j && j < numFields($abs) ==>
|
|
Value(VFieldPtr($abs, j), $r2, $GcMem[$ptr + 4 * j], $AbsMem[$toAbs[$ptr]][j]));
|
|
{
|
|
var save1:int;
|
|
var save2:int;
|
|
var ptr:int;
|
|
|
|
var $index:int;
|
|
|
|
assert TO(numFields($r2[$ptr]));
|
|
assert TO(2);
|
|
assert TVT($r2[$ptr], $vt);
|
|
assert TVL($r2[$ptr]);
|
|
|
|
$index := 0;
|
|
|
|
ptr := ebx;
|
|
edx := ebx;
|
|
|
|
call edi := RoLoad32(ecx + ?VT_BASE_LENGTH);
|
|
call ebx := RoLoad32(ecx + ?VT_ARRAY_ELEMENT_SIZE);
|
|
call edx := GcLoad(edx + 8);
|
|
eax := ebx;
|
|
call eax, edx := MulChecked(eax, edx);
|
|
call eax := AddChecked(eax, edi);
|
|
call eax := AddChecked(eax, 3);
|
|
edx := 3;
|
|
call edx := Not(edx);
|
|
call eax := And(eax, edx);
|
|
ebp := eax;
|
|
call edi := Shr(edi, 2);
|
|
|
|
call ebx := Shr(ebx, 2); // arrayElementWords($vt)
|
|
|
|
assert TVM(ebx, 0);
|
|
call edx := RoLoad32(ecx + ?VT_ARRAY_ELEMENT_CLASS);
|
|
call edx := RoLoad32(edx + ?VT_MASK);
|
|
|
|
//while (4 * edi < ebp)
|
|
loop:
|
|
assert TO($index) && 0 <= $index;
|
|
assert Mult(ebx, $index) >= 0;
|
|
assert TO(edi) && edi == baseWords($vt) + Mult(ebx, $index);
|
|
|
|
assert ebp == 4 * numFields($r2[$ptr]);
|
|
assert edx == mask(arrayElementClass($vt));
|
|
assert ebx == arrayElementWords($vt);
|
|
assert 4 * edi <= ebp;
|
|
|
|
assert Pointer($r2, $ptr, $r1[$ptr]);
|
|
assert BigGcInv($freshAbs, ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs, $r1, $r2,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize, $Time);
|
|
assert old(StackTop) <= StackTop && StackTop <= ColorBase;
|
|
assert (forall ss:int::{TV(ss)} TV(ss) ==> HeapHi <= ss && ss < old(StackTop) ==> $GcMem[ss] == old($GcMem)[ss]);
|
|
assert MarkStack(?gcLo, StackTop, $toAbs, $color, $GcMem, $ptr);
|
|
assert Gray($color[$ptr]);
|
|
assert RExtend(old($r2), $r2);
|
|
assert ObjInvPartial($ptr, 0, edi, $r2, $r2, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
assert ObjInvPartial($ptr, edi, numFields($r2[$ptr]), $r2, $r1, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
assert $toAbs[$ptr] != NO_ABS && $toAbs[$ptr] == $r2[$ptr];
|
|
eax := 0;
|
|
call eax := Lea(eax + 4 * edi);
|
|
if (eax >= ebp) { goto loopEnd; }
|
|
|
|
save1 := ebx;
|
|
save2 := ebp;
|
|
ebp := ptr;
|
|
call scanObjectOtherVectorPointersSparseFields($vt, $ptr, $abs, edi, $index);
|
|
ebx := save1;
|
|
ebp := save2;
|
|
|
|
assert TVM3(ebx, $index, 1);
|
|
assert TVM(ebx, $index);
|
|
$index := $index + 1;
|
|
call edi := Add(edi, ebx);
|
|
goto loop;
|
|
loopEnd:
|
|
|
|
assert TO(1);
|
|
}
|
|
|
|
procedure scanObjectPtrArray($vt:int, $ptr:int, $abs:int)
|
|
requires ebx == $ptr;
|
|
requires ecx == $vt;
|
|
requires BigGcInv($freshAbs, ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs, $r1, $r2,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize, $Time);
|
|
requires MarkStack(?gcLo, StackTop, $toAbs, $color, $GcMem, $ptr);
|
|
requires StackTop <= ColorBase;
|
|
requires Pointer($r1, $ptr, $abs);
|
|
requires TV($ptr);
|
|
requires Gray($color[$ptr]);
|
|
requires $vt == $AbsMem[$r1[$ptr]][1];
|
|
requires tag($vt) == ?PTR_ARRAY_TAG;
|
|
modifies $r2, $color, StackTop, $GcMem;
|
|
modifies eax, ebx, ecx, edx, esi, edi, ebp, esp;
|
|
ensures BigGcInv($freshAbs, ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs, $r1, $r2,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize, $Time);
|
|
ensures MarkStack(?gcLo, StackTop, $toAbs, $color, $GcMem, $ptr);
|
|
ensures old(StackTop) <= StackTop && StackTop <= ColorBase;
|
|
ensures (forall ss:int::{TV(ss)} TV(ss) ==> HeapHi <= ss && ss < old(StackTop) ==> $GcMem[ss] == old($GcMem)[ss]);
|
|
ensures RExtend(old($r2), $r2);
|
|
ensures (forall j:int::{TO(j)} TO(j) ==> 0 <= j && j < numFields($abs) ==>
|
|
Value(VFieldPtr($abs, j), $r2, $GcMem[$ptr + 4 * j], $AbsMem[$toAbs[$ptr]][j]));
|
|
{
|
|
var $ind:int;
|
|
var save1:int;
|
|
var save2:int;
|
|
|
|
assert TO(numFields($r1[$ptr]));
|
|
assert TO(3);
|
|
assert TVT($r1[$ptr], $vt);
|
|
assert TVL($r1[$ptr]);
|
|
|
|
call ebp := GcLoad(ebx + 12);
|
|
call esi := RoLoad32(ecx + ?VT_BASE_LENGTH);
|
|
// size := pad(esi + 4 * ebp);
|
|
call ebp := AddChecked(ebp, ebp);
|
|
call ebp := AddChecked(ebp, ebp);
|
|
call ebp := AddChecked(ebp, esi);
|
|
call ebp := AddChecked(ebp, 3);
|
|
eax := 3;
|
|
call eax := Not(eax);
|
|
call ebp := And(ebp, eax);
|
|
call esi := Shr(esi, 2);
|
|
$ind := esi;
|
|
|
|
call edi := Lea(ebx + 4 * esi);
|
|
call ebp := Add(ebp, ebx);
|
|
|
|
//while (edi < ebp)
|
|
loop:
|
|
assert edi == $ptr + 4 * $ind;
|
|
assert ebp == $ptr + 4 * numFields($r1[$ptr]);
|
|
assert TO($ind) && baseWords($vt) <= $ind; // && $ind <= nElems + 3;
|
|
assert Pointer($r2, $ptr, $r1[$ptr]);
|
|
assert BigGcInv($freshAbs, ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs, $r1, $r2,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize, $Time);
|
|
assert old(StackTop) <= StackTop && StackTop <= ColorBase;
|
|
assert (forall ss:int::{TV(ss)} TV(ss) ==> HeapHi <= ss && ss < old(StackTop) ==> $GcMem[ss] == old($GcMem)[ss]);
|
|
assert MarkStack(?gcLo, StackTop, $toAbs, $color, $GcMem, $ptr);
|
|
assert Gray($color[$ptr]);
|
|
assert RExtend(old($r2), $r2);
|
|
assert ObjInvPartial($ptr, 0, $ind, $r2, $r2, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
assert ObjInvPartial($ptr, $ind, numFields($r1[$ptr]), $r2, $r1, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
assert $toAbs[$ptr] != NO_ABS && $toAbs[$ptr] == $r1[$ptr];
|
|
if (edi >= ebp) { goto loopEnd; }
|
|
|
|
assert TO(0) && TO(1) && TO(3);
|
|
assert TVT($r1[$ptr], $vt);
|
|
assert TVL($r1[$ptr]);
|
|
call ecx := GcLoad(edi);
|
|
//if (gcAddrEx(ecx))
|
|
if (ecx < ?gcLo) { goto skip1; }
|
|
if (ecx > ?gcHi) { goto skip1; }
|
|
assert TV(ecx - 4);
|
|
call reach($toAbs[$ptr], $ind, $Time);
|
|
|
|
save1 := edi;
|
|
save2 := ebp;
|
|
call visit(ecx, $AbsMem[$toAbs[$ptr]][$ind], $ptr);
|
|
edi := save1;
|
|
ebp := save2;
|
|
skip1:
|
|
|
|
$ind := $ind + 1;
|
|
call edi := Add(edi, 4);
|
|
goto loop;
|
|
loopEnd:
|
|
}
|
|
|
|
procedure scanObjectPtrVector($vt:int, $ptr:int, $abs:int)
|
|
requires ebx == $ptr;
|
|
requires ecx == $vt;
|
|
requires BigGcInv($freshAbs, ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs, $r1, $r2,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize, $Time);
|
|
requires MarkStack(?gcLo, StackTop, $toAbs, $color, $GcMem, $ptr);
|
|
requires StackTop <= ColorBase;
|
|
requires Pointer($r1, $ptr, $abs);
|
|
requires TV($ptr);
|
|
requires Gray($color[$ptr]);
|
|
requires $vt == $AbsMem[$r1[$ptr]][1];
|
|
requires tag($vt) == ?PTR_VECTOR_TAG;
|
|
modifies $r2, $color, StackTop, $GcMem;
|
|
modifies eax, ebx, ecx, edx, esi, edi, ebp, esp;
|
|
ensures BigGcInv($freshAbs, ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs, $r1, $r2,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize, $Time);
|
|
ensures MarkStack(?gcLo, StackTop, $toAbs, $color, $GcMem, $ptr);
|
|
ensures old(StackTop) <= StackTop && StackTop <= ColorBase;
|
|
ensures (forall ss:int::{TV(ss)} TV(ss) ==> HeapHi <= ss && ss < old(StackTop) ==> $GcMem[ss] == old($GcMem)[ss]);
|
|
ensures RExtend(old($r2), $r2);
|
|
ensures (forall j:int::{TO(j)} TO(j) ==> 0 <= j && j < numFields($abs) ==>
|
|
Value(VFieldPtr($abs, j), $r2, $GcMem[$ptr + 4 * j], $AbsMem[$toAbs[$ptr]][j]));
|
|
{
|
|
var $ind:int;
|
|
var save1:int;
|
|
var save2:int;
|
|
assert TO(numFields($r1[$ptr]));
|
|
assert TO(2);
|
|
assert TVT($r1[$ptr], $vt);
|
|
assert TVL($r1[$ptr]);
|
|
|
|
call ebp := GcLoad(ebx + 8);
|
|
call esi := RoLoad32(ecx + ?VT_BASE_LENGTH);
|
|
// size := pad(esi + 4 * ebp);
|
|
call ebp := AddChecked(ebp, ebp);
|
|
call ebp := AddChecked(ebp, ebp);
|
|
call ebp := AddChecked(ebp, esi);
|
|
call ebp := AddChecked(ebp, 3);
|
|
eax := 3;
|
|
call eax := Not(eax);
|
|
call ebp := And(ebp, eax);
|
|
call esi := Shr(esi, 2);
|
|
$ind := esi;
|
|
|
|
call edi := Lea(ebx + 4 * esi);
|
|
call ebp := Add(ebp, ebx);
|
|
|
|
//while (edi < ebp)
|
|
loop:
|
|
assert edi == $ptr + 4 * $ind;
|
|
assert ebp == $ptr + 4 * numFields($r1[$ptr]);
|
|
assert TO($ind) && baseWords($vt) <= $ind; // && $ind <= nElems + 3;
|
|
assert Pointer($r2, $ptr, $r1[$ptr]);
|
|
assert BigGcInv($freshAbs, ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs, $r1, $r2,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize, $Time);
|
|
assert old(StackTop) <= StackTop && StackTop <= ColorBase;
|
|
assert (forall ss:int::{TV(ss)} TV(ss) ==> HeapHi <= ss && ss < old(StackTop) ==> $GcMem[ss] == old($GcMem)[ss]);
|
|
assert MarkStack(?gcLo, StackTop, $toAbs, $color, $GcMem, $ptr);
|
|
assert Gray($color[$ptr]);
|
|
assert RExtend(old($r2), $r2);
|
|
assert ObjInvPartial($ptr, 0, $ind, $r2, $r2, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
assert ObjInvPartial($ptr, $ind, numFields($r1[$ptr]), $r2, $r1, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
assert $toAbs[$ptr] != NO_ABS && $toAbs[$ptr] == $r1[$ptr];
|
|
if (edi >= ebp) { goto loopEnd; }
|
|
|
|
assert TO(0) && TO(1) && TO(2);
|
|
assert TVT($r1[$ptr], $vt);
|
|
call ecx := GcLoad(edi);
|
|
//if (gcAddrEx(ecx))
|
|
if (ecx < ?gcLo) { goto skip1; }
|
|
if (ecx > ?gcHi) { goto skip1; }
|
|
assert TV(ecx - 4);
|
|
call reach($toAbs[$ptr], $ind, $Time);
|
|
|
|
save1 := edi;
|
|
save2 := ebp;
|
|
call visit(ecx, $AbsMem[$toAbs[$ptr]][$ind], $ptr);
|
|
edi := save1;
|
|
ebp := save2;
|
|
skip1:
|
|
|
|
$ind := $ind + 1;
|
|
call edi := Add(edi, 4);
|
|
goto loop;
|
|
loopEnd:
|
|
}
|
|
|
|
procedure scanObjectOtherArrayNoPointers($vt:int, $ptr:int, $abs:int)
|
|
requires ebx == $ptr;
|
|
requires ecx == $vt;
|
|
requires BigGcInv($freshAbs, ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs, $r1, $r2,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize, $Time);
|
|
requires MarkStack(?gcLo, StackTop, $toAbs, $color, $GcMem, $ptr);
|
|
requires StackTop <= ColorBase;
|
|
requires Pointer($r1, $ptr, $abs);
|
|
requires TV($ptr);
|
|
requires Gray($color[$ptr]);
|
|
requires $vt == $AbsMem[$r1[$ptr]][1];
|
|
requires tag($vt) == ?OTHER_ARRAY_TAG;
|
|
requires arrayOf($vt) != ?TYPE_STRUCT;
|
|
modifies $r2, $color, StackTop, $GcMem;
|
|
modifies eax, ebx, ecx, edx, esi, edi, ebp, esp;
|
|
ensures BigGcInv($freshAbs, ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs, $r1, $r2,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize, $Time);
|
|
ensures MarkStack(?gcLo, StackTop, $toAbs, $color, $GcMem, $ptr);
|
|
ensures old(StackTop) <= StackTop && StackTop <= ColorBase;
|
|
ensures (forall ss:int::{TV(ss)} TV(ss) ==> HeapHi <= ss && ss < old(StackTop) ==> $GcMem[ss] == old($GcMem)[ss]);
|
|
ensures RExtend(old($r2), $r2);
|
|
ensures (forall j:int::{TO(j)} TO(j) ==> 0 <= j && j < numFields($abs) ==>
|
|
Value(VFieldPtr($abs, j), $r2, $GcMem[$ptr + 4 * j], $AbsMem[$toAbs[$ptr]][j]));
|
|
{
|
|
assert TO(numFields($r1[$ptr]));
|
|
assert TVT($r1[$ptr], $vt);
|
|
}
|
|
|
|
procedure scanObjectString($vt:int, $ptr:int, $abs:int)
|
|
requires ebx == $ptr;
|
|
requires ecx == $vt;
|
|
requires BigGcInv($freshAbs, ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs, $r1, $r2,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize, $Time);
|
|
requires MarkStack(?gcLo, StackTop, $toAbs, $color, $GcMem, $ptr);
|
|
requires StackTop <= ColorBase;
|
|
requires Pointer($r1, $ptr, $abs);
|
|
requires TV($ptr);
|
|
requires Gray($color[$ptr]);
|
|
requires $vt == $AbsMem[$r1[$ptr]][1];
|
|
requires tag($vt) == ?STRING_TAG;
|
|
modifies $r2, $color, StackTop, $GcMem;
|
|
modifies eax, ebx, ecx, edx, esi, edi, ebp, esp;
|
|
ensures BigGcInv($freshAbs, ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs, $r1, $r2,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize, $Time);
|
|
ensures MarkStack(?gcLo, StackTop, $toAbs, $color, $GcMem, $ptr);
|
|
ensures old(StackTop) <= StackTop && StackTop <= ColorBase;
|
|
ensures (forall ss:int::{TV(ss)} TV(ss) ==> HeapHi <= ss && ss < old(StackTop) ==> $GcMem[ss] == old($GcMem)[ss]);
|
|
ensures RExtend(old($r2), $r2);
|
|
ensures (forall j:int::{TO(j)} TO(j) ==> 0 <= j && j < numFields($abs) ==>
|
|
Value(VFieldPtr($abs, j), $r2, $GcMem[$ptr + 4 * j], $AbsMem[$toAbs[$ptr]][j]));
|
|
{
|
|
assert TO(numFields($r1[$ptr]));
|
|
assert TVT($r1[$ptr], $vt);
|
|
}
|
|
|
|
procedure scanObjectOther($vt:int, $ptr:int, $abs:int)
|
|
requires ebx == $ptr;
|
|
requires ecx == $vt;
|
|
requires BigGcInv($freshAbs, ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs, $r1, $r2,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize, $Time);
|
|
requires MarkStack(?gcLo, StackTop, $toAbs, $color, $GcMem, $ptr);
|
|
requires StackTop <= ColorBase;
|
|
requires Pointer($r1, $ptr, $abs);
|
|
requires TV($ptr);
|
|
requires Gray($color[$ptr]);
|
|
requires $vt == $AbsMem[$r1[$ptr]][1];
|
|
requires isOtherTag(tag($vt));
|
|
modifies $r2, $color, StackTop, $GcMem;
|
|
modifies eax, ebx, ecx, edx, esi, edi, ebp, esp;
|
|
ensures BigGcInv($freshAbs, ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs, $r1, $r2,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize, $Time);
|
|
ensures MarkStack(?gcLo, StackTop, $toAbs, $color, $GcMem, $ptr);
|
|
ensures old(StackTop) <= StackTop && StackTop <= ColorBase;
|
|
ensures (forall ss:int::{TV(ss)} TV(ss) ==> HeapHi <= ss && ss < old(StackTop) ==> $GcMem[ss] == old($GcMem)[ss]);
|
|
ensures RExtend(old($r2), $r2);
|
|
ensures (forall j:int::{TO(j)} TO(j) ==> 0 <= j && j < numFields($abs) ==>
|
|
Value(VFieldPtr($abs, j), $r2, $GcMem[$ptr + 4 * j], $AbsMem[$toAbs[$ptr]][j]));
|
|
{
|
|
var save1:int;
|
|
var save2:int;
|
|
var save3:int;
|
|
var save4:int;
|
|
var save5:int;
|
|
var ptr:int;
|
|
ptr := ebx;
|
|
|
|
assert TO(numFields($r1[$ptr]));
|
|
assert TVT($r1[$ptr], $vt);
|
|
assert TVL($r1[$ptr]);
|
|
|
|
call edx := RoLoad32(ecx + ?VT_MASK);
|
|
call edi := RoLoad32(edx);
|
|
call ebp := RoLoad32(ecx + ?VT_BASE_LENGTH);
|
|
|
|
esi := 1;
|
|
|
|
//while (esi < edi + 1)
|
|
loop:
|
|
assert ebp == 4 * numFields($r1[$ptr]);
|
|
assert edx == mask($vt);
|
|
assert edi == ro32(mask($vt));
|
|
assert TSlot(esi) && 0 < esi && esi <= ro32(mask($vt)) + 1;
|
|
assert Pointer($r2, $ptr, $r1[$ptr]);
|
|
assert BigGcInv($freshAbs, ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs, $r1, $r2,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize, $Time);
|
|
assert old(StackTop) <= StackTop && StackTop <= ColorBase;
|
|
assert (forall ss:int::{TV(ss)} TV(ss) ==> HeapHi <= ss && ss < old(StackTop) ==> $GcMem[ss] == old($GcMem)[ss]);
|
|
assert MarkStack(?gcLo, StackTop, $toAbs, $color, $GcMem, $ptr);
|
|
assert Gray($color[$ptr]);
|
|
assert RExtend(old($r2), $r2);
|
|
assert ObjInvBase($ptr, $r2, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
assert (forall j:int::{TO(j)} TO(j) ==> 0 <= j && j < numFields($r1[$ptr]) ==>
|
|
between(1, esi, fieldToSlot($vt, j)) ==>
|
|
ObjInvField($ptr, j, $r2, $r2, $toAbs, $AbsMem, $GcMem, $gcSlice));
|
|
assert (forall j:int::{TO(j)} TO(j) ==> 0 <= j && j < numFields($r1[$ptr]) ==>
|
|
!between(1, esi, fieldToSlot($vt, j)) ==>
|
|
ObjInvField($ptr, j, $r2, $r1, $toAbs, $AbsMem, $GcMem, $gcSlice));
|
|
assert $toAbs[$ptr] != NO_ABS && $toAbs[$ptr] == $r1[$ptr];
|
|
if (esi > edi) { goto loopEnd; }
|
|
|
|
assert TO(0) && TO(1);
|
|
assert TVT($r1[$ptr], $vt);
|
|
assert TVL($r1[$ptr]);
|
|
assert TO(ro32(mask($vt) + 4 * esi) + 1);
|
|
call ebx := RoLoad32(edx + 4 * esi);
|
|
//if (ebx != 0)
|
|
if (ebx == 0) { goto skip1; }
|
|
eax := ptr;
|
|
call ecx := GcLoad(eax + 4 * ebx + 4);
|
|
|
|
//if (gcAddrEx(ecx))
|
|
if (ecx < ?gcLo) { goto skip2; }
|
|
if (ecx > ?gcHi) { goto skip2; }
|
|
assert TV(ecx - 4);
|
|
call reach($toAbs[$ptr], 1 + ro32(edx + 4 * esi), $Time);
|
|
|
|
save1 := ebx;
|
|
save2 := esi;
|
|
save3 := edi;
|
|
save4 := ebp;
|
|
save5 := edx;
|
|
call visit(ecx, $AbsMem[$toAbs[$ptr]][1 + ro32(edx + 4 * esi)], $ptr);
|
|
ebx := save1;
|
|
esi := save2;
|
|
edi := save3;
|
|
ebp := save4;
|
|
edx := save5;
|
|
skip2:
|
|
skip1:
|
|
call esi := AddChecked(esi, 1);
|
|
goto loop;
|
|
loopEnd:
|
|
|
|
assert TVT($r1[$ptr], $vt);
|
|
assert TVL($r1[$ptr]);
|
|
}
|
|
|
|
procedure scanObject($ptr:int, $abs:int)
|
|
requires ebx == $ptr;
|
|
requires $abs == $r1[$ptr];
|
|
requires BigGcInv($freshAbs, ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs, $r1, $r2,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize, $Time);
|
|
requires Pointer($r1, $ptr, $abs);
|
|
requires TV($ptr);
|
|
requires Gray($color[$ptr]);
|
|
requires MarkStack(?gcLo, StackTop, $toAbs, $color, $GcMem, $ptr);
|
|
requires StackTop <= ColorBase;
|
|
|
|
modifies $r2, $color;
|
|
modifies eax, ebx, ecx, edx, esi, edi, ebp, esp;
|
|
modifies StackTop, $GcMem;
|
|
|
|
ensures old(StackTop) <= StackTop && StackTop <= ColorBase;
|
|
ensures (forall ss:int::{TV(ss)} TV(ss) ==> HeapHi <= ss && ss < old(StackTop) ==> $GcMem[ss] == old($GcMem)[ss]);
|
|
ensures BigGcInv($freshAbs, ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs, $r1, $r2,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize, $Time);
|
|
ensures MarkStack(?gcLo, StackTop, $toAbs, $color, $GcMem, $ptr);
|
|
ensures RExtend(old($r2), $r2);
|
|
ensures (forall j:int::{TO(j)} TO(j) ==> 0 <= j && j < numFields($abs) ==>
|
|
Value(VFieldPtr($abs, j), $r2, $GcMem[$ptr + 4 * j], $AbsMem[$toAbs[$ptr]][j]));
|
|
{
|
|
var $vt:int;
|
|
|
|
assert TO(1);
|
|
call ecx := GcLoad(ebx + 4);
|
|
$vt := ecx;
|
|
|
|
assert TO(numFields($r1[$ptr]));
|
|
|
|
call readTag($toAbs[$ptr], $vt);
|
|
|
|
if (eax != ?SPARSE_TAG) { goto skip1; }
|
|
call scanObjectSparse($vt, $ptr, $abs);
|
|
goto end;
|
|
skip1:
|
|
|
|
if (eax != ?DENSE_TAG) { goto skip2; }
|
|
call scanObjectDense($vt, $ptr, $abs);
|
|
goto end;
|
|
skip2:
|
|
|
|
if (eax != ?STRING_TAG) { goto skip3; }
|
|
call scanObjectString($vt, $ptr, $abs);
|
|
goto end;
|
|
skip3:
|
|
|
|
if (eax != ?PTR_VECTOR_TAG) { goto skip4; }
|
|
call scanObjectPtrVector($vt, $ptr, $abs);
|
|
goto end;
|
|
skip4:
|
|
|
|
if (eax != ?OTHER_VECTOR_TAG) { goto skip5; }
|
|
call readArrayOf($r1[$ptr], $vt);
|
|
call readElementInfo($r1[$ptr], $vt);
|
|
if (ebp != ?TYPE_STRUCT) { goto noPoint; }
|
|
if (ebp != ?TYPE_STRUCT) { goto vecSkip1; }
|
|
if (edi != ?SPARSE_TAG) { goto vecSkip1; }
|
|
noPoint:
|
|
call scanObjectOtherVectorNoPointers($vt, $ptr, $abs);
|
|
goto end;
|
|
vecSkip1:
|
|
if (ebp != ?TYPE_STRUCT) { goto vecSkip2; }
|
|
|
|
//if (tag(arrayElementClass(vt)) != ?SPARSE_TAG) { goto vecSkip2; }
|
|
eax := edi;
|
|
call eax := And(eax, 15);
|
|
if (eax != ?SPARSE_TAG) { goto vecSkip2; }
|
|
|
|
call scanObjectOtherVectorPointers($vt, $ptr, $abs);
|
|
goto end;
|
|
|
|
vecSkip2:
|
|
assert !(
|
|
(ebp != ?TYPE_STRUCT)
|
|
|| (ebp == ?TYPE_STRUCT && edi == ?SPARSE_TAG)
|
|
|| (ebp == ?TYPE_STRUCT && tag(arrayElementClass($vt)) == ?SPARSE_TAG));
|
|
call DebugBreak();
|
|
|
|
skip5:
|
|
|
|
if (eax != ?PTR_ARRAY_TAG) { goto skip6; }
|
|
call scanObjectPtrArray($vt, $ptr, $abs);
|
|
goto end;
|
|
skip6:
|
|
|
|
if (eax != ?OTHER_ARRAY_TAG) { goto skip7; }
|
|
call readArrayOf($r1[$ptr], $vt);
|
|
if (ebp == ?TYPE_STRUCT) { goto arraySkip1; }
|
|
call scanObjectOtherArrayNoPointers($vt, $ptr, $abs);
|
|
goto end;
|
|
arraySkip1:
|
|
call DebugBreak();
|
|
goto end;
|
|
skip7:
|
|
|
|
call scanObjectOther($vt, $ptr, $abs);
|
|
end:
|
|
}
|
|
|
|
procedure FromInteriorPointer($iptr:int, $offset:int, $abs:int)
|
|
requires ecx == $iptr;
|
|
requires BigGcInv($freshAbs, ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs, $r1, $r2,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize, $Time);
|
|
requires 0 <= $offset && $offset <= 4 * numFields($abs) - 4;
|
|
requires Pointer($r1, $iptr - $offset - 4, $abs);
|
|
modifies eax, ebx, ecx, edx, esp;
|
|
ensures eax == $offset;
|
|
{
|
|
var save1:int;
|
|
var save2:int;
|
|
|
|
eax := 0;
|
|
// while ($r1[$iptr - eax - 4] == NO_ABS)
|
|
loop:
|
|
assert $iptr - $offset <= $iptr - eax && $iptr - eax <= $iptr;
|
|
assert TV($iptr - eax - 4) && TV($iptr - $offset - 4);
|
|
assert ecx == $iptr;
|
|
|
|
assert TV(?gcLo);
|
|
assert TO($iptr - eax - 4 - HeapLo);
|
|
|
|
ebx := ecx;
|
|
call ebx := Sub(ebx, eax);
|
|
call ebx := Sub(ebx, 4);
|
|
call ebx := Sub(ebx, HeapLo);
|
|
edx := ebx;
|
|
call edx := And(edx, 3);
|
|
call __andAligned(ebx);
|
|
call __addAligned(HeapLo, ebx);
|
|
if (edx != 0)
|
|
{
|
|
goto skip1;
|
|
}
|
|
|
|
save1 := eax;
|
|
save2 := ecx;
|
|
eax := ColorBase;
|
|
call bb4GetColor($color, HeapLo, HeapLo, HeapLo, HeapHi, $iptr - save1 - 4, ColorBase, HeapLo);
|
|
eax := save1;
|
|
ecx := save2;
|
|
|
|
if (ebx == 0) { goto skip1; }
|
|
esp := esp + 4; return;
|
|
skip1:
|
|
call eax := Add(eax, 1);
|
|
goto loop;
|
|
}
|
|
|
|
procedure scanStackUpdateInvs($r:[int]int, $f1:int, $f2:int, $frame:int, $addr:int, $v:int)
|
|
requires $FrameSlice[$addr] == $frame;
|
|
requires !($f1 <= $frame && $frame < $f2);
|
|
requires (forall f:int::{TV(f)} TV(f) ==> $f1 <= f && f < $f2 ==>
|
|
FrameInv(f, $FrameLayout[f], $r, $FrameAddr, $FrameSlice, $FrameLayout, $FrameMem, $FrameAbs, $FrameOffset, $Time));
|
|
ensures (forall f:int::{TV(f)} TV(f) ==> $f1 <= f && f < $f2 ==>
|
|
FrameInv(f, $FrameLayout[f], $r, $FrameAddr, $FrameSlice, $FrameLayout, $FrameMem[$addr := $v], $FrameAbs, $FrameOffset, $Time));
|
|
{
|
|
assert TO(0) && TO(1);
|
|
assert (forall f:int::{TV(f)} TV(f) ==> TVF($FrameLayout[f]) && TVFT(f));
|
|
}
|
|
|
|
procedure scanStackWordDense($frame:int, $addr:int, $desc:int, $addrp:int, $p:int, $args:int)
|
|
requires ecx == $addrp;
|
|
requires BigGcInv($freshAbs, ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs, $r1, $r2,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize, $Time);
|
|
requires MarkStack(?gcLo, StackTop, $toAbs, $color, $GcMem, 0);
|
|
requires StackTop <= ColorBase;
|
|
requires $desc == frameDescriptor($FrameLayout[$frame]);
|
|
requires $addr == $FrameAddr[$frame];
|
|
requires $FrameSlice[$addrp] == $frame;
|
|
requires $args == frameLayoutArgs($FrameLayout[$frame]);
|
|
requires $addrp == $addr + 4 * $p;
|
|
requires getBit($desc, 0) && !getBit($desc, 1) && and(shr($desc, 6), 1023) == 0;
|
|
requires frameHasPtr($FrameLayout[$frame], $p);
|
|
requires 0 <= $frame && $frame < $FrameCount && TV($frame);
|
|
requires (forall f:int::{TV(f)} TV(f) ==> 0 <= f && f < $frame ==>
|
|
FrameInv(f, $FrameLayout[f], $r1, $FrameAddr, $FrameSlice, $FrameLayout, $FrameMem, $FrameAbs, $FrameOffset, $Time));
|
|
requires (forall f:int::{TV(f)} TV(f) ==> $frame < f && f < $FrameCount ==>
|
|
FrameInv(f, $FrameLayout[f], $r2, $FrameAddr, $FrameSlice, $FrameLayout, $FrameMem, $FrameAbs, $FrameOffset, $Time));
|
|
|
|
requires $p <= 1 + $args && $p > $args - 1 - 16 && TO($p);
|
|
requires (forall f:int::{TV(f)} TV(f) ==> 0 <= f && f < $frame ==>
|
|
FrameInv(f, $FrameLayout[f], $r1, $FrameAddr, $FrameSlice, $FrameLayout, $FrameMem, $FrameAbs, $FrameOffset, $Time));
|
|
requires (forall f:int::{TV(f)} TV(f) ==> $frame < f && f < $FrameCount ==>
|
|
FrameInv(f, $FrameLayout[f], $r2, $FrameAddr, $FrameSlice, $FrameLayout, $FrameMem, $FrameAbs, $FrameOffset, $Time));
|
|
requires FrameNextInv($frame, $FrameMem[$FrameAddr[$frame] + 4], $FrameMem[$FrameAddr[$frame]], $FrameAddr, $FrameLayout);
|
|
requires (forall j:int::{TO(j)} TO(j) ==> inFrame($FrameLayout[$frame], j) && j <= $p ==>
|
|
$FrameSlice[$addr + 4 * j] == $frame
|
|
&& InteriorValue(frameHasPtr($FrameLayout[$frame], j), $r1, $FrameMem[$addr + 4 * j], $FrameAbs[$frame][j], $FrameOffset[$addr + 4 * j])
|
|
&& (frameHasPtr($FrameLayout[$frame], j) && gcAddrEx($FrameMem[$addr + 4 * j]) ==> reached($FrameAbs[$frame][j], $Time))
|
|
);
|
|
requires (forall j:int::{TO(j)} TO(j) ==> inFrame($FrameLayout[$frame], j) && j > $p ==>
|
|
$FrameSlice[$addr + 4 * j] == $frame
|
|
&& InteriorValue(frameHasPtr($FrameLayout[$frame], j), $r2, $FrameMem[$addr + 4 * j], $FrameAbs[$frame][j], $FrameOffset[$addr + 4 * j])
|
|
&& (frameHasPtr($FrameLayout[$frame], j) && gcAddrEx($FrameMem[$addr + 4 * j]) ==> reached($FrameAbs[$frame][j], $Time))
|
|
);
|
|
|
|
modifies $r2, $color;
|
|
modifies eax, ebx, ecx, edx, esi, edi, ebp, esp;
|
|
modifies StackTop, $GcMem;
|
|
|
|
ensures (forall f:int::{TV(f)} TV(f) ==> 0 <= f && f < $frame ==>
|
|
FrameInv(f, $FrameLayout[f], $r1, $FrameAddr, $FrameSlice, $FrameLayout, $FrameMem, $FrameAbs, $FrameOffset, $Time));
|
|
ensures (forall f:int::{TV(f)} TV(f) ==> $frame < f && f < $FrameCount ==>
|
|
FrameInv(f, $FrameLayout[f], $r2, $FrameAddr, $FrameSlice, $FrameLayout, $FrameMem, $FrameAbs, $FrameOffset, $Time));
|
|
ensures FrameNextInv($frame, $FrameMem[$FrameAddr[$frame] + 4], $FrameMem[$FrameAddr[$frame]], $FrameAddr, $FrameLayout);
|
|
ensures (forall j:int::{TO(j)} TO(j) ==> inFrame($FrameLayout[$frame], j) && j <= $p - 1 ==>
|
|
$FrameSlice[$addr + 4 * j] == $frame
|
|
&& InteriorValue(frameHasPtr($FrameLayout[$frame], j), $r1, $FrameMem[$addr + 4 * j], $FrameAbs[$frame][j], $FrameOffset[$addr + 4 * j])
|
|
&& (frameHasPtr($FrameLayout[$frame], j) && gcAddrEx($FrameMem[$addr + 4 * j]) ==> reached($FrameAbs[$frame][j], $Time))
|
|
);
|
|
ensures (forall j:int::{TO(j)} TO(j) ==> inFrame($FrameLayout[$frame], j) && j > $p - 1 ==>
|
|
$FrameSlice[$addr + 4 * j] == $frame
|
|
&& InteriorValue(frameHasPtr($FrameLayout[$frame], j), $r2, $FrameMem[$addr + 4 * j], $FrameAbs[$frame][j], $FrameOffset[$addr + 4 * j])
|
|
&& (frameHasPtr($FrameLayout[$frame], j) && gcAddrEx($FrameMem[$addr + 4 * j]) ==> reached($FrameAbs[$frame][j], $Time))
|
|
);
|
|
ensures BigGcInv($freshAbs, ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs, $r1, $r2,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize, $Time);
|
|
ensures MarkStack(?gcLo, StackTop, $toAbs, $color, $GcMem, 0);
|
|
ensures StackTop <= ColorBase;
|
|
ensures RExtend(old($r2), $r2);
|
|
{
|
|
var save1:int;
|
|
var v:int;
|
|
var offset:int;
|
|
assert TVF($FrameLayout[$frame]);
|
|
assert TV($FrameMem[$addrp] - 4);
|
|
|
|
call eax := FrameLoad(($frame), ecx);
|
|
//if (gcAddrEx(eax))
|
|
if (eax < ?gcLo) { goto skip1; }
|
|
if (eax > ?gcHi) { goto skip1; }
|
|
save1 := ecx;
|
|
v := eax;
|
|
|
|
ecx := eax;
|
|
esp := esp - 4; call FromInteriorPointer(v, $FrameOffset[$addrp], $FrameAbs[$frame][$p]);
|
|
offset := eax;
|
|
|
|
ecx := v;
|
|
call ecx := Sub(ecx, eax);
|
|
assert TV(ecx - 4);
|
|
|
|
call visit(ecx, $FrameAbs[$frame][$p], 0);
|
|
|
|
assert TV(eax - 4);
|
|
call scanStackUpdateInvs($r1, 0, $frame, $frame, $addrp, eax + offset);
|
|
call scanStackUpdateInvs($r2, $frame + 1, $FrameCount, $frame, $addrp, eax + offset);
|
|
|
|
ecx := save1;
|
|
skip1:
|
|
}
|
|
|
|
procedure scanStackDense($frame:int, $addr:int, $desc:int)
|
|
requires ecx == $addr;
|
|
requires edx == $desc;
|
|
requires $desc == frameDescriptor($FrameLayout[$frame]);
|
|
requires $addr == $FrameAddr[$frame];
|
|
requires getBit($desc, 0) && !getBit($desc, 1) && and(shr($desc, 6), 1023) == 0;
|
|
requires 0 <= $frame && $frame < $FrameCount && TV($frame);
|
|
requires (forall f:int::{TV(f)} TV(f) ==> 0 <= f && f <= $frame ==>
|
|
FrameInv(f, $FrameLayout[f], $r1, $FrameAddr, $FrameSlice, $FrameLayout, $FrameMem, $FrameAbs, $FrameOffset, $Time));
|
|
requires (forall f:int::{TV(f)} TV(f) ==> $frame < f && f < $FrameCount ==>
|
|
FrameInv(f, $FrameLayout[f], $r2, $FrameAddr, $FrameSlice, $FrameLayout, $FrameMem, $FrameAbs, $FrameOffset, $Time));
|
|
requires BigGcInv($freshAbs, ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs, $r1, $r2,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize, $Time);
|
|
requires MarkStack(?gcLo, StackTop, $toAbs, $color, $GcMem, 0);
|
|
requires StackTop <= ColorBase;
|
|
|
|
modifies $r2, $color;
|
|
modifies eax, ebx, ecx, edx, esi, edi, ebp, esp;
|
|
modifies StackTop, $GcMem;
|
|
|
|
ensures (forall f:int::{TV(f)} TV(f) ==> 0 <= f && f <= $frame - 1 ==>
|
|
FrameInv(f, $FrameLayout[f], $r1, $FrameAddr, $FrameSlice, $FrameLayout, $FrameMem, $FrameAbs, $FrameOffset, $Time));
|
|
ensures (forall f:int::{TV(f)} TV(f) ==> $frame - 1 < f && f < $FrameCount ==>
|
|
FrameInv(f, $FrameLayout[f], $r2, $FrameAddr, $FrameSlice, $FrameLayout, $FrameMem, $FrameAbs, $FrameOffset, $Time));
|
|
ensures BigGcInv($freshAbs, ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs, $r1, $r2,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize, $Time);
|
|
ensures MarkStack(?gcLo, StackTop, $toAbs, $color, $GcMem, 0);
|
|
ensures StackTop <= ColorBase;
|
|
ensures RExtend(old($r2), $r2);
|
|
{
|
|
var b:int;
|
|
var v:int;
|
|
var offset:int;
|
|
var args:int;
|
|
var addr:int;
|
|
var desc:int;
|
|
var addrp:int;
|
|
assert TVF($FrameLayout[$frame]);
|
|
assert TO(0);
|
|
|
|
addr := ecx;
|
|
desc := edx;
|
|
|
|
eax := edx;
|
|
call eax := Shr(eax, 2);
|
|
call eax := And(eax, 15);
|
|
args := eax; // frameLayoutArgs($FrameLayout[$frame]);
|
|
b := 0;
|
|
ebx := 0;
|
|
call ebx := Lea(ebx + 4 * eax + 4);
|
|
call ebx := AddChecked(ebx, ecx);
|
|
addrp := ebx;
|
|
|
|
//while (b < args)
|
|
loop1:
|
|
assert addrp == $addr + 4 * (args + 1 - b);
|
|
assert $frame < $FrameCount && TV($frame);
|
|
assert 0 <= b && b <= args && TO(args + 1 - b);
|
|
assert (forall f:int::{TV(f)} TV(f) ==> 0 <= f && f < $frame ==>
|
|
FrameInv(f, $FrameLayout[f], $r1, $FrameAddr, $FrameSlice, $FrameLayout, $FrameMem, $FrameAbs, $FrameOffset, $Time));
|
|
assert (forall f:int::{TV(f)} TV(f) ==> $frame < f && f < $FrameCount ==>
|
|
FrameInv(f, $FrameLayout[f], $r2, $FrameAddr, $FrameSlice, $FrameLayout, $FrameMem, $FrameAbs, $FrameOffset, $Time));
|
|
|
|
assert FrameNextInv($frame, $FrameMem[$FrameAddr[$frame] + 4], $FrameMem[$FrameAddr[$frame]], $FrameAddr, $FrameLayout);
|
|
|
|
assert (forall j:int::{TO(j)} TO(j) ==> inFrame($FrameLayout[$frame], j) && j <= (args + 1 - b) ==>
|
|
$FrameSlice[$addr + 4 * j] == $frame
|
|
&& InteriorValue(frameHasPtr($FrameLayout[$frame], j), $r1, $FrameMem[$addr + 4 * j], $FrameAbs[$frame][j], $FrameOffset[$addr + 4 * j])
|
|
&& (frameHasPtr($FrameLayout[$frame], j) && gcAddrEx($FrameMem[$addr + 4 * j]) ==> reached($FrameAbs[$frame][j], $Time))
|
|
);
|
|
|
|
assert (forall j:int::{TO(j)} TO(j) ==> inFrame($FrameLayout[$frame], j) && j > (args + 1 - b) ==>
|
|
$FrameSlice[$addr + 4 * j] == $frame
|
|
&& InteriorValue(frameHasPtr($FrameLayout[$frame], j), $r2, $FrameMem[$addr + 4 * j], $FrameAbs[$frame][j], $FrameOffset[$addr + 4 * j])
|
|
&& (frameHasPtr($FrameLayout[$frame], j) && gcAddrEx($FrameMem[$addr + 4 * j]) ==> reached($FrameAbs[$frame][j], $Time))
|
|
);
|
|
|
|
assert BigGcInv($freshAbs, ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs, $r1, $r2,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize, $Time);
|
|
assert MarkStack(?gcLo, StackTop, $toAbs, $color, $GcMem, 0);
|
|
assert StackTop <= ColorBase;
|
|
assert RExtend(old($r2), $r2);
|
|
eax := b;
|
|
if (eax >= args) { goto loopEnd1; }
|
|
|
|
assert TVF($FrameLayout[$frame]);
|
|
call ecx := Lea(eax + 16);
|
|
ebx := desc;
|
|
call ebx := Shr(ebx, ecx);
|
|
call ebx := And(ebx, 1);
|
|
//if (getBit($desc, 16 + b))
|
|
if (ebx != 1) { goto skip1; }
|
|
ecx := addrp;
|
|
call scanStackWordDense($frame, $addr, $desc, $addr + 4 * (args + 1 - b), args + 1 - b, args);
|
|
skip1:
|
|
|
|
call b := Add(b, 1);
|
|
call addrp := Sub(addrp, 4);
|
|
goto loop1;
|
|
loopEnd1:
|
|
|
|
assert TO(0);
|
|
assert TO(1);
|
|
assert TV($FrameMem[$addr]);
|
|
assert TV($FrameMem[$addr] - 4);
|
|
|
|
call addrp := SubChecked(addrp, 8);
|
|
|
|
//while (b < 16)
|
|
loop2:
|
|
assert addrp == $addr + 4 * (args - 1 - b);
|
|
assert $frame < $FrameCount && TV($frame);
|
|
assert (args - 1 - b) < 0 && (args - 1 - b) <= 1 + args && TO(args - 1 - b);
|
|
assert (forall f:int::{TV(f)} TV(f) ==> 0 <= f && f < $frame ==>
|
|
FrameInv(f, $FrameLayout[f], $r1, $FrameAddr, $FrameSlice, $FrameLayout, $FrameMem, $FrameAbs, $FrameOffset, $Time));
|
|
assert (forall f:int::{TV(f)} TV(f) ==> $frame < f && f < $FrameCount ==>
|
|
FrameInv(f, $FrameLayout[f], $r2, $FrameAddr, $FrameSlice, $FrameLayout, $FrameMem, $FrameAbs, $FrameOffset, $Time));
|
|
|
|
assert FrameNextInv($frame, $FrameMem[$FrameAddr[$frame] + 4], $FrameMem[$FrameAddr[$frame]], $FrameAddr, $FrameLayout);
|
|
|
|
assert (forall j:int::{TO(j)} TO(j) ==> inFrame($FrameLayout[$frame], j) && j <= (args - 1 - b) ==>
|
|
$FrameSlice[$addr + 4 * j] == $frame
|
|
&& InteriorValue(frameHasPtr($FrameLayout[$frame], j), $r1, $FrameMem[$addr + 4 * j], $FrameAbs[$frame][j], $FrameOffset[$addr + 4 * j])
|
|
&& (frameHasPtr($FrameLayout[$frame], j) && gcAddrEx($FrameMem[$addr + 4 * j]) ==> reached($FrameAbs[$frame][j], $Time))
|
|
);
|
|
|
|
assert (forall j:int::{TO(j)} TO(j) ==> inFrame($FrameLayout[$frame], j) && j > (args - 1 - b) ==>
|
|
$FrameSlice[$addr + 4 * j] == $frame
|
|
&& InteriorValue(frameHasPtr($FrameLayout[$frame], j), $r2, $FrameMem[$addr + 4 * j], $FrameAbs[$frame][j], $FrameOffset[$addr + 4 * j])
|
|
&& (frameHasPtr($FrameLayout[$frame], j) && gcAddrEx($FrameMem[$addr + 4 * j]) ==> reached($FrameAbs[$frame][j], $Time))
|
|
);
|
|
|
|
assert BigGcInv($freshAbs, ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs, $r1, $r2,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize, $Time);
|
|
assert MarkStack(?gcLo, StackTop, $toAbs, $color, $GcMem, 0);
|
|
assert StackTop <= ColorBase;
|
|
assert RExtend(old($r2), $r2);
|
|
eax := b;
|
|
if (eax >= 16) { goto loopEnd2; }
|
|
|
|
assert TVF($FrameLayout[$frame]);
|
|
call ecx := Lea(eax + 16);
|
|
ebx := desc;
|
|
call ebx := Shr(ebx, ecx);
|
|
call ebx := And(ebx, 1);
|
|
//if (getBit($desc, 16 + b))
|
|
if (ebx != 1) { goto skip2; }
|
|
ecx := addrp;
|
|
call scanStackWordDense($frame, $addr, $desc, $addr + 4 * (args - 1 - b), args - 1 - b, args);
|
|
skip2:
|
|
call b := Add(b, 1);
|
|
call addrp := SubChecked(addrp, 4);
|
|
goto loop2;
|
|
loopEnd2:
|
|
}
|
|
|
|
procedure scanStackSparse8($frame:int, $addr:int, $desc:int)
|
|
requires ecx == $addr;
|
|
requires edx == $desc;
|
|
requires $desc == frameDescriptor($FrameLayout[$frame]);
|
|
requires $addr == $FrameAddr[$frame];
|
|
requires !getBit($desc, 0) && ro32($desc) == 4096;
|
|
requires 0 <= $frame && $frame < $FrameCount && TV($frame);
|
|
requires (forall f:int::{TV(f)} TV(f) ==> 0 <= f && f <= $frame ==>
|
|
FrameInv(f, $FrameLayout[f], $r1, $FrameAddr, $FrameSlice, $FrameLayout, $FrameMem, $FrameAbs, $FrameOffset, $Time));
|
|
requires (forall f:int::{TV(f)} TV(f) ==> $frame < f && f < $FrameCount ==>
|
|
FrameInv(f, $FrameLayout[f], $r2, $FrameAddr, $FrameSlice, $FrameLayout, $FrameMem, $FrameAbs, $FrameOffset, $Time));
|
|
requires BigGcInv($freshAbs, ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs, $r1, $r2,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize, $Time);
|
|
requires MarkStack(?gcLo, StackTop, $toAbs, $color, $GcMem, 0);
|
|
requires StackTop <= ColorBase;
|
|
|
|
modifies $r2, $color;
|
|
modifies eax, ebx, ecx, edx, esi, edi, ebp, esp;
|
|
modifies StackTop, $GcMem;
|
|
|
|
ensures (forall f:int::{TV(f)} TV(f) ==> 0 <= f && f <= $frame - 1 ==>
|
|
FrameInv(f, $FrameLayout[f], $r1, $FrameAddr, $FrameSlice, $FrameLayout, $FrameMem, $FrameAbs, $FrameOffset, $Time));
|
|
ensures (forall f:int::{TV(f)} TV(f) ==> $frame - 1 < f && f < $FrameCount ==>
|
|
FrameInv(f, $FrameLayout[f], $r2, $FrameAddr, $FrameSlice, $FrameLayout, $FrameMem, $FrameAbs, $FrameOffset, $Time));
|
|
ensures BigGcInv($freshAbs, ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs, $r1, $r2,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize, $Time);
|
|
ensures MarkStack(?gcLo, StackTop, $toAbs, $color, $GcMem, 0);
|
|
ensures StackTop <= ColorBase;
|
|
ensures RExtend(old($r2), $r2);
|
|
{
|
|
var p:int;
|
|
var v:int;
|
|
var addr:int;
|
|
var desc:int;
|
|
var addrp:int;
|
|
var offset:int;
|
|
var count:int;
|
|
assert TVF($FrameLayout[$frame]);
|
|
assert TO(0);
|
|
|
|
addr := ecx;
|
|
desc := edx;
|
|
|
|
p := 0;
|
|
call eax := RoLoadU8(edx + 4);
|
|
count := eax;
|
|
//while (p < count)
|
|
loop:
|
|
assert p >= 0 && TSlot(p);
|
|
|
|
assert (forall f:int::{TV(f)} TV(f) ==> 0 <= f && f < $frame ==>
|
|
FrameInv(f, $FrameLayout[f], $r1, $FrameAddr, $FrameSlice, $FrameLayout, $FrameMem, $FrameAbs, $FrameOffset, $Time));
|
|
assert (forall f:int::{TV(f)} TV(f) ==> $frame < f && f < $FrameCount ==>
|
|
FrameInv(f, $FrameLayout[f], $r2, $FrameAddr, $FrameSlice, $FrameLayout, $FrameMem, $FrameAbs, $FrameOffset, $Time));
|
|
|
|
assert FrameNextInv($frame, $FrameMem[$FrameAddr[$frame] + 4], $FrameMem[$FrameAddr[$frame]], $FrameAddr, $FrameLayout);
|
|
|
|
assert (forall j:int::{TO(j)} TO(j) ==> inFrame($FrameLayout[$frame], j) && !between(0, p, frameFieldToSlot($FrameLayout[$frame], j)) ==>
|
|
$FrameSlice[addr + 4 * j] == $frame
|
|
&& InteriorValue(frameHasPtr($FrameLayout[$frame], j), $r1, $FrameMem[addr + 4 * j], $FrameAbs[$frame][j], $FrameOffset[addr + 4 * j])
|
|
&& (frameHasPtr($FrameLayout[$frame], j) && gcAddrEx($FrameMem[addr + 4 * j]) ==> reached($FrameAbs[$frame][j], $Time))
|
|
);
|
|
|
|
assert (forall j:int::{TO(j)} TO(j) ==> inFrame($FrameLayout[$frame], j) && between(0, p, frameFieldToSlot($FrameLayout[$frame], j)) ==>
|
|
$FrameSlice[addr + 4 * j] == $frame
|
|
&& InteriorValue(frameHasPtr($FrameLayout[$frame], j), $r2, $FrameMem[addr + 4 * j], $FrameAbs[$frame][j], $FrameOffset[addr + 4 * j])
|
|
&& (frameHasPtr($FrameLayout[$frame], j) && gcAddrEx($FrameMem[addr + 4 * j]) ==> reached($FrameAbs[$frame][j], $Time))
|
|
);
|
|
|
|
assert BigGcInv($freshAbs, ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs, $r1, $r2,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize, $Time);
|
|
assert MarkStack(?gcLo, StackTop, $toAbs, $color, $GcMem, 0);
|
|
assert StackTop <= ColorBase;
|
|
assert RExtend(old($r2), $r2);
|
|
eax := p;
|
|
if (eax >= count) { goto loopEnd; }
|
|
|
|
assert TO(roS8(desc + 6 + p));
|
|
assert TV($FrameMem[addr + 4 * roS8(desc + 6 + p)] - 4);
|
|
ebx := desc;
|
|
esi := addr;
|
|
call ebp := RoLoadS8(ebx + 1 * eax + 6);
|
|
call ebp := LeaSignedIndex(esi, 4, ebp, 0);
|
|
addrp := ebp;
|
|
call ecx := FrameLoad(($frame), ebp);
|
|
//if (gcAddrEx(ecx))
|
|
if (ecx < ?gcLo) { goto skip1; }
|
|
if (ecx > ?gcHi) { goto skip1; }
|
|
v := ecx;
|
|
esp := esp - 4; call FromInteriorPointer(v, $FrameOffset[addr + 4 * roS8(desc + 6 + p)], $FrameAbs[$frame][roS8(desc + 6 + p)]);
|
|
offset := eax;
|
|
|
|
ecx := v;
|
|
call ecx := Sub(ecx, eax);
|
|
assert TV(ecx - 4);
|
|
|
|
call visit(ecx, $FrameAbs[$frame][roS8(desc + 6 + p)], 0);
|
|
assert TV(eax - 4);
|
|
call scanStackUpdateInvs($r1, 0, $frame, $frame, addr + 4 * roS8(desc + 6 + p), eax);
|
|
call scanStackUpdateInvs($r2, $frame + 1, $FrameCount, $frame, addr + 4 * roS8(desc + 6 + p), eax);
|
|
ebx := addrp;
|
|
skip1:
|
|
|
|
// This is just here to improve performance:
|
|
assert (forall j:int::{TO(j)} TO(j) ==> inFrame($FrameLayout[$frame], j) &&
|
|
p == frameFieldToSlot($FrameLayout[$frame], j) ==> j == roS8(desc + 6 + p));
|
|
|
|
call p := Add(p, 1);
|
|
goto loop;
|
|
loopEnd:
|
|
}
|
|
|
|
procedure scanStack($ra:int, $nextFp:int)
|
|
requires ecx == $ra && word($ra);
|
|
requires edx == $nextFp;
|
|
requires FrameNextInv($FrameCount, $ra, $nextFp, $FrameAddr, $FrameLayout);
|
|
requires StackInv($r1, $FrameCount, $FrameAddr, $FrameLayout, $FrameSlice, $FrameMem, $FrameAbs, $FrameOffset, $Time);
|
|
requires BigGcInv($freshAbs, ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs, $r1, $r2,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize, $Time);
|
|
requires MarkStack(?gcLo, StackTop, $toAbs, $color, $GcMem, 0);
|
|
requires StackTop <= ColorBase;
|
|
modifies $r2, $color;
|
|
modifies eax, ebx, ecx, edx, esi, edi, ebp, esp;
|
|
modifies StackTop, $GcMem;
|
|
ensures StackInv($r2, $FrameCount, $FrameAddr, $FrameLayout, $FrameSlice, $FrameMem, $FrameAbs, $FrameOffset, $Time);
|
|
ensures BigGcInv($freshAbs, ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs, $r1, $r2,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize, $Time);
|
|
ensures RExtend(old($r2), $r2);
|
|
ensures MarkStack(?gcLo, StackTop, $toAbs, $color, $GcMem, 0);
|
|
ensures StackTop <= ColorBase;
|
|
{
|
|
var $frame:int;
|
|
var p:int;
|
|
var addr:int;
|
|
var desc:int;
|
|
var found:int;
|
|
var _ra:int;
|
|
var _nextFp:int;
|
|
_ra := ecx;
|
|
_nextFp := edx;
|
|
|
|
$frame := $FrameCount - 1;
|
|
loop:
|
|
assert $frame < $FrameCount && TV($frame);
|
|
assert word(_ra);
|
|
assert FrameNextInv($frame + 1, _ra, _nextFp, $FrameAddr, $FrameLayout);
|
|
assert (forall f:int::{TV(f)} TV(f) ==> 0 <= f && f <= $frame ==>
|
|
FrameInv(f, $FrameLayout[f], $r1, $FrameAddr, $FrameSlice, $FrameLayout, $FrameMem, $FrameAbs, $FrameOffset, $Time));
|
|
assert (forall f:int::{TV(f)} TV(f) ==> $frame < f && f < $FrameCount ==>
|
|
FrameInv(f, $FrameLayout[f], $r2, $FrameAddr, $FrameSlice, $FrameLayout, $FrameMem, $FrameAbs, $FrameOffset, $Time));
|
|
assert BigGcInv($freshAbs, ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs, $r1, $r2,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize, $Time);
|
|
assert MarkStack(?gcLo, StackTop, $toAbs, $color, $GcMem, 0);
|
|
assert StackTop <= ColorBase;
|
|
assert RExtend(old($r2), $r2);
|
|
|
|
assert TVF($FrameLayout[$frame]);
|
|
|
|
ecx := _ra;
|
|
edx := _nextFp;
|
|
esp := esp - 4; call TablesSearch($frame + 1, _ra, _nextFp);
|
|
desc := eax;
|
|
found := edx;
|
|
|
|
if (edx == 0) { goto loopEnd; }
|
|
|
|
ecx := _nextFp;
|
|
addr := ecx;
|
|
assert TV(addr);
|
|
assert TO(0);
|
|
assert TO(1);
|
|
call eax := FrameLoad(($frame), ecx);
|
|
_nextFp := eax;
|
|
call eax := FrameLoad(($frame), ecx + 4);
|
|
_ra := eax;
|
|
|
|
// if (getBit(desc, 0) && !getBit(desc, 1) && and(shr(desc, 6), 1023) == 0)
|
|
eax := desc;
|
|
call eax := Shr(eax, 0);
|
|
call eax := And(eax, 1);
|
|
if (eax != 1) { goto skip1; }
|
|
eax := desc;
|
|
call eax := Shr(eax, 1);
|
|
call eax := And(eax, 1);
|
|
if (eax == 1) { goto skip1; }
|
|
eax := desc;
|
|
call eax := Shr(eax, 6);
|
|
call eax := And(eax, 1023);
|
|
if (eax != 0) { goto skip1; }
|
|
ecx := addr;
|
|
edx := desc;
|
|
call scanStackDense($frame, addr, desc);
|
|
$frame := $frame - 1;
|
|
goto loop;
|
|
skip1:
|
|
|
|
// else if (!getBit(desc, 0) && ro32(desc) == 4096)
|
|
eax := desc;
|
|
call eax := Shr(eax, 0);
|
|
call eax := And(eax, 1);
|
|
if (eax == 1) { goto skip2; }
|
|
eax := desc;
|
|
call eax := RoLoad32(eax);
|
|
if (eax != 4096) { goto skip2; }
|
|
ecx := addr;
|
|
edx := desc;
|
|
call scanStackSparse8($frame, addr, desc);
|
|
$frame := $frame - 1;
|
|
goto loop;
|
|
skip2:
|
|
|
|
// else
|
|
assert !( (getBit(desc, 0) && !getBit(desc, 1) && and(shr(desc, 6), 1023) == 0)
|
|
|| (!getBit(desc, 0) && ro32(desc) == 4096));
|
|
call DebugBreak();
|
|
|
|
loopEnd:
|
|
assert $frame == 0 - 1;
|
|
}
|
|
|
|
procedure scanStaticSection($section:int)
|
|
requires ecx == $section;
|
|
requires 0 <= $section && $section < ?sectionCount && TV($section);
|
|
requires (forall s:int::{TV(s)} TV(s) ==> $section <= s && s < ?sectionCount ==>
|
|
SectionInv(s, sectionBase(s), sectionEnd(s), $r1, $SectionMem, $SectionAbs, $Time));
|
|
requires (forall s:int::{TV(s)} TV(s) ==> 0 <= s && s < $section ==>
|
|
SectionInv(s, sectionBase(s), sectionEnd(s), $r2, $SectionMem, $SectionAbs, $Time));
|
|
ensures (forall s:int::{TV(s)} TV(s) ==> $section + 1 <= s && s < ?sectionCount ==>
|
|
SectionInv(s, sectionBase(s), sectionEnd(s), $r1, $SectionMem, $SectionAbs, $Time));
|
|
ensures (forall s:int::{TV(s)} TV(s) ==> 0 <= s && s < $section + 1 ==>
|
|
SectionInv(s, sectionBase(s), sectionEnd(s), $r2, $SectionMem, $SectionAbs, $Time));
|
|
|
|
requires BigGcInv($freshAbs, ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs, $r1, $r2,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize, $Time);
|
|
requires MarkStack(?gcLo, StackTop, $toAbs, $color, $GcMem, 0);
|
|
requires StackTop <= ColorBase;
|
|
|
|
modifies $r2, $color;
|
|
modifies eax, ebx, ecx, edx, esi, edi, ebp, esp;
|
|
modifies StackTop, $GcMem;
|
|
|
|
ensures BigGcInv($freshAbs, ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs, $r1, $r2,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize, $Time);
|
|
ensures StackTop <= ColorBase;
|
|
ensures MarkStack(?gcLo, StackTop, $toAbs, $color, $GcMem, 0);
|
|
ensures RExtend(old($r2), $r2);
|
|
{
|
|
var sEnd:int;
|
|
var addr:int;
|
|
var section:int;
|
|
var save1:int;
|
|
var save2:int;
|
|
var save3:int;
|
|
|
|
section := ecx;
|
|
|
|
assert TVS(section, 0);
|
|
|
|
eax := ?dataSectionEnd;
|
|
call eax := RoLoad32(eax + 4 * ecx);
|
|
sEnd := eax;
|
|
|
|
eax := ?staticDataPointerBitMap;
|
|
call edx := RoLoad32(eax + 4 * ecx);
|
|
|
|
eax := ?dataSectionBase;
|
|
call eax := RoLoad32(eax + 4 * ecx);
|
|
addr := eax;
|
|
edi := eax;
|
|
|
|
esi := 0;
|
|
//while (edi < sEnd)
|
|
loop:
|
|
assert edx == ro32(?staticDataPointerBitMap + 4 * $section);
|
|
assert edi == addr + 4 * esi;
|
|
assert 0 <= section && TV(section);
|
|
assert 0 <= esi && TO(esi);
|
|
assert (forall s:int::{TV(s)} TV(s) ==> section < s && s < ?sectionCount ==>
|
|
SectionInv(s, sectionBase(s), sectionEnd(s), $r1, $SectionMem, $SectionAbs, $Time));
|
|
assert (forall s:int::{TV(s)} TV(s) ==> 0 <= s && s < section ==>
|
|
SectionInv(s, sectionBase(s), sectionEnd(s), $r2, $SectionMem, $SectionAbs, $Time));
|
|
|
|
assert (forall j:int::{TO(j)} TO(j) ==> 0 <= j && addr + 4 * j < sectionEnd(section) && j >= esi ==>
|
|
sectionSlice(addr + 4 * j) == section
|
|
&& Value(sectionHasPtr(section, j), $r1, $SectionMem[addr + 4 * j], $SectionAbs[section][j])
|
|
&& (sectionHasPtr(section, j) && gcAddrEx($SectionMem[addr + 4 * j]) ==> reached($SectionAbs[section][j], $Time))
|
|
);
|
|
|
|
assert (forall j:int::{TO(j)} TO(j) ==> 0 <= j && addr + 4 * j < sectionEnd(section) && j < esi ==>
|
|
sectionSlice(addr + 4 * j) == section
|
|
&& Value(sectionHasPtr(section, j), $r2, $SectionMem[addr + 4 * j], $SectionAbs[section][j])
|
|
&& (sectionHasPtr(section, j) && gcAddrEx($SectionMem[addr + 4 * j]) ==> reached($SectionAbs[section][j], $Time))
|
|
);
|
|
|
|
assert StackTop <= ColorBase;
|
|
assert MarkStack(?gcLo, StackTop, $toAbs, $color, $GcMem, 0);
|
|
assert BigGcInv($freshAbs, ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs, $r1, $r2,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize, $Time);
|
|
assert RExtend(old($r2), $r2);
|
|
|
|
if (edi >= sEnd) { goto loopEnd; }
|
|
|
|
assert TVS(section, esi);
|
|
eax := esi;
|
|
call eax := Shr(eax, 5);
|
|
call eax := RoLoad32(edx + 4 * eax);
|
|
// assert getBit(v, and(esi, 31)) == sectionHasPtr(section, esi);
|
|
//if (getBit(v, and(esi, 31)))
|
|
ecx := esi;
|
|
call ecx := And(ecx, 31);
|
|
call eax := Shr(eax, ecx);
|
|
call eax := And(eax, 1);
|
|
if (eax != 1) { goto skip1; }
|
|
assert TV($SectionMem[addr + 4 * esi] - 4);
|
|
call ecx := SectionLoad(edi);
|
|
//if (gcAddrEx(ecx))
|
|
if (ecx < ?gcLo) { goto skip2; }
|
|
if (ecx > ?gcHi) { goto skip2; }
|
|
save1 := edi;
|
|
save2 := esi;
|
|
save3 := edx;
|
|
call visit(ecx, $SectionAbs[section][esi], 0);
|
|
edi := save1;
|
|
esi := save2;
|
|
edx := save3;
|
|
skip2:
|
|
skip1:
|
|
|
|
call esi := Add(esi, 1);
|
|
call edi := AddChecked(edi, 4);
|
|
goto loop;
|
|
loopEnd:
|
|
}
|
|
|
|
procedure scanStatic()
|
|
requires StaticInv($r1, $SectionMem, $SectionAbs, $Time);
|
|
ensures StaticInv($r2, $SectionMem, $SectionAbs, $Time);
|
|
|
|
requires BigGcInv($freshAbs, ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs, $r1, $r2,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize, $Time);
|
|
requires MarkStack(?gcLo, StackTop, $toAbs, $color, $GcMem, 0);
|
|
requires StackTop <= ColorBase;
|
|
|
|
modifies $r2, $color;
|
|
modifies eax, ebx, ecx, edx, esi, edi, ebp, esp;
|
|
modifies StackTop, $GcMem;
|
|
|
|
ensures BigGcInv($freshAbs, ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs, $r1, $r2,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize, $Time);
|
|
ensures StackTop <= ColorBase;
|
|
ensures MarkStack(?gcLo, StackTop, $toAbs, $color, $GcMem, 0);
|
|
ensures RExtend(old($r2), $r2);
|
|
{
|
|
var section:int;
|
|
section := 0;
|
|
//while (section < ?sectionCount)
|
|
loop:
|
|
assert 0 <= section && TV(section);
|
|
assert (forall s:int::{TV(s)} TV(s) ==> section <= s && s < ?sectionCount ==>
|
|
SectionInv(s, sectionBase(s), sectionEnd(s), $r1, $SectionMem, $SectionAbs, $Time));
|
|
assert (forall s:int::{TV(s)} TV(s) ==> 0 <= s && s < section ==>
|
|
SectionInv(s, sectionBase(s), sectionEnd(s), $r2, $SectionMem, $SectionAbs, $Time));
|
|
assert BigGcInv($freshAbs, ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs, $r1, $r2,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize, $Time);
|
|
assert StackTop <= ColorBase;
|
|
assert MarkStack(?gcLo, StackTop, $toAbs, $color, $GcMem, 0);
|
|
assert RExtend(old($r2), $r2);
|
|
ecx := section;
|
|
if (ecx >= ?sectionCount) { goto loopEnd; }
|
|
|
|
call scanStaticSection(section);
|
|
call section := AddChecked(section, 1);
|
|
goto loop;
|
|
loopEnd:
|
|
}
|
|
|
|
procedure AllocBlock($minSize:int, $maxSize:int, $maxWords:int)
|
|
requires ecx == $minSize;
|
|
requires edx == $maxSize;
|
|
requires MutatorInv(ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize);
|
|
requires 8 <= $minSize && $minSize <= $maxSize;
|
|
requires $maxSize == 4 * $maxWords;
|
|
|
|
modifies $fs, $fn, $GcMem, CacheSize;
|
|
modifies eax, ebx, ecx, edx, esi, edi, ebp, esp;
|
|
|
|
ensures MutatorInv(ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize);
|
|
ensures eax != 0 ==> $fs[eax] >= $minSize;
|
|
ensures eax != 0 ==> HeapLo < eax && eax + $fs[eax] <= HeapHi;
|
|
ensures eax != 0 ==> Disconnected(HeapLo, eax, $fs, $fn);
|
|
ensures eax != 0 ==> CacheSize != 0 ==> eax != CachePtr;
|
|
ensures eax != 0 ==> Aligned(eax);
|
|
{
|
|
edi := HeapLo;
|
|
|
|
loop:
|
|
assert MutatorInv(ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize);
|
|
assert HeapLo <= edi && edi < HeapHi;
|
|
assert $fs[edi] != 0;
|
|
|
|
assert TV(edi) && TV($fn[edi]) && TO(1);
|
|
esi := edi;
|
|
call edi := GcLoad(edi);
|
|
if (edi != 0) { goto notEmpty; }
|
|
eax := 0;
|
|
esp := esp + 4; return;
|
|
notEmpty:
|
|
|
|
call ebx := GcLoad(edi + 4);
|
|
//assert $fs[edi] == ebx;
|
|
if (ebx < ecx) { goto loop; }
|
|
ebp := ebx;
|
|
call ebp := Sub(ebp, 8);
|
|
if (ebp < edx) { goto skip1; }
|
|
// Allocate from the end of the block
|
|
assert TV(edi + $fs[edi]);
|
|
assert TO(0 - $maxWords);
|
|
call eax := Lea(edi + ebx);
|
|
call eax := Sub(eax, edx);
|
|
assert TV(eax);
|
|
|
|
// If we dip below ReserveMin, skip this block
|
|
if (eax < ReserveMin) { goto loop; }
|
|
|
|
call ebx := Sub(ebx, edx);
|
|
// If the remaining size is too small, allocate the whole block
|
|
// TUNING: min cache size
|
|
if (ebx < 256) { goto skip1; }
|
|
// if (ebx < 1024) { goto skip1; }
|
|
|
|
$fn[eax] := 0;
|
|
$fs[eax] := edx;
|
|
call GcStore(eax, 0);
|
|
call GcStore(eax + 4, edx);
|
|
|
|
$fs[edi] := $fs[edi] - edx;
|
|
call GcStore(edi + 4, ebx);
|
|
esp := esp + 4; return;
|
|
skip1:
|
|
// Allocate the whole block
|
|
|
|
// If we dip below ReserveMin, skip this block
|
|
if (edi < ReserveMin) { goto loop; }
|
|
|
|
$fn[esi] := $fn[edi];
|
|
call ebx := GcLoad(edi);
|
|
call GcStore(esi, ebx);
|
|
$fn[edi] := 0;
|
|
call GcStore(edi, 0);
|
|
eax := edi;
|
|
esp := esp + 4; return;
|
|
}
|
|
|
|
procedure allocFromCache($size:int, $nFields:int)
|
|
requires ecx == $size;
|
|
requires MutatorInv(ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize);
|
|
requires 8 <= $size && $size + 8 <= CacheSize;
|
|
requires $size == 4 * $nFields;
|
|
|
|
modifies $fs, $fn, $GcMem, CacheSize;
|
|
modifies eax, edx;
|
|
ensures MutatorInv(ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize);
|
|
ensures $fs[eax] >= $size;
|
|
ensures HeapLo < eax && eax + $size <= HeapHi;
|
|
ensures Disconnected(HeapLo, eax, $fs, $fn);
|
|
ensures eax != CachePtr;
|
|
ensures Aligned(eax);
|
|
{
|
|
assert TV(CachePtr) && TV(CachePtr + CacheSize);
|
|
assert TO(0 - $nFields) && TO(1);
|
|
call CacheSize := Sub(CacheSize, ecx);
|
|
$fs[CachePtr] := CacheSize;
|
|
eax := CacheSize;
|
|
edx := CachePtr;
|
|
call GcStore(edx + 4, eax);
|
|
|
|
call eax := Add(eax, edx);
|
|
assert TV(CachePtr) && TV(eax);
|
|
|
|
$fn[eax] := 0;
|
|
$fs[eax] := $size;
|
|
call GcStore(eax, 0);
|
|
call GcStore(eax + 4, ecx);
|
|
}
|
|
|
|
procedure AllocSlow($size:int, $nFields:int)
|
|
requires ecx == $size;
|
|
requires MutatorInv(ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize);
|
|
requires 8 <= $size;
|
|
requires $size == 4 * $nFields;
|
|
modifies $fs, $fn, $GcMem, CachePtr, CacheSize;
|
|
modifies eax, ebx, ecx, edx, esi, edi, ebp, esp;
|
|
ensures MutatorInv(ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize);
|
|
ensures eax != 0 ==> $fs[eax] >= $size;
|
|
ensures eax != 0 ==> HeapLo < eax && eax + $size <= HeapHi;
|
|
ensures eax != 0 ==> Disconnected(HeapLo, eax, $fs, $fn);
|
|
ensures eax != 0 ==> CacheSize != 0 ==> eax != CachePtr;
|
|
ensures eax != 0 ==> Aligned(eax);
|
|
{
|
|
var size:int;
|
|
|
|
// TUNING: min cache size
|
|
if (ecx < 192) { goto skip1; }
|
|
// if (ecx < 768) { goto skip1; }
|
|
// if (ecx < 1536) { goto skip1; }
|
|
// Large object: allocate directly
|
|
edx := ecx;
|
|
esp := esp - 4; call AllocBlock($size, $size, $nFields);
|
|
esp := esp + 4; return;
|
|
//else
|
|
skip1:
|
|
// Small object: allocate from cache
|
|
size := ecx;
|
|
// TUNING: min cache size
|
|
ecx := 256;
|
|
// ecx := 1024;
|
|
// ecx := 2048;
|
|
edx := 65536;
|
|
// TUNING: min cache size
|
|
esp := esp - 4; call AllocBlock(256, 65536, 16384);
|
|
// esp := esp - 4; call AllocBlock(1024, 65536, 16384);
|
|
// esp := esp - 4; call AllocBlock(2048, 65536, 16384);
|
|
assert TV(eax);
|
|
if (eax == 0) { goto skip2; }
|
|
CachePtr := eax;
|
|
assert TO(1);
|
|
ecx := CachePtr;
|
|
call ecx := GcLoad(ecx + 4);
|
|
CacheSize := ecx;
|
|
ecx := size;
|
|
call allocFromCache($size, $nFields);
|
|
skip2:
|
|
esp := esp + 4; return;
|
|
}
|
|
|
|
procedure processMarkStack()
|
|
requires BigGcInv($freshAbs, ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs, $r1, $r2,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize, $Time);
|
|
requires MarkStack(?gcLo, StackTop, $toAbs, $color, $GcMem, 0);
|
|
requires StackTop <= ColorBase;
|
|
|
|
modifies $r2, $color;
|
|
modifies eax, ebx, ecx, edx, esi, edi, ebp, esp;
|
|
modifies StackTop, $GcMem;
|
|
|
|
ensures BigGcInv($freshAbs, ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs, $r1, $r2,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize, $Time);
|
|
ensures StackTop == ?gcLo;
|
|
ensures MarkStack(?gcLo, StackTop, $toAbs, $color, $GcMem, 0);
|
|
ensures RExtend(old($r2), $r2);
|
|
{
|
|
var ptr:int;
|
|
eax := StackTop;
|
|
|
|
// while (StackTop != ?gcLo)
|
|
loop:
|
|
assert MarkStack(?gcLo, StackTop, $toAbs, $color, $GcMem, 0);
|
|
assert BigGcInv($freshAbs, ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs, $r1, $r2,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize, $Time);
|
|
assert RExtend(old($r2), $r2);
|
|
assert StackTop <= ColorBase;
|
|
|
|
eax := StackTop;
|
|
if (eax == ?gcLo) { goto loopEnd; }
|
|
|
|
assert TV(StackTop) && TO(0 - 1);
|
|
call __notAligned(?gcLo);
|
|
call eax := Sub(eax, 4);
|
|
call ebx := GcLoad(eax);
|
|
ptr := ebx;
|
|
StackTop := eax;
|
|
assert TV(StackTop);
|
|
assert TV(ptr);
|
|
|
|
call __notAligned(StackTop);
|
|
call scanObject(ptr, $r1[ptr]);
|
|
|
|
esi := ptr;
|
|
call esi := Sub(esi, HeapLo);
|
|
edi := ColorBase;
|
|
edx := 3; // black
|
|
call bb4SetColor($color, 3, HeapLo, HeapLo, HeapLo, HeapHi, ptr, ColorBase, HeapLo);
|
|
$color[ptr] := 3; // black
|
|
goto loop;
|
|
loopEnd:
|
|
}
|
|
|
|
procedure sweepObject($ptr:int, $prev:int, $regionStart:int) returns($_ptr:int, $_prev:int, $_regionStart:int)
|
|
requires ebx == $color[$ptr];
|
|
requires esi == $ptr;
|
|
requires edi == $prev;
|
|
requires ebp == $regionStart;
|
|
requires $freshAbs != NO_ABS;
|
|
requires HeapLo + 8 <= HeapHi;
|
|
requires $toAbs[$ptr] != NO_ABS;
|
|
requires Black($color[$ptr]) ==> $toAbs[$ptr] == $r2[$ptr];
|
|
requires $ptr < HeapHi;
|
|
|
|
requires GcInv(ColorBase, HeapLo, HeapHi, $color, $toAbs, $r1, $r2, $GcMem);
|
|
requires ObjectSeq(HeapLo, $regionStart, $toAbs, $fs, $fn);
|
|
requires FreeInv(HeapLo, $regionStart, $fs, $fn, $GcMem, CachePtr, CacheSize);
|
|
requires Objects($ptr, HeapHi, $toAbs, $fs, $fn);
|
|
requires $fs[$prev] != 0;
|
|
requires $GcMem[$prev] == 0;
|
|
requires Aligned($prev) && HeapLo <= $prev && $prev + 8 <= $regionStart && $regionStart <= $ptr;
|
|
requires $ptr < HeapHi + 4;
|
|
requires (forall ii:int::{TV(ii)} TV(ii) ==> HeapLo <= ii && ii < $prev && $fs[ii] != 0 ==> $fn[ii] <= $prev);
|
|
requires (forall ii:int::{TV(ii)} TV(ii) ==> $prev <= ii && ii < $ptr && $fs[ii] != 0 ==> $fn[ii] == 0);
|
|
requires (forall ii:int::{TV(ii)} TV(ii) ==> $regionStart <= ii && ii < $ptr ==> $toAbs[ii] == NO_ABS && $fs[ii] == 0);
|
|
requires CacheSize == 0;
|
|
requires HeapLo <= $ptr;
|
|
requires Aligned($regionStart) && Aligned($ptr);
|
|
requires AllocInv2($toAbs, HeapLo, HeapHi, $r1, $r2, false);
|
|
requires (forall i:int::{TV(i)} TV(i) ==> HeapLo <= i && i < HeapHi ==> $toAbs[i] != NO_ABS ==> !Gray($color[i]));
|
|
requires (forall i:int::{TV(i)} TV(i) ==> HeapLo <= i && i < $ptr ==> (White($color[i]) <==> $toAbs[i] != NO_ABS));
|
|
requires (forall i:int::{TV(i)} TV(i) ==> HeapLo <= i && i < $ptr && $toAbs[i] != NO_ABS ==>
|
|
$r1[i] != NO_ABS && $r2[i] != NO_ABS
|
|
&& $toAbs[i] != NO_ABS && $toAbs[i] == $r2[i]
|
|
&& ObjInv(i, $r2, $r2, $toAbs, $AbsMem, $GcMem, $gcSlice));
|
|
requires MsGcInv($ptr, HeapHi, $Time, $r1, $r2, $color, true, $GcMem, $toAbs, $AbsMem, $gcSlice);
|
|
|
|
modifies $color;
|
|
modifies eax, ebx, ecx, edx, esi, edi, ebp, esp;
|
|
modifies $toAbs, $fs, $fn, $GcMem, CacheSize;
|
|
|
|
ensures esi == $_ptr;
|
|
ensures edi == $_prev;
|
|
ensures ebp == $_regionStart;
|
|
ensures GcInv(ColorBase, HeapLo, HeapHi, $color, $toAbs, $r1, $r2, $GcMem);
|
|
ensures ObjectSeq(HeapLo, $_regionStart, $toAbs, $fs, $fn);
|
|
ensures FreeInv(HeapLo, $_regionStart, $fs, $fn, $GcMem, CachePtr, CacheSize);
|
|
ensures Objects($_ptr, HeapHi, $toAbs, $fs, $fn);
|
|
ensures $fs[$_prev] != 0;
|
|
ensures $GcMem[$_prev] == 0;
|
|
ensures Aligned($_prev) && HeapLo <= $_prev && $_prev + 8 <= $_regionStart && $_regionStart <= $_ptr;
|
|
ensures $_ptr < HeapHi + 4;
|
|
ensures (forall ii:int::{TV(ii)} TV(ii) ==> HeapLo <= ii && ii < $_prev && $fs[ii] != 0 ==> $fn[ii] <= $_prev);
|
|
ensures (forall ii:int::{TV(ii)} TV(ii) ==> $_prev <= ii && ii < $_ptr && $fs[ii] != 0 ==> $fn[ii] == 0);
|
|
ensures (forall ii:int::{TV(ii)} TV(ii) ==> $_regionStart <= ii && ii < $_ptr ==> $toAbs[ii] == NO_ABS && $fs[ii] == 0);
|
|
ensures CacheSize == 0;
|
|
ensures HeapLo <= $_ptr;
|
|
ensures Aligned($_regionStart) && Aligned($_ptr);
|
|
ensures AllocInv2($toAbs, HeapLo, HeapHi, $r1, $r2, false);
|
|
ensures (forall i:int::{TV(i)} TV(i) ==> HeapLo <= i && i < HeapHi ==> $toAbs[i] != NO_ABS ==> !Gray($color[i]));
|
|
ensures (forall i:int::{TV(i)} TV(i) ==> HeapLo <= i && i < $_ptr ==> (White($color[i]) <==> $toAbs[i] != NO_ABS));
|
|
ensures (forall i:int::{TV(i)} TV(i) ==> HeapLo <= i && i < $_ptr && $toAbs[i] != NO_ABS ==>
|
|
$r1[i] != NO_ABS && $r2[i] != NO_ABS
|
|
&& $toAbs[i] != NO_ABS && $toAbs[i] == $r2[i]
|
|
&& ObjInv(i, $r2, $r2, $toAbs, $AbsMem, $GcMem, $gcSlice));
|
|
ensures MsGcInv($_ptr, HeapHi, $Time, $r1, $r2, $color, true, $GcMem, $toAbs, $AbsMem, $gcSlice);
|
|
{
|
|
var size:int;
|
|
var save1:int;
|
|
var save2:int;
|
|
var save3:int;
|
|
|
|
assert TV(esi) && TV(ebp) && TV(edi) && TO(1);
|
|
assert TO(numFields($toAbs[esi]));
|
|
|
|
if (ebx != 3) { goto skip1; } // !black
|
|
save1 := esi;
|
|
save2 := edi;
|
|
save3 := ebp;
|
|
ecx := esi;
|
|
call edx := GcLoad(esi + 4);
|
|
esp := esp - 4; call GetSize($ptr, $GcMem[$ptr + 4], $r2, $r2);
|
|
size := eax;
|
|
assert size == 4 * numFields($toAbs[$ptr]);
|
|
esi := save1;
|
|
ebp := save3;
|
|
|
|
call esi := Sub(esi, HeapLo);
|
|
edi := ColorBase;
|
|
edx := 1; // white
|
|
call bb4SetColor($color, 1, HeapLo, HeapLo, HeapLo, HeapHi, $ptr, ColorBase, HeapLo);
|
|
esi := save1;
|
|
edi := save2;
|
|
$color[esi] := 1; // white
|
|
|
|
eax := esi;
|
|
call eax := Sub(eax, ebp);
|
|
// TUNING: min cache size
|
|
if (eax < 256) { goto skipFree; }
|
|
// if (eax < 1024) { goto skipFree; }
|
|
// if (eax < 2048) { goto skipFree; }
|
|
// Turn region into free block
|
|
$fn[edi] := ebp;
|
|
call GcStore(edi, ebp);
|
|
$fn[ebp] := 0;
|
|
$fs[ebp] := eax;
|
|
call GcStore(ebp, 0);
|
|
call GcStore(ebp + 4, eax);
|
|
edi := ebp;
|
|
skipFree:
|
|
// Start a new region.
|
|
call esi := Add(esi, size);
|
|
ebp := esi;
|
|
goto skip2;
|
|
//else
|
|
skip1:
|
|
assert White($color[esi]);
|
|
save1 := esi;
|
|
save2 := edi;
|
|
save3 := ebp;
|
|
ecx := esi;
|
|
call edx := GcLoad(esi + 4);
|
|
esp := esp - 4; call GetSize($ptr, $GcMem[$ptr + 4], $r1, $r1);
|
|
size := eax;
|
|
assert size == 4 * numFields($toAbs[$ptr]);
|
|
esi := save1;
|
|
edi := save2;
|
|
ebp := save3;
|
|
|
|
$toAbs[esi] := NO_ABS;
|
|
call esi := Sub(esi, HeapLo);
|
|
edi := ColorBase;
|
|
edx := 0; // unallocated
|
|
call bb4SetColor($color, 0, HeapLo, HeapLo, HeapLo, HeapHi, $ptr, ColorBase, HeapLo);
|
|
esi := save1;
|
|
edi := save2;
|
|
$color[esi] := 0; // unallocated
|
|
|
|
call esi := Add(esi, size);
|
|
skip2:
|
|
$_ptr := esi;
|
|
$_prev := edi;
|
|
$_regionStart := ebp;
|
|
}
|
|
|
|
procedure Sweep()
|
|
requires AllocInv2($toAbs, HeapLo, HeapHi, $r1, $r2, false);
|
|
requires MsGcInv(HeapLo, HeapHi, $Time, $r1, $r2, $color, true, $GcMem, $toAbs, $AbsMem, $gcSlice);
|
|
requires (forall i:int::{TV(i)} TV(i) ==> HeapLo <= i && i < HeapHi ==> $toAbs[i] != NO_ABS ==> !Gray($color[i]));
|
|
requires (forall i:int::{TV(i)} TV(i) ==> HeapLo <= i && i < HeapHi ==> $toAbs[i] != NO_ABS && Black($color[i]) ==>
|
|
$toAbs[i] == $r2[i]);
|
|
requires GcInv(ColorBase, HeapLo, HeapHi, $color, $toAbs, $r1, $r2, $GcMem);
|
|
requires $freshAbs != NO_ABS;
|
|
requires (forall i:int::{TV(i)} TV(i) ==> gcAddr(i) ==> $toAbs[i] != $freshAbs);
|
|
requires Objects(HeapLo + 8, HeapHi, $toAbs, $fs, $fn);
|
|
requires $fs[HeapLo] == 8;
|
|
requires ObjectSeq(HeapLo, HeapLo + 8, $toAbs, $fs, $fn);
|
|
requires FreeInv(HeapLo, HeapLo + 8, $fs, $fn, $GcMem, CachePtr, CacheSize);
|
|
requires HeapLo + 8 <= HeapHi;
|
|
|
|
modifies $color;
|
|
modifies eax, ebx, ecx, edx, esi, edi, ebp, esp;
|
|
modifies $toAbs, $fs, $fn, $GcMem, CacheSize;
|
|
|
|
ensures (forall i:int::{TV(i)} TV(i) ==> HeapLo <= i && i < HeapHi ==> $toAbs[i] != NO_ABS ==> reached($toAbs[i], $Time));
|
|
ensures MsInv(HeapLo, HeapHi, $color, $GcMem, $toAbs, $AbsMem, $gcSlice);
|
|
ensures GcInv(ColorBase, HeapLo, HeapHi, $color, $toAbs, $r1, $r2, $GcMem);
|
|
ensures (forall i:int::{TV(i)} TV(i) ==> gcAddr(i) ==> $toAbs[i] != $freshAbs);
|
|
ensures ObjectSeq(HeapLo, HeapHi, $toAbs, $fs, $fn);
|
|
ensures FreeInv(HeapLo, HeapHi, $fs, $fn, $GcMem, CachePtr, CacheSize);
|
|
ensures $toAbs == $r2;
|
|
{
|
|
// esi = ptr
|
|
// edi = prev
|
|
// ebp = regionStart
|
|
var $_ptr:int;
|
|
var $_prev:int;
|
|
var $_regionStart:int;
|
|
assert TV(HeapLo);
|
|
assert TV(HeapLo + 8);
|
|
|
|
CacheSize := 0;
|
|
edi := HeapLo;
|
|
call esi := Lea(edi + 8);
|
|
ebp := esi;
|
|
$fn[edi] := 0;
|
|
assert TV(edi);
|
|
call GcStore(edi, 0);
|
|
|
|
//
|
|
// ... [edi:free ... ] ... [ebp:empty ... ] esi
|
|
//
|
|
|
|
//while (esi < HeapHi)
|
|
loop:
|
|
assert GcInv(ColorBase, HeapLo, HeapHi, $color, $toAbs, $r1, $r2, $GcMem);
|
|
assert ObjectSeq(HeapLo, ebp, $toAbs, $fs, $fn);
|
|
assert FreeInv(HeapLo, ebp, $fs, $fn, $GcMem, CachePtr, CacheSize);
|
|
assert Objects(esi, HeapHi, $toAbs, $fs, $fn);
|
|
assert $fs[edi] != 0;
|
|
assert $GcMem[edi] == 0;
|
|
assert Aligned(edi);
|
|
assert HeapLo <= edi && edi + 8 <= ebp && ebp <= esi;
|
|
assert esi < HeapHi + 4;
|
|
assert (forall ii:int::{TV(ii)} TV(ii) ==> HeapLo <= ii && ii < edi && $fs[ii] != 0 ==> $fn[ii] <= edi);
|
|
assert (forall ii:int::{TV(ii)} TV(ii) ==> edi <= ii && ii < esi && $fs[ii] != 0 ==> $fn[ii] == 0);
|
|
assert (forall ii:int::{TV(ii)} TV(ii) ==> ebp <= ii && ii < esi ==> $toAbs[ii] == NO_ABS && $fs[ii] == 0);
|
|
assert CacheSize == 0;
|
|
|
|
assert HeapLo <= esi;
|
|
assert Aligned(ebp) && Aligned(esi);
|
|
assert AllocInv2($toAbs, HeapLo, HeapHi, $r1, $r2, false);
|
|
assert (forall i:int::{TV(i)} TV(i) ==> HeapLo <= i && i < HeapHi ==> $toAbs[i] != NO_ABS ==> !Gray($color[i]));
|
|
|
|
assert (forall i:int::{TV(i)} TV(i) ==> HeapLo <= i && i < esi ==> (White($color[i]) <==> $toAbs[i] != NO_ABS));
|
|
assert (forall i:int::{TV(i)} TV(i) ==> HeapLo <= i && i < esi && $toAbs[i] != NO_ABS ==>
|
|
$r1[i] != NO_ABS && $r2[i] != NO_ABS
|
|
&& $toAbs[i] != NO_ABS && $toAbs[i] == $r2[i]
|
|
&& ObjInv(i, $r2, $r2, $toAbs, $AbsMem, $GcMem, $gcSlice));
|
|
assert MsGcInv(esi, HeapHi, $Time, $r1, $r2, $color, true, $GcMem, $toAbs, $AbsMem, $gcSlice);
|
|
if (esi >= HeapHi) { goto loopEnd; }
|
|
|
|
assert TV(esi) && TV(ebp) && TV(edi);
|
|
|
|
ebx := esi;
|
|
call ebx := Sub(ebx, HeapLo);
|
|
eax := ColorBase;
|
|
call bb4GetColor($color, HeapLo, HeapLo, HeapLo, HeapHi, esi, ColorBase, HeapLo);
|
|
assert ebx == $color[esi];
|
|
if (ebx == 0) { goto skip1; } // unallocated
|
|
call $_ptr, $_prev, $_regionStart := sweepObject(esi, edi, ebp);
|
|
goto loop;
|
|
//else
|
|
skip1:
|
|
assert TO(1);
|
|
call __notAligned(esi);
|
|
$fs[esi] := 0;
|
|
call esi := Add(esi, 4);
|
|
goto loop;
|
|
loopEnd:
|
|
|
|
// don't forget the last region
|
|
eax := esi;
|
|
call eax := Sub(eax, ebp);
|
|
// TUNING: min cache size
|
|
if (eax < 256) { goto skip2; }
|
|
// if (eax < 1024) { goto skip2; }
|
|
// if (eax < 2048) { goto skip2; }
|
|
// Turn region into free block
|
|
$fn[edi] := ebp;
|
|
call GcStore(edi, ebp);
|
|
$fn[ebp] := 0;
|
|
$fs[ebp] := esi - ebp;
|
|
assert TV(ebp) && TO(1);
|
|
call GcStore(ebp, 0);
|
|
call GcStore(ebp + 4, eax);
|
|
edi := ebp;
|
|
skip2:
|
|
|
|
call __notAligned(HeapHi);
|
|
$toAbs := $r2;
|
|
|
|
esp := esp + 4; return;
|
|
}
|
|
|
|
procedure GarbageCollect($ra:int, $nextFp:int)
|
|
requires ecx == $ra && word($ra);
|
|
requires edx == $nextFp;
|
|
requires FrameNextInv($FrameCount, $ra, $nextFp, $FrameAddr, $FrameLayout);
|
|
requires StaticInv($toAbs, $SectionMem, $SectionAbs, $Time);
|
|
requires StackInv($toAbs, $FrameCount, $FrameAddr, $FrameLayout, $FrameSlice, $FrameMem, $FrameAbs, $FrameOffset, $Time);
|
|
requires MutatorInv(ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize);
|
|
requires $freshAbs != NO_ABS;
|
|
requires (forall i:int::{TV(i)} TV(i) ==> gcAddr(i) ==> $toAbs[i] != $freshAbs);
|
|
|
|
modifies $r1, $r2, $GcMem, $toAbs, $gcSlice, $color, StackTop;
|
|
modifies $fs, $fn, CacheSize;
|
|
modifies eax, ebx, ecx, edx, esi, edi, ebp, esp;
|
|
|
|
// postcondition same as precondition, plus reached:
|
|
ensures StaticInv($toAbs, $SectionMem, $SectionAbs, $Time);
|
|
ensures StackInv($toAbs, $FrameCount, $FrameAddr, $FrameLayout, $FrameSlice, $FrameMem, $FrameAbs, $FrameOffset, $Time);
|
|
ensures MutatorInv(ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize);
|
|
ensures (forall i:int::{TV(i)} TV(i) ==> gcAddr(i) ==> $toAbs[i] != $freshAbs);
|
|
ensures (forall i:int::{TV(i)} TV(i) ==> HeapLo <= i && i < HeapHi && $toAbs[i] != NO_ABS ==>
|
|
reached($toAbs[i], $Time));
|
|
ensures ebp == old(ebp);
|
|
{
|
|
var saveEbp:int;
|
|
saveEbp := ebp;
|
|
|
|
$r1 := $toAbs;
|
|
$r2 := MAP_NO_ABS;
|
|
|
|
eax := ?gcLo;
|
|
StackTop := eax;
|
|
call scanStack($ra, $nextFp);
|
|
call scanStatic();
|
|
call processMarkStack();
|
|
|
|
assert TV(HeapLo);
|
|
$fn[HeapLo] := 0;
|
|
eax := HeapLo;
|
|
call GcStore(eax, 0);
|
|
CacheSize := 0;
|
|
|
|
esp := esp - 4; call Sweep();
|
|
|
|
ebp := saveEbp;
|
|
esp := esp + 4; return;
|
|
}
|
|
|
|
procedure allocObjectMemory($ra:int, $nextFp:int, $size:int, $nFields:int)
|
|
requires eax == $size;
|
|
requires ecx == $ra && word($ra);
|
|
requires edx == $nextFp;
|
|
requires FrameNextInv($FrameCount, $ra, $nextFp, $FrameAddr, $FrameLayout);
|
|
requires StaticInv($toAbs, $SectionMem, $SectionAbs, $Time);
|
|
requires StackInv($toAbs, $FrameCount, $FrameAddr, $FrameLayout, $FrameSlice, $FrameMem, $FrameAbs, $FrameOffset, $Time);
|
|
requires MutatorInv(ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize);
|
|
requires 8 <= $size;
|
|
requires $size == 4 * $nFields;
|
|
requires $freshAbs != NO_ABS;
|
|
requires (forall i:int::{TV(i)} TV(i) ==> HeapLo <= i && i < HeapHi ==> $toAbs[i] != $freshAbs);
|
|
|
|
modifies $r1, $r2, $GcMem, $toAbs, $gcSlice, $color, StackTop;
|
|
modifies $fs, $fn, CachePtr, CacheSize, ReserveMin;
|
|
modifies eax, ebx, ecx, edx, esi, edi, ebp, esp;
|
|
|
|
ensures StaticInv($toAbs, $SectionMem, $SectionAbs, $Time);
|
|
ensures StackInv($toAbs, $FrameCount, $FrameAddr, $FrameLayout, $FrameSlice, $FrameMem, $FrameAbs, $FrameOffset, $Time);
|
|
ensures MutatorInv(ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize);
|
|
ensures $fs[eax] >= $size;
|
|
ensures HeapLo < eax && eax + $size <= HeapHi;
|
|
ensures Disconnected(HeapLo, eax, $fs, $fn);
|
|
ensures CacheSize != 0 ==> eax != CachePtr;
|
|
ensures Aligned(eax);
|
|
ensures (forall i:int::{TV(i)} TV(i) ==> HeapLo <= i && i < HeapHi ==> $toAbs[i] != $freshAbs);
|
|
{
|
|
var ra:int;
|
|
var nextFp:int;
|
|
var size:int;
|
|
ra := ecx;
|
|
|
|
ecx := eax;
|
|
call eax := AddChecked(eax, 8);
|
|
if (eax > CacheSize) { goto skip1; }
|
|
call allocFromCache($size, $nFields);
|
|
goto end;
|
|
//else
|
|
skip1:
|
|
nextFp := edx;
|
|
size := ecx;
|
|
esp := esp - 4; call AllocSlow($size, $nFields);
|
|
if (eax != 0) { goto end; }
|
|
ecx := ra; // $ra && word($ra);
|
|
edx := nextFp; // $nextFp;
|
|
|
|
esp := esp - 4; call GarbageCollect($ra, $nextFp);
|
|
ecx := size;
|
|
esp := esp - 4; call AllocSlow($size, $nFields);
|
|
if (eax != 0) { goto end; }
|
|
// Try using some of the reserve:
|
|
ecx := size;
|
|
call ReserveMin := SubChecked(ReserveMin, ecx);
|
|
// TUNING: wilderness policy // REVIEW: this should be a parameter, not hard-wired into the code
|
|
call ReserveMin := SubChecked(ReserveMin, 1048576); // Bartok,Zinger
|
|
// call ReserveMin := SubChecked(ReserveMin, 65536); // Sat
|
|
esp := esp - 4; call AllocSlow($size, $nFields);
|
|
if (eax != 0) { goto end; }
|
|
// out of memory
|
|
call DebugBreak();
|
|
end:
|
|
}
|
|
|
|
procedure doAllocWord($ret:int, $ind:int, $nf:int)
|
|
requires esi == $ret + 4 * $ind;
|
|
|
|
requires TO($ind) && $ind >= 0 && $ind < $nf;
|
|
requires Aligned($ret) && HeapLo <= $ret && $ret + 4 * $ind + 4 <= HeapHi;
|
|
requires MsInv(HeapLo, HeapHi, $color, $GcMem, $toAbs, $AbsMem, $gcSlice);
|
|
requires GcInv(ColorBase, HeapLo, HeapHi, $color, $toAbs, $toAbs, $toAbs, $GcMem);
|
|
requires ObjectSeq(HeapLo, HeapHi, $toAbs, $fs, $fn);
|
|
requires FreeInvBase(HeapLo, HeapHi, $fs, $fn, $GcMem, CachePtr, CacheSize);
|
|
requires (forall i:int::{TV(i)} TV(i) ==> HeapLo <= i && i < HeapHi && $fs[i] != 0 && i != $ret ==>
|
|
FreeInvI(i, HeapLo, HeapHi, $fs, $fn, $GcMem, CachePtr, CacheSize));
|
|
requires (forall j:int::{TO(j)} TO(j) ==> 0 <= j && j < $ind ==> $gcSlice[$ret + 4 * j] == $ret);
|
|
requires (forall j:int::{TO(j)} TO(j) ==> 0 <= j && j < $ind ==> gcAddr($ret + 4 * j)); // REVIEW: necessary?
|
|
requires (forall j:int::{TO(j)} TO(j) ==> 0 <= j && j < $ind ==> $GcMem[$ret + 4 * j] == NULL);
|
|
requires $fs[$ret] >= 4 * $nf;
|
|
requires CacheSize != 0 ==> $ret != CachePtr;
|
|
requires Disconnected(HeapLo, $ret, $fs, $fn);
|
|
|
|
modifies $GcMem, $gcSlice;
|
|
|
|
ensures MsInv(HeapLo, HeapHi, $color, $GcMem, $toAbs, $AbsMem, $gcSlice);
|
|
ensures GcInv(ColorBase, HeapLo, HeapHi, $color, $toAbs, $toAbs, $toAbs, $GcMem);
|
|
ensures ObjectSeq(HeapLo, HeapHi, $toAbs, $fs, $fn);
|
|
ensures FreeInvBase(HeapLo, HeapHi, $fs, $fn, $GcMem, CachePtr, CacheSize);
|
|
ensures (forall i:int::{TV(i)} TV(i) ==> HeapLo <= i && i < HeapHi && $fs[i] != 0 && i != $ret ==>
|
|
FreeInvI(i, HeapLo, HeapHi, $fs, $fn, $GcMem, CachePtr, CacheSize));
|
|
ensures (forall j:int::{TO(j)} TO(j) ==> 0 <= j && j < $ind + 1 ==> $gcSlice[$ret + 4 * j] == $ret);
|
|
ensures (forall j:int::{TO(j)} TO(j) ==> 0 <= j && j < $ind + 1 ==> gcAddr($ret + 4 * j)); // REVIEW: necessary?
|
|
ensures (forall j:int::{TO(j)} TO(j) ==> 0 <= j && j < $ind + 1 ==> $GcMem[$ret + 4 * j] == NULL);
|
|
ensures ebp == old(ebp);
|
|
{
|
|
assert TV($ret);
|
|
assert TV($ret + 4 * $ind);// && TV($ret + 4 * $ind + 1) && TV($ret + 4 * $ind + 2) && TV($ret + 4 * $ind + 3);
|
|
$gcSlice[$ret + 4 * $ind] := $ret;
|
|
|
|
call GcStore(esi, 0);
|
|
}
|
|
|
|
procedure doAllocWords($ret:int, $size:int, $nf:int)
|
|
requires eax == $ret;
|
|
requires ebx == $ret + $size;
|
|
requires $size == $nf * 4;
|
|
requires $nf >= 0;
|
|
requires Aligned($ret) && HeapLo <= $ret && $ret + $size <= HeapHi;
|
|
requires MsInv(HeapLo, HeapHi, $color, $GcMem, $toAbs, $AbsMem, $gcSlice);
|
|
requires GcInv(ColorBase, HeapLo, HeapHi, $color, $toAbs, $toAbs, $toAbs, $GcMem);
|
|
requires ObjectSeq(HeapLo, HeapHi, $toAbs, $fs, $fn);
|
|
requires FreeInvBase(HeapLo, HeapHi, $fs, $fn, $GcMem, CachePtr, CacheSize);
|
|
requires (forall i:int::{TV(i)} TV(i) ==> HeapLo <= i && i < HeapHi && $fs[i] != 0 && i != $ret ==>
|
|
FreeInvI(i, HeapLo, HeapHi, $fs, $fn, $GcMem, CachePtr, CacheSize));
|
|
requires $fs[$ret] >= 4 * $nf;
|
|
requires CacheSize != 0 ==> $ret != CachePtr;
|
|
requires Disconnected(HeapLo, $ret, $fs, $fn);
|
|
|
|
modifies $GcMem, $gcSlice;
|
|
modifies esi;
|
|
|
|
ensures MsInv(HeapLo, HeapHi, $color, $GcMem, $toAbs, $AbsMem, $gcSlice);
|
|
ensures GcInv(ColorBase, HeapLo, HeapHi, $color, $toAbs, $toAbs, $toAbs, $GcMem);
|
|
ensures ObjectSeq(HeapLo, HeapHi, $toAbs, $fs, $fn);
|
|
ensures FreeInvBase(HeapLo, HeapHi, $fs, $fn, $GcMem, CachePtr, CacheSize);
|
|
ensures (forall i:int::{TV(i)} TV(i) ==> HeapLo <= i && i < HeapHi && $fs[i] != 0 && i != $ret ==>
|
|
FreeInvI(i, HeapLo, HeapHi, $fs, $fn, $GcMem, CachePtr, CacheSize));
|
|
ensures (forall j:int::{TO(j)} TO(j) ==> 0 <= j && j < $nf ==> $gcSlice[$ret + 4 * j] == $ret);
|
|
ensures (forall j:int::{TO(j)} TO(j) ==> 0 <= j && j < $nf ==> gcAddr($ret + 4 * j)); // REVIEW: necessary?
|
|
ensures (forall j:int::{TO(j)} TO(j) ==> 0 <= j && j < $nf ==> $GcMem[$ret + 4 * j] == NULL);
|
|
ensures ebp == old(ebp);
|
|
{
|
|
var $ind:int;
|
|
$ind := 0;
|
|
|
|
esi := ?gcLo;
|
|
esi := eax;
|
|
|
|
//while (4 * $ind < $size)
|
|
if (esi >= ebx) { goto loopEnd; }
|
|
loop:
|
|
assert 4 * $ind < $size;
|
|
assert esi == $ret + 4 * $ind;
|
|
assert TO($ind) && $ind >= 0;
|
|
assert MsInv(HeapLo, HeapHi, $color, $GcMem, $toAbs, $AbsMem, $gcSlice);
|
|
assert GcInv(ColorBase, HeapLo, HeapHi, $color, $toAbs, $toAbs, $toAbs, $GcMem);
|
|
assert ObjectSeq(HeapLo, HeapHi, $toAbs, $fs, $fn);
|
|
assert FreeInvBase(HeapLo, HeapHi, $fs, $fn, $GcMem, CachePtr, CacheSize);
|
|
assert (forall i:int::{TV(i)} TV(i) ==> HeapLo <= i && i < HeapHi && $fs[i] != 0 && i != $ret ==>
|
|
FreeInvI(i, HeapLo, HeapHi, $fs, $fn, $GcMem, CachePtr, CacheSize));
|
|
assert (forall j:int::{TO(j)} TO(j) ==> 0 <= j && j < $ind ==> $gcSlice[$ret + 4 * j] == $ret);
|
|
assert (forall j:int::{TO(j)} TO(j) ==> 0 <= j && j < $ind ==> gcAddr($ret + 4 * j)); // REVIEW: necessary?
|
|
assert (forall j:int::{TO(j)} TO(j) ==> 0 <= j && j < $ind ==> $GcMem[$ret + 4 * j] == NULL);
|
|
|
|
call doAllocWord($ret, $ind, $nf);
|
|
$ind := $ind + 1;
|
|
call esi := Add(esi, 4);
|
|
if (esi < ebx) { goto loop; }
|
|
loopEnd:
|
|
}
|
|
|
|
procedure doAllocObject($ra:int, $nextFp:int, $ptr:int, $abs:int, $vt:int, $size:int)
|
|
requires eax == $ptr;
|
|
requires ebx == $ptr + $size;
|
|
requires ecx == $vt;
|
|
requires HeapLo < $ptr && $ptr + 4 * numFields($abs) <= HeapHi && Aligned($ptr);
|
|
requires !VFieldPtr($abs, 0);
|
|
requires !VFieldPtr($abs, 1);
|
|
requires 2 <= numFields($abs);
|
|
requires $size == 4 * numFields($abs);
|
|
requires ObjSize($abs, $vt, $AbsMem[$abs][2], $AbsMem[$abs][3]);
|
|
requires MutatorInv(ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize);
|
|
requires $fs[$ptr] >= 4 * numFields($abs);
|
|
requires CacheSize != 0 ==> $ptr != CachePtr;
|
|
requires Disconnected(HeapLo, $ptr, $fs, $fn);
|
|
|
|
// requirements on vtable and layout:
|
|
requires word($vt) && !gcAddrEx($vt);
|
|
requires VTable($abs, $vt);
|
|
requires ObjSize($abs, $vt, 0, 0);
|
|
requires !isVarSize(tag($vt));
|
|
|
|
// require a fresh, empty abstract node:
|
|
requires $abs != NO_ABS;
|
|
requires (forall i:int::{TV(i)} TV(i) ==> gcAddr(i) ==> $toAbs[i] != $abs);
|
|
requires $AbsMem[$abs][0] == NULL;
|
|
requires $AbsMem[$abs][1] == $vt;
|
|
requires (forall j:int::{TO(j)} TO(j) ==> 2 <= j && j < numFields($abs) ==> $AbsMem[$abs][j] == NULL);
|
|
|
|
modifies $GcMem, $toAbs, $gcSlice, $fs, $color;
|
|
modifies eax, ebx, ecx, edx, esi, edi, ebp, esp;
|
|
|
|
ensures MutatorInv(ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize);
|
|
ensures old($toAbs)[eax - 4] == NO_ABS;
|
|
ensures $toAbs == old($toAbs)[eax - 4 := $abs];
|
|
ensures Pointer($toAbs, eax - 4, $abs);
|
|
ensures ebp == old(ebp);
|
|
{
|
|
assert TV($ptr) && TV($fn[$ptr]);
|
|
|
|
assert TV(eax + 0) && TV(eax + 4);
|
|
assert TO(1) && TO(2);
|
|
assert TO(numFields($abs));
|
|
|
|
call doAllocWords(eax, $size, numFields($abs));
|
|
|
|
call GcStore(eax + 4, ecx);
|
|
|
|
$toAbs[$ptr] := $abs;
|
|
ebx := eax;
|
|
esi := eax;
|
|
call esi := Sub(esi, HeapLo);
|
|
edi := ColorBase;
|
|
edx := 1; // white
|
|
call bb4SetColor($color, 1, HeapLo, HeapLo, HeapLo, HeapHi, $ptr, ColorBase, HeapLo);
|
|
$color[$ptr] := 1; // white
|
|
$fs[$ptr] := 0;
|
|
|
|
assert TO(numFields($abs));
|
|
|
|
call eax := Lea(ebx + 4);
|
|
|
|
assert TV(eax + 4);
|
|
assert TO(0);
|
|
}
|
|
|
|
procedure doAllocString($ra:int, $nextFp:int, $ptr:int, $abs:int, $vt:int, $nElems:int)
|
|
requires eax == $ptr;
|
|
requires ebx == $ptr + pad(16 + 2 * $nElems);
|
|
requires ecx == pad(16 + 2 * $nElems);
|
|
requires edx == $nElems;
|
|
requires $vt == ?STRING_VTABLE;
|
|
requires $ptr + pad(16 + 2 * $nElems) + 0 <= HeapHi;
|
|
|
|
requires HeapLo < $ptr && $ptr + 4 * numFields($abs) <= HeapHi && Aligned($ptr);
|
|
requires !VFieldPtr($abs, 0);
|
|
requires !VFieldPtr($abs, 1);
|
|
requires 2 <= numFields($abs);
|
|
requires ObjSize($abs, $vt, $AbsMem[$abs][2], $AbsMem[$abs][3]);
|
|
requires MutatorInv(ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize);
|
|
requires $fs[$ptr] >= 4 * numFields($abs);
|
|
requires CacheSize != 0 ==> $ptr != CachePtr;
|
|
requires Disconnected(HeapLo, $ptr, $fs, $fn);
|
|
|
|
// requirements on vtable and layout:
|
|
requires word($vt) && !gcAddrEx($vt);
|
|
requires word($nElems);
|
|
requires VTable($abs, $vt);
|
|
requires ObjSize($abs, $vt, $nElems, 0);
|
|
requires tag($vt) == ?STRING_TAG;
|
|
|
|
// require a fresh, empty abstract node:
|
|
requires $abs != NO_ABS;
|
|
requires (forall i:int::{TV(i)} TV(i) ==> gcAddr(i) ==> $toAbs[i] != $abs);
|
|
requires $AbsMem[$abs][0] == NULL;
|
|
requires $AbsMem[$abs][1] == $vt;
|
|
requires $AbsMem[$abs][2] == $nElems;
|
|
requires $AbsMem[$abs][3] == $nElems - 1;
|
|
requires (forall j:int::{TO(j)} TO(j) ==> 4 <= j && 4 * j < pad(16 + 2 * $nElems) ==> $AbsMem[$abs][j] == NULL);
|
|
|
|
modifies $GcMem, $toAbs, $gcSlice, $fs, $color;
|
|
modifies eax, ebx, ecx, edx, esi, edi, ebp, esp;
|
|
|
|
ensures MutatorInv(ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize);
|
|
ensures old($toAbs)[eax - 4] == NO_ABS;
|
|
ensures $toAbs == old($toAbs)[eax - 4 := $abs];
|
|
ensures Pointer($toAbs, eax - 4, $abs);
|
|
ensures ebp == old(ebp);
|
|
{
|
|
assert TV(eax + 0) && TV(eax + 4) && TV(eax + 8) && TV(eax + 12);
|
|
assert TO(1) && TO(2) && TO(3);
|
|
assert TVL($abs);
|
|
assert TVT($abs, $vt);
|
|
assert TO(numFields($abs));
|
|
|
|
call doAllocWords(eax, pad(16 + 2 * $nElems), numFields($abs));
|
|
|
|
call GcStore(eax + 8, edx);
|
|
call edx := SubChecked(edx, 1);
|
|
call GcStore(eax + 12, edx);
|
|
edx := ?STRING_VTABLE;
|
|
call GcStore(eax + 4, edx);
|
|
|
|
$toAbs[$ptr] := $abs;
|
|
ebx := eax;
|
|
esi := eax;
|
|
call esi := Sub(esi, HeapLo);
|
|
edi := ColorBase;
|
|
edx := 1; // white
|
|
call bb4SetColor($color, 1, HeapLo, HeapLo, HeapLo, HeapHi, $ptr, ColorBase, HeapLo);
|
|
$color[$ptr] := 1; // white
|
|
$fs[$ptr] := 0;
|
|
|
|
assert TO(numFields($abs));
|
|
|
|
call eax := Lea(ebx + 4);
|
|
|
|
assert TV(eax + 4);
|
|
assert TO(0);
|
|
}
|
|
|
|
procedure doAllocArrayHelper($abs:int, $vt:int, $rank:int, $nElems:int)
|
|
requires ecx == $vt;
|
|
requires esi == $nElems;
|
|
requires VTable($abs, $vt);
|
|
requires ObjSize($abs, $vt, $rank, $nElems);
|
|
requires tag($vt) == ?PTR_ARRAY_TAG || tag($vt) == ?OTHER_ARRAY_TAG;
|
|
modifies eax, ebx, edx, edi;
|
|
ensures !VFieldPtr($abs, 0);
|
|
ensures !VFieldPtr($abs, 1);
|
|
ensures !VFieldPtr($abs, 2);
|
|
ensures !VFieldPtr($abs, 3);
|
|
ensures between(4, numFields($abs), baseWords($vt));
|
|
ensures eax == 4 * numFields($abs);
|
|
{
|
|
assert TO(2) && TO(3);
|
|
assert TVL($abs);
|
|
assert TVT($abs, $vt);
|
|
|
|
call eax := RoLoad32(ecx + ?VT_BASE_LENGTH);
|
|
call ebx := RoLoad32(ecx + ?VT_ARRAY_ELEMENT_SIZE);
|
|
call edi := RoLoad32(ecx + ?VT_MASK);
|
|
call edi := And(edi, 15);
|
|
|
|
//if (edi == ?PTR_ARRAY_TAG)
|
|
if (edi != ?PTR_ARRAY_TAG) { goto skip1; }
|
|
edi := esi;
|
|
call edi := AddChecked(edi, edi);
|
|
call edi := AddChecked(edi, edi);
|
|
call eax := AddChecked(eax, edi);
|
|
call eax := AddChecked(eax, 3);
|
|
edi := 3;
|
|
call edi := Not(edi);
|
|
call eax := And(eax, edi);
|
|
goto skip2;
|
|
//else
|
|
skip1:
|
|
edi := eax;
|
|
eax := ebx;
|
|
call eax, edx := MulChecked(eax, esi);
|
|
call eax := AddChecked(eax, edi);
|
|
call eax := AddChecked(eax, 3);
|
|
edi := 3;
|
|
call edi := Not(edi);
|
|
call eax := And(eax, edi);
|
|
skip2:
|
|
}
|
|
|
|
procedure doAllocArray($ra:int, $nextFp:int, $ptr:int, $abs:int, $vt:int, $rank:int, $nElems:int, $size:int)
|
|
requires eax == $ptr;
|
|
requires ebx == $ptr + $size;
|
|
requires ecx == $vt;
|
|
requires edx == $rank;
|
|
requires esi == $nElems;
|
|
requires HeapLo < $ptr && $ptr + 4 * numFields($abs) <= HeapHi && Aligned($ptr);
|
|
requires !VFieldPtr($abs, 0);
|
|
requires !VFieldPtr($abs, 1);
|
|
requires !VFieldPtr($abs, 2);
|
|
requires !VFieldPtr($abs, 3);
|
|
requires 4 <= numFields($abs);
|
|
requires $size == 4 * numFields($abs);
|
|
requires ObjSize($abs, $vt, $rank, $nElems);
|
|
requires MutatorInv(ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize);
|
|
requires $fs[$ptr] >= 4 * numFields($abs);
|
|
requires CacheSize != 0 ==> $ptr != CachePtr;
|
|
requires Disconnected(HeapLo, $ptr, $fs, $fn);
|
|
|
|
// requirements on vtable and layout:
|
|
requires word($vt) && !gcAddrEx($vt);
|
|
requires word($rank);
|
|
requires word($nElems);
|
|
requires VTable($abs, $vt);
|
|
requires ObjSize($abs, $vt, $rank, $nElems);
|
|
requires tag($vt) == ?PTR_ARRAY_TAG || tag($vt) == ?OTHER_ARRAY_TAG;
|
|
|
|
// require a fresh, empty abstract node:
|
|
requires $abs != NO_ABS;
|
|
requires (forall i:int::{TV(i)} TV(i) ==> gcAddr(i) ==> $toAbs[i] != $abs);
|
|
requires $AbsMem[$abs][0] == NULL;
|
|
requires $AbsMem[$abs][1] == $vt;
|
|
requires $AbsMem[$abs][2] == $rank;
|
|
requires $AbsMem[$abs][3] == $nElems;
|
|
requires (forall j:int::{TO(j)} TO(j) ==> 4 <= j && j < numFields($abs) ==> $AbsMem[$abs][j] == NULL);
|
|
|
|
modifies $GcMem, $toAbs, $gcSlice, $fs, $color;
|
|
modifies eax, ebx, ecx, edx, esi, edi, ebp, esp;
|
|
|
|
ensures MutatorInv(ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize);
|
|
ensures old($toAbs)[eax - 4] == NO_ABS;
|
|
ensures $toAbs == old($toAbs)[eax - 4 := $abs];
|
|
ensures Pointer($toAbs, eax - 4, $abs);
|
|
ensures ebp == old(ebp);
|
|
{
|
|
var nElems:int;
|
|
nElems := esi;
|
|
|
|
assert TV(eax + 0) && TV(eax + 4) && TV(eax + 8) && TV(eax + 12);
|
|
assert TO(1) && TO(2) && TO(3) && TO(4);
|
|
assert TO(numFields($abs));
|
|
|
|
call doAllocWords(eax, $size, numFields($abs));
|
|
|
|
esi := nElems;
|
|
call GcStore(eax + 4, ecx);
|
|
call GcStore(eax + 8, edx);
|
|
call GcStore(eax + 12, esi);
|
|
|
|
$toAbs[$ptr] := $abs;
|
|
ebx := eax;
|
|
esi := eax;
|
|
call esi := Sub(esi, HeapLo);
|
|
edi := ColorBase;
|
|
edx := 1; // white
|
|
call bb4SetColor($color, 1, HeapLo, HeapLo, HeapLo, HeapHi, $ptr, ColorBase, HeapLo);
|
|
$color[$ptr] := 1; // white
|
|
$fs[$ptr] := 0;
|
|
|
|
assert TO(numFields($abs));
|
|
|
|
call eax := Lea(ebx + 4);
|
|
|
|
assert TV(eax + 4);
|
|
assert TO(0);
|
|
}
|
|
|
|
procedure doAllocVectorHelper($abs:int, $vt:int, $nElems:int)
|
|
requires ecx == $vt;
|
|
requires edx == $nElems;
|
|
requires VTable($abs, $vt);
|
|
requires ObjSize($abs, $vt, $nElems, 0);
|
|
requires tag($vt) == ?PTR_VECTOR_TAG || tag($vt) == ?OTHER_VECTOR_TAG;
|
|
modifies eax, ebx, edx, esi, edi;
|
|
ensures !VFieldPtr($abs, 0);
|
|
ensures !VFieldPtr($abs, 1);
|
|
ensures !VFieldPtr($abs, 2);
|
|
ensures 3 <= numFields($abs);
|
|
ensures eax == 4 * numFields($abs);
|
|
ensures ObjSize($abs, $vt, $nElems, $AbsMem[$abs][3]);
|
|
{
|
|
assert TO(2);
|
|
assert TVL($abs);
|
|
assert TVT($abs, $vt);
|
|
|
|
call eax := RoLoad32(ecx + ?VT_BASE_LENGTH);
|
|
call ebx := RoLoad32(ecx + ?VT_ARRAY_ELEMENT_SIZE);
|
|
call edi := RoLoad32(ecx + ?VT_MASK);
|
|
call edi := And(edi, 15);
|
|
|
|
//if (edi == ?PTR_ARRAY_TAG)
|
|
if (edi != ?PTR_VECTOR_TAG) { goto skip1; }
|
|
edi := edx;
|
|
call edi := AddChecked(edi, edi);
|
|
call edi := AddChecked(edi, edi);
|
|
call eax := AddChecked(eax, edi);
|
|
call eax := AddChecked(eax, 3);
|
|
edi := 3;
|
|
call edi := Not(edi);
|
|
call eax := And(eax, edi);
|
|
goto skip2;
|
|
//else
|
|
skip1:
|
|
edi := eax;
|
|
eax := ebx;
|
|
call eax, edx := MulChecked(eax, edx);
|
|
call eax := AddChecked(eax, edi);
|
|
call eax := AddChecked(eax, 3);
|
|
edi := 3;
|
|
call edi := Not(edi);
|
|
call eax := And(eax, edi);
|
|
skip2:
|
|
}
|
|
|
|
procedure doAllocVector($ra:int, $nextFp:int, $ptr:int, $abs:int, $vt:int, $nElems:int, $size:int)
|
|
requires eax == $ptr;
|
|
requires ebx == $ptr + $size;
|
|
requires ecx == $vt;
|
|
requires edx == $nElems;
|
|
requires HeapLo < $ptr && $ptr + 4 * numFields($abs) <= HeapHi && Aligned($ptr);
|
|
requires !VFieldPtr($abs, 0);
|
|
requires !VFieldPtr($abs, 1);
|
|
requires !VFieldPtr($abs, 2);
|
|
requires 3 <= numFields($abs);
|
|
requires $size == 4 * numFields($abs);
|
|
requires ObjSize($abs, $vt, $nElems, $AbsMem[$abs][3]);
|
|
requires MutatorInv(ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize);
|
|
requires $fs[$ptr] >= 4 * numFields($abs);
|
|
requires CacheSize != 0 ==> $ptr != CachePtr;
|
|
requires Disconnected(HeapLo, $ptr, $fs, $fn);
|
|
|
|
// requirements on vtable and layout:
|
|
requires word($vt) && !gcAddrEx($vt);
|
|
requires word($nElems);
|
|
requires VTable($abs, $vt);
|
|
requires ObjSize($abs, $vt, $nElems, 0);
|
|
requires tag($vt) == ?PTR_VECTOR_TAG || tag($vt) == ?OTHER_VECTOR_TAG;
|
|
|
|
// require a fresh, empty abstract node:
|
|
requires $abs != NO_ABS;
|
|
requires (forall i:int::{TV(i)} TV(i) ==> gcAddr(i) ==> $toAbs[i] != $abs);
|
|
requires $AbsMem[$abs][0] == NULL;
|
|
requires $AbsMem[$abs][1] == $vt;
|
|
requires $AbsMem[$abs][2] == $nElems;
|
|
requires (forall j:int::{TO(j)} TO(j) ==> 3 <= j && j < numFields($abs) ==> $AbsMem[$abs][j] == NULL);
|
|
|
|
modifies $GcMem, $toAbs, $gcSlice, $fs, $color;
|
|
modifies eax, ebx, ecx, edx, esi, edi, ebp, esp;
|
|
|
|
ensures MutatorInv(ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize);
|
|
ensures old($toAbs)[eax - 4] == NO_ABS;
|
|
ensures $toAbs == old($toAbs)[eax - 4 := $abs];
|
|
ensures Pointer($toAbs, eax - 4, $abs);
|
|
ensures ebp == old(ebp);
|
|
{
|
|
assert TV(eax + 0) && TV(eax + 4) && TV(eax + 8);
|
|
assert TO(1) && TO(2) && TO(3);
|
|
assert TO(numFields($abs));
|
|
|
|
call doAllocWords(eax, $size, numFields($abs));
|
|
|
|
call GcStore(eax + 4, ecx);
|
|
call GcStore(eax + 8, edx);
|
|
|
|
|
|
$toAbs[$ptr] := $abs;
|
|
ebx := eax;
|
|
esi := eax;
|
|
call esi := Sub(esi, HeapLo);
|
|
edi := ColorBase;
|
|
edx := 1; // white
|
|
call bb4SetColor($color, 1, HeapLo, HeapLo, HeapLo, HeapHi, $ptr, ColorBase, HeapLo);
|
|
$color[$ptr] := 1; // white
|
|
$fs[$ptr] := 0;
|
|
|
|
assert TO(numFields($abs));
|
|
|
|
call eax := Lea(ebx + 4);
|
|
|
|
assert TV(eax + 4);
|
|
assert TO(0);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// The procedures below are the entry points from the mutator.
|
|
//
|
|
// Therefore, the requires, ensures, and modifies clauses for these procedures
|
|
// are part of the trusted computing base!
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
procedure Initialize()
|
|
modifies $toAbs, $color;
|
|
modifies eax, ebx, ecx, edx, esi, edi, ebp, esp;
|
|
modifies $GcMem, HeapLo, HeapHi, ColorBase, $fn, $fs, CacheSize, ReserveMin;
|
|
ensures MutatorInv(ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize);
|
|
ensures ebp == old(ebp);
|
|
ensures WellFormed($toAbs);
|
|
{
|
|
var save:int;
|
|
var unitSize:int;
|
|
save := ebp;
|
|
|
|
// The gc memory consists a mark stack, a color bit map, and a heap:
|
|
// <--4--><--4--><--64-->
|
|
// The bit map must consist of a multiple of 4 bytes.
|
|
// For each 2 bits in the bit map, there is one word in the heap.
|
|
|
|
// In the worst case, the mark stack could have as many words
|
|
// as there are pointed-to objects in memory. Since an
|
|
// object requires at least 2 words (preheader, header), and
|
|
// a pointer requires 1 word, this means that the mark stack
|
|
// might need to be as big as 1/3 the heap size: 64 / 3 >= 22.
|
|
// We're more optimistic; we pick 1/16 the heap size: 64 / 16 = 4.
|
|
|
|
// Thus, the total gc memory size must be a multiple of:
|
|
// 4 + 4 + 64 = 72 bytes
|
|
|
|
// Compute gcMem size, in bytes and words
|
|
esi := ?gcHi;
|
|
call esi := Sub(esi, ?gcLo);
|
|
edi := esi;
|
|
|
|
// Break into 72-byte units. Let ebp be the number of units.
|
|
edx := 0;
|
|
eax := edi;
|
|
ebx := 72;
|
|
call eax, edx := Div(eax, edx, ebx);
|
|
ebp := eax;
|
|
unitSize := ebp;
|
|
assert 72 * unitSize <= (?gcHi - ?gcLo);
|
|
|
|
if (ebp != 0) { goto skip1; }
|
|
// not enough space for heap data structures
|
|
call DebugBreak();
|
|
skip1:
|
|
|
|
// Divide heap into ?gcLo <--4--> eax <--4--> ebx <--64--> ecx <--> ?gcHi
|
|
edx := 0;
|
|
call ebp := Lea(edx + 4 * ebp);
|
|
eax := ?gcLo;
|
|
call eax := Add(eax, ebp);
|
|
ColorBase := eax;
|
|
//assert ColorBase == ?gcLo + 4 * unitSize;
|
|
call ebx := Lea(eax + ebp);
|
|
HeapLo := ebx;
|
|
//assert HeapLo == ?gcLo + 8 * unitSize;
|
|
call ebp := Lea(edx + 4 * ebp);
|
|
call ecx := Lea(ebx + 4 * ebp);
|
|
HeapHi := ecx;
|
|
//assert HeapHi == ?gcLo + 72 * unitSize;
|
|
|
|
$toAbs := MAP_NO_ABS;
|
|
|
|
assert TV(?gcLo);
|
|
assert TV(ColorBase);
|
|
assert TV(HeapLo);
|
|
assert TV(HeapLo + 8);
|
|
assert TV(HeapHi);
|
|
assert TO(0);
|
|
assert TO(1);
|
|
assert TO(2);
|
|
assert TO(3);
|
|
assert TO(unitSize);
|
|
assert TO(2 * unitSize);
|
|
assert TO(16 * unitSize);
|
|
|
|
$fs := MAP_ZERO;
|
|
$fn := MAP_ZERO;
|
|
$color := MAP_ZERO;
|
|
eax := ColorBase;
|
|
ebx := HeapLo;
|
|
|
|
//assert Aligned(ColorBase);
|
|
//assert Aligned(HeapLo);
|
|
//assert HeapHi - HeapLo == 16 * (HeapLo - ColorBase);
|
|
|
|
esp := esp - 4; call BB4Zero2($color, HeapLo, HeapLo, HeapLo, HeapHi, 0, ColorBase, HeapLo, 0, 0);
|
|
|
|
$fn[HeapLo] := HeapLo + 8;
|
|
$fs[HeapLo] := 8;
|
|
eax := HeapLo;
|
|
call ebx := Lea(eax + 8);
|
|
call GcStore(eax, ebx);
|
|
call GcStore(eax + 4, 8);
|
|
$fs[HeapLo + 8] := HeapHi - (HeapLo + 8);
|
|
$fn[HeapLo + 8] := 0;
|
|
call GcStore(eax + 8, 0);
|
|
ecx := HeapHi;
|
|
call ecx := Sub(ecx, ebx);
|
|
call GcStore(eax + 12, ecx);
|
|
CacheSize := 0;
|
|
|
|
eax := HeapLo;
|
|
// TUNING: wilderness size // REVIEW: this should be a parameter, not hard-wired into the code
|
|
// call eax := AddChecked(eax, 128000000); // Bartok
|
|
// call eax := AddChecked(eax, 8000000); // Zinger, Sat
|
|
ReserveMin := eax;
|
|
|
|
ebp := save;
|
|
esp := esp + 4; return;
|
|
}
|
|
|
|
// Prepare to call GcLoad (don't actually call it -- let the mutator call it)
|
|
procedure readField($ptr:int, $fld:int) returns ($val:int)
|
|
requires MutatorInv(ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize);
|
|
requires Pointer($toAbs, $ptr, $toAbs[$ptr]);
|
|
requires 0 <= $fld && $fld < numFields($toAbs[$ptr]);
|
|
ensures gcAddr($ptr + 4 * $fld);
|
|
ensures $val == $GcMem[$ptr + 4 * $fld];
|
|
ensures Value(VFieldPtr($toAbs[$ptr], $fld), $toAbs, $val, $AbsMem[$toAbs[$ptr]][$fld]);
|
|
{
|
|
// call $val := GcLoad($ptr + 4 * $fld);
|
|
$val := $GcMem[$ptr + 4 * $fld];
|
|
assert TV($val) && TV($ptr);
|
|
assert TO($fld);
|
|
}
|
|
|
|
// Prepare to call GcStore (don't actually call it -- let the mutator call it)
|
|
procedure writeField($ptr:int, $fld:int, $val:int, $abs:int) returns ($_gcData:[int]int, $_absData:[int][int]int)
|
|
requires MutatorInv(ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize);
|
|
requires Pointer($toAbs, $ptr, $toAbs[$ptr]);
|
|
requires 0 <= $fld && $fld < numFields($toAbs[$ptr]);
|
|
requires !isReadonlyField(tag($AbsMem[$toAbs[$ptr]][1]), $fld);
|
|
requires Value(VFieldPtr($toAbs[$ptr], $fld), $toAbs, $val, $abs);
|
|
ensures gcAddr($ptr + 4 * $fld);
|
|
ensures word($val);
|
|
ensures $_gcData == $GcMem[$ptr + 4 * $fld := $val];
|
|
ensures $_absData == $AbsMem[$toAbs[$ptr] := $AbsMem[$toAbs[$ptr]][$fld := $abs]];
|
|
ensures MutatorInv(ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs,
|
|
$_absData, $_gcData, $gcSlice, CachePtr, CacheSize);
|
|
{
|
|
// call GcStore($ptr + 4 * $fld, $val);
|
|
// call AbsEdgeWrite($ptr, $fld, $val);
|
|
$_gcData := $GcMem[$ptr + 4 * $fld := $val];
|
|
$_absData := $AbsMem[$toAbs[$ptr] := $AbsMem[$toAbs[$ptr]][$fld := $abs]];
|
|
assert TVL($toAbs[$ptr]);
|
|
assert TV($val) && TV($ptr);
|
|
assert TO($fld);
|
|
// assert TO(1);
|
|
}
|
|
|
|
procedure AllocObject($ra:int, $abs:int, $vt:int)
|
|
// GC invariant:
|
|
requires MutatorInv(ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize);
|
|
|
|
// requirements on mutator root layout:
|
|
requires 0 <= $FrameCount;
|
|
requires $FrameSlice[esp] == $FrameCount && $FrameMem[esp] == $ra;
|
|
requires FrameNextInv($FrameCount, $ra, ebp, $FrameAddr, $FrameLayout);
|
|
requires StaticInv($toAbs, $SectionMem, $SectionAbs, $Time);
|
|
requires StackInv($toAbs, $FrameCount, $FrameAddr, $FrameLayout, $FrameSlice, $FrameMem, $FrameAbs, $FrameOffset, $Time);
|
|
|
|
// requirements on vtable and layout:
|
|
requires ecx == $vt;
|
|
requires word($vt) && !gcAddrEx($vt);
|
|
requires VTable($abs, $vt);
|
|
requires ObjSize($abs, $vt, 0, 0);
|
|
requires !isVarSize(tag($vt));
|
|
|
|
// require a fresh, empty abstract node:
|
|
requires $abs != NO_ABS;
|
|
requires (forall i:int::{TV(i)} TV(i) ==> gcAddr(i) ==> $toAbs[i] != $abs);
|
|
requires $AbsMem[$abs][0] == NULL;
|
|
requires $AbsMem[$abs][1] == $vt;
|
|
requires (forall j:int::{TO(j)} TO(j) ==> 2 <= j && j < numFields($abs) ==> $AbsMem[$abs][j] == NULL);
|
|
|
|
modifies $r1, $r2, $GcMem, $toAbs, $gcSlice, $color, StackTop, $freshAbs;
|
|
modifies $fs, $fn, CachePtr, CacheSize, ReserveMin;
|
|
modifies eax, ebx, ecx, edx, esi, edi, ebp, esp;
|
|
|
|
ensures StaticInv($toAbs, $SectionMem, $SectionAbs, $Time);
|
|
ensures StackInv($toAbs, $FrameCount, $FrameAddr, $FrameLayout, $FrameSlice, $FrameMem, $FrameAbs, $FrameOffset, $Time);
|
|
ensures MutatorInv(ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize);
|
|
ensures Pointer($toAbs, eax - 4, $abs);
|
|
ensures WellFormed($toAbs);
|
|
ensures ebp == old(ebp);
|
|
{
|
|
var vt:int;
|
|
var fp:int;
|
|
var size:int;
|
|
fp := ebp;
|
|
vt := ecx;
|
|
$freshAbs := $abs;
|
|
|
|
assert TO(2);
|
|
assert TVL($abs);
|
|
assert TVT($abs, $vt);
|
|
call eax := RoLoad32(ecx + ?VT_BASE_LENGTH);
|
|
size := eax;
|
|
|
|
call ecx := FrameLoad(($FrameCount), esp);
|
|
edx := ebp;
|
|
call allocObjectMemory($ra, fp, 4 * numFields($abs), numFields($abs));
|
|
|
|
edx := size;
|
|
call ebx := Lea(eax + edx);
|
|
ecx := vt;
|
|
call doAllocObject($ra, fp, eax, $abs, vt, 4 * numFields($abs));
|
|
|
|
ebp := fp;
|
|
esp := esp + 4; return;
|
|
}
|
|
|
|
procedure AllocString($ra:int, $abs:int, $vt:int, $nElems:int)
|
|
// GC invariant:
|
|
requires MutatorInv(ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize);
|
|
|
|
// requirements on mutator root layout:
|
|
requires 0 <= $FrameCount;
|
|
requires $FrameSlice[esp] == $FrameCount && $FrameMem[esp] == $ra;
|
|
requires FrameNextInv($FrameCount, $ra, ebp, $FrameAddr, $FrameLayout);
|
|
requires StaticInv($toAbs, $SectionMem, $SectionAbs, $Time);
|
|
requires StackInv($toAbs, $FrameCount, $FrameAddr, $FrameLayout, $FrameSlice, $FrameMem, $FrameAbs, $FrameOffset, $Time);
|
|
|
|
// requirements on vtable and layout:
|
|
requires ecx == $nElems - 1;
|
|
requires $vt == ?STRING_VTABLE;
|
|
requires word($vt) && !gcAddrEx($vt);
|
|
requires word($nElems);
|
|
requires VTable($abs, $vt);
|
|
requires ObjSize($abs, $vt, $nElems, 0);
|
|
requires tag($vt) == ?STRING_TAG;
|
|
|
|
// require a fresh, empty abstract node:
|
|
requires $abs != NO_ABS;
|
|
requires (forall i:int::{TV(i)} TV(i) ==> gcAddr(i) ==> $toAbs[i] != $abs);
|
|
requires $AbsMem[$abs][0] == NULL;
|
|
requires $AbsMem[$abs][1] == $vt;
|
|
requires $AbsMem[$abs][2] == $nElems;
|
|
requires $AbsMem[$abs][3] == $nElems - 1;
|
|
requires (forall j:int::{TO(j)} TO(j) ==> 4 <= j && 4 * j < pad(16 + 2 * $nElems) ==> $AbsMem[$abs][j] == NULL);
|
|
|
|
modifies $r1, $r2, $GcMem, $toAbs, $gcSlice, $color, StackTop, $freshAbs;
|
|
modifies $fs, $fn, CachePtr, CacheSize, ReserveMin;
|
|
modifies eax, ebx, ecx, edx, esi, edi, ebp, esp;
|
|
|
|
ensures StaticInv($toAbs, $SectionMem, $SectionAbs, $Time);
|
|
ensures StackInv($toAbs, $FrameCount, $FrameAddr, $FrameLayout, $FrameSlice, $FrameMem, $FrameAbs, $FrameOffset, $Time);
|
|
ensures MutatorInv(ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize);
|
|
ensures Pointer($toAbs, eax - 4, $abs);
|
|
ensures WellFormed($toAbs);
|
|
ensures ebp == old(ebp);
|
|
{
|
|
var fp:int;
|
|
var size:int;
|
|
var nElems:int;
|
|
fp := ebp;
|
|
$freshAbs := $abs;
|
|
|
|
assert TO(2);
|
|
assert TVL($abs);
|
|
assert TVT($abs, $vt);
|
|
call ecx := AddChecked(ecx, 1);
|
|
edx := ecx;
|
|
nElems := edx;
|
|
call ecx := AddChecked(ecx, ecx);
|
|
call ecx := AddChecked(ecx, 19);
|
|
eax := 3;
|
|
call eax := Not(eax);
|
|
call ecx := And(ecx, eax);
|
|
size := ecx;
|
|
eax := ecx;
|
|
|
|
call ecx := FrameLoad(($FrameCount), esp);
|
|
edx := ebp;
|
|
call allocObjectMemory($ra, fp, 4 * numFields($abs), numFields($abs));
|
|
|
|
edx := nElems;
|
|
ecx := size;
|
|
call ebx := Lea(eax + ecx);
|
|
call doAllocString($ra, fp, eax, $abs, ?STRING_VTABLE, $nElems);
|
|
|
|
ebp := fp;
|
|
esp := esp + 4; return;
|
|
}
|
|
|
|
procedure AllocArray($ra:int, $abs:int, $vt:int, $rank:int, $nElems:int)
|
|
// GC invariant:
|
|
requires MutatorInv(ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize);
|
|
|
|
// requirements on mutator root layout:
|
|
requires 0 <= $FrameCount;
|
|
requires $FrameSlice[esp] == $FrameCount && $FrameMem[esp] == $ra;
|
|
requires FrameNextInv($FrameCount, $ra, ebp, $FrameAddr, $FrameLayout);
|
|
requires StaticInv($toAbs, $SectionMem, $SectionAbs, $Time);
|
|
requires StackInv($toAbs, $FrameCount, $FrameAddr, $FrameLayout, $FrameSlice, $FrameMem, $FrameAbs, $FrameOffset, $Time);
|
|
|
|
// requirements on vtable and layout:
|
|
requires ecx == $vt;
|
|
requires edx == $rank;
|
|
requires $FrameSlice[esp + 4] == $FrameCount && $FrameMem[esp + 4] == $nElems;
|
|
requires word($vt) && !gcAddrEx($vt);
|
|
requires word($rank);
|
|
requires word($nElems);
|
|
requires VTable($abs, $vt);
|
|
requires ObjSize($abs, $vt, $rank, $nElems);
|
|
requires tag($vt) == ?PTR_ARRAY_TAG || tag($vt) == ?OTHER_ARRAY_TAG;
|
|
|
|
// require a fresh, empty abstract node:
|
|
requires $abs != NO_ABS;
|
|
requires (forall i:int::{TV(i)} TV(i) ==> gcAddr(i) ==> $toAbs[i] != $abs);
|
|
requires $AbsMem[$abs][0] == NULL;
|
|
requires $AbsMem[$abs][1] == $vt;
|
|
requires $AbsMem[$abs][2] == $rank;
|
|
requires $AbsMem[$abs][3] == $nElems;
|
|
requires (forall j:int::{TO(j)} TO(j) ==> 4 <= j && j < numFields($abs) ==> $AbsMem[$abs][j] == NULL);
|
|
|
|
modifies $r1, $r2, $GcMem, $toAbs, $gcSlice, $color, StackTop, $freshAbs;
|
|
modifies $fs, $fn, CachePtr, CacheSize, ReserveMin;
|
|
modifies eax, ebx, ecx, edx, esi, edi, ebp, esp;
|
|
|
|
ensures StaticInv($toAbs, $SectionMem, $SectionAbs, $Time);
|
|
ensures StackInv($toAbs, $FrameCount, $FrameAddr, $FrameLayout, $FrameSlice, $FrameMem, $FrameAbs, $FrameOffset, $Time);
|
|
ensures MutatorInv(ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize);
|
|
ensures Pointer($toAbs, eax - 4, $abs);
|
|
ensures WellFormed($toAbs);
|
|
ensures ebp == old(ebp);
|
|
{
|
|
var vt:int;
|
|
var rank:int;
|
|
var size:int;
|
|
var nElems:int;
|
|
var fp:int;
|
|
|
|
$freshAbs := $abs;
|
|
rank := edx;
|
|
fp := ebp;
|
|
vt := ecx;
|
|
call esi := FrameLoad(($FrameCount), esp + 4);
|
|
nElems := esi;
|
|
|
|
call doAllocArrayHelper($abs, $vt, $rank, $nElems);
|
|
size := eax;
|
|
|
|
call ecx := FrameLoad(($FrameCount), esp);
|
|
edx := ebp;
|
|
call allocObjectMemory($ra, fp, 4 * numFields($abs), numFields($abs));
|
|
|
|
edx := size;
|
|
call ebx := Lea(eax + edx);
|
|
edx := rank;
|
|
esi := nElems;
|
|
ecx := vt;
|
|
call doAllocArray($ra, fp, eax, $abs, vt, $rank, $nElems, 4 * numFields($abs));
|
|
|
|
ebp := fp;
|
|
esp := esp + 4; return;
|
|
}
|
|
|
|
procedure AllocVector($ra:int, $abs:int, $vt:int, $nElems:int)
|
|
// GC invariant:
|
|
requires MutatorInv(ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize);
|
|
|
|
// requirements on mutator root layout:
|
|
requires 0 <= $FrameCount;
|
|
requires $FrameSlice[esp] == $FrameCount && $FrameMem[esp] == $ra;
|
|
requires FrameNextInv($FrameCount, $ra, ebp, $FrameAddr, $FrameLayout);
|
|
requires StaticInv($toAbs, $SectionMem, $SectionAbs, $Time);
|
|
requires StackInv($toAbs, $FrameCount, $FrameAddr, $FrameLayout, $FrameSlice, $FrameMem, $FrameAbs, $FrameOffset, $Time);
|
|
|
|
// requirements on vtable and layout:
|
|
requires ecx == $vt;
|
|
requires edx == $nElems;
|
|
requires word($vt) && !gcAddrEx($vt);
|
|
requires word($nElems);
|
|
requires VTable($abs, $vt);
|
|
requires ObjSize($abs, $vt, $nElems, 0);
|
|
requires tag($vt) == ?PTR_VECTOR_TAG || tag($vt) == ?OTHER_VECTOR_TAG;
|
|
|
|
// require a fresh, empty abstract node:
|
|
requires $abs != NO_ABS;
|
|
requires (forall i:int::{TV(i)} TV(i) ==> gcAddr(i) ==> $toAbs[i] != $abs);
|
|
requires $AbsMem[$abs][0] == NULL;
|
|
requires $AbsMem[$abs][1] == $vt;
|
|
requires $AbsMem[$abs][2] == $nElems;
|
|
requires (forall j:int::{TO(j)} TO(j) ==> 3 <= j && j < numFields($abs) ==> $AbsMem[$abs][j] == NULL);
|
|
|
|
modifies $r1, $r2, $GcMem, $toAbs, $gcSlice, $color, StackTop, $freshAbs;
|
|
modifies $fs, $fn, CachePtr, CacheSize, ReserveMin;
|
|
modifies eax, ebx, ecx, edx, esi, edi, ebp, esp;
|
|
|
|
ensures StaticInv($toAbs, $SectionMem, $SectionAbs, $Time);
|
|
ensures StackInv($toAbs, $FrameCount, $FrameAddr, $FrameLayout, $FrameSlice, $FrameMem, $FrameAbs, $FrameOffset, $Time);
|
|
ensures MutatorInv(ColorBase, HeapLo, HeapHi, $color, $fs, $fn, $toAbs,
|
|
$AbsMem, $GcMem, $gcSlice, CachePtr, CacheSize);
|
|
ensures Pointer($toAbs, eax - 4, $abs);
|
|
ensures WellFormed($toAbs);
|
|
ensures ebp == old(ebp);
|
|
{
|
|
var vt:int;
|
|
var size:int;
|
|
var nElems:int;
|
|
var fp:int;
|
|
|
|
$freshAbs := $abs;
|
|
fp := ebp;
|
|
vt := ecx;
|
|
nElems := edx;
|
|
|
|
call doAllocVectorHelper($abs, $vt, $nElems);
|
|
size := eax;
|
|
|
|
call ecx := FrameLoad(($FrameCount), esp);
|
|
edx := ebp;
|
|
call allocObjectMemory($ra, fp, 4 * numFields($abs), numFields($abs));
|
|
|
|
edx := size;
|
|
call ebx := Lea(eax + edx);
|
|
edx := nElems;
|
|
ecx := vt;
|
|
call doAllocVector($ra, fp, eax, $abs, vt, $nElems, 4 * numFields($abs));
|
|
|
|
ebp := fp;
|
|
esp := esp + 4; return;
|
|
}
|
|
|