2804 lines
106 KiB
Plaintext
2804 lines
106 KiB
Plaintext
//
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//
|
|
|
|
// Verified copying garbage collector
|
|
//
|
|
// medium term goal: support more Bartok array-of-struct and vector-of-struct object layouts
|
|
// medium term goal: make generational
|
|
// 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 VerifiedCopyingCollector.bpl
|
|
|
|
/*****************************************************************************
|
|
******************************************************************************
|
|
**** VERIFIED
|
|
******************************************************************************
|
|
*****************************************************************************/
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// COPYING COLLECTOR
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
function IsFwdPtr(i:int) returns(bool) { gcAddrEx(i) }
|
|
|
|
var $freshAbs:int;
|
|
|
|
// The allocation bitmap ranges from ?gcLo..HeapLo
|
|
// The spaces (from and to) range from HeapLo..?gcHi
|
|
var HeapLo:int;
|
|
// Fromspace ranges from Fi to Fl, where Fk..Fl is empty
|
|
// Tospace ranges from Ti to Tl, where Tk..Tl is empty
|
|
var Fi:int;
|
|
var Fk:int;
|
|
var Fl:int;
|
|
var Ti:int;
|
|
var Tj:int;
|
|
var Tk:int;
|
|
var Tl:int;
|
|
// Bitmaps for fromspace and tospace:
|
|
var BF:int;
|
|
var BT:int;
|
|
|
|
function ObjectSpc(i1:int, i2:int, r:[int]int) returns (bool)
|
|
{
|
|
(forall i:int::{TV(i)} TV(i) ==> i1 <= i && i < i2 && r[i] != NO_ABS ==>
|
|
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))
|
|
}
|
|
|
|
function ObjectSeq(i1:int, i2:int, r:[int]int) returns (bool)
|
|
{
|
|
(i1 == i2 || r[i1] != NO_ABS)
|
|
&& (forall i:int::{TV(i)} TV(i) ==> i1 <= i && i < i2 && r[i] != NO_ABS ==>
|
|
(forall ii:int::{TV(ii)} TV(ii) ==> i < ii && ii < i + 4 * numFields(r[i]) ==>
|
|
r[ii] == NO_ABS)
|
|
&& (forall j:int::{TO(j)} TO(j) ==> 0 <= j && j < numFields(r[i]) ==> gcAddr(i + 4 * j)) // REVIEW: necessary?
|
|
&& ( (i + 4 * numFields(r[i]) == i2)
|
|
|| (i + 4 * numFields(r[i]) < i2 && r[i + 4 * numFields(r[i])] != NO_ABS)))
|
|
}
|
|
|
|
function EmptySeq(i1:int, i2:int, r:[int]int, $toAbs:[int]int) returns (bool)
|
|
{
|
|
(forall i:int::{TV(i)} TV(i) ==> i1 <= i && i < i2 ==> gcAddr(i) && r[i] == NO_ABS && $toAbs[i] == NO_ABS) // REVIEW: gcAddr necessary?
|
|
}
|
|
|
|
// invariant:
|
|
// note: typically, Tj = _tj and Tk = _tk
|
|
function CopyGcInv($freshAbs:int, BF:int, BT:int, HeapLo:int, Fi:int, Fk:int, Fl:int, Ti:int, Tj:int, _tj:int, Tk:int, _tk:int, Tl:int, $Time:Time, $r1:[int]int, $r2:[int]int,
|
|
r1Live:bool, $toAbs:[int]int, $AbsMem:[int][int]int,
|
|
$GcMem:[int]int, $gcSlice:[int]int) returns (bool)
|
|
{
|
|
?gcLo <= HeapLo
|
|
&& HeapLo <= ?gcHi
|
|
&& ((Fi == HeapLo && Ti == Fl && BF == ?gcLo) || (Ti == HeapLo && Fi == Tl && BT == ?gcLo))
|
|
&& (Fi == HeapLo ==> ?gcLo + BitIndex(HeapLo, Fl) == BT && ?gcLo + BitIndex(HeapLo, Tl) == HeapLo)
|
|
&& (Ti == HeapLo ==> ?gcLo + BitIndex(HeapLo, Tl) == BF && ?gcLo + BitIndex(HeapLo, Fl) == HeapLo)
|
|
&& Fi <= Fk && Fk <= Fl && Fl <= ?gcHi
|
|
&& Ti <= Tj && Tj <= _tj && _tj <= Tk && Tk <= _tk && _tk <= Tl && Tl <= ?gcHi
|
|
&& Aligned(Fi) && Aligned(Fk) && Aligned(Ti) && Aligned(Tj) && Aligned(Tk)
|
|
&& Aligned(?gcLo + BitIndex(HeapLo, Fi)) && Aligned(?gcLo + BitIndex(HeapLo, Ti))
|
|
&& ?gcLo <= ?gcLo + BitIndex(HeapLo, Fi) && ?gcLo + BitIndex(HeapLo, Fl) <= HeapLo
|
|
&& ?gcLo <= ?gcLo + BitIndex(HeapLo, Ti) && ?gcLo + BitIndex(HeapLo, Tl) <= HeapLo
|
|
&& BF == ?gcLo + BitIndex(HeapLo, Fi) && BT == ?gcLo + BitIndex(HeapLo, Ti)
|
|
&& (Fl - Fi) == Mult(32, (BitIndex(HeapLo, Fl) - BitIndex(HeapLo, Fi))) // Mult is faster than "*" here
|
|
&& (Tl - Ti) == Mult(32, (BitIndex(HeapLo, Tl) - BitIndex(HeapLo, Ti))) // Mult is faster than "*" here
|
|
&& bbvec4($r1, NO_ABS, Fi, $GcMem, Fi, Fi, Fl, ?gcLo + BitIndex(HeapLo, Fi), ?gcLo + BitIndex(HeapLo, Fl))
|
|
&& bbvec4($toAbs, NO_ABS, Ti, $GcMem, Ti, Ti, Tl, ?gcLo + BitIndex(HeapLo, Ti), ?gcLo + BitIndex(HeapLo, Tl))
|
|
&& WellFormed($toAbs)
|
|
&& ObjectSpc(Fi, Fk, $r1)
|
|
&& EmptySeq( Fk, Fl, $r1, $toAbs)
|
|
&& ObjectSpc(Ti, Tj, $r2)
|
|
&& ObjectSeq(_tj, Tk, $r2)
|
|
&& EmptySeq( _tk, Tl, $r2, $toAbs)
|
|
&& (forall i:int::{TV(i)} TV(i) ==> gcAddr(i) ==> $r1[i] != NO_ABS && r1Live ==> Fi <= i && i < Fk)
|
|
&& (forall i:int::{TV(i)} TV(i) ==> gcAddr(i) ==> $r2[i] != NO_ABS ==> Ti <= i && i < _tk)
|
|
&& (forall i:int::{TV(i)} TV(i) ==> Fi <= i && i < Fk && $r1[i] != NO_ABS ==>
|
|
( IsFwdPtr($GcMem[i + 4]) <==> $toAbs[i] == NO_ABS)
|
|
&& ( IsFwdPtr($GcMem[i + 4]) ==> Pointer($r2, $GcMem[i + 4] - 4, $r1[i]) && AlignedHeapAddr(i + 4) && word($GcMem[i + 4]))
|
|
&& (!IsFwdPtr($GcMem[i + 4]) ==> $toAbs[i] == $r1[i])
|
|
&& (!IsFwdPtr($GcMem[i + 4]) ==> r1Live ==> ObjInv(i, $r1, $r1, $toAbs, $AbsMem, $GcMem, $gcSlice))
|
|
&& i + 4 < Fk // REVIEW: hack?
|
|
&& Aligned(i) // REVIEW: redundant?
|
|
)
|
|
&& (forall i:int::{TV(i)} TV(i) ==> Fi <= i && i < Fl && $toAbs[i] != NO_ABS ==> $r1[i] != NO_ABS && $r1[i] != NO_ABS)
|
|
&& (forall i:int::{TV(i)} TV(i) ==> Ti <= i && i < Tl && $toAbs[i] != NO_ABS ==> $r2[i] != NO_ABS && $r2[i] != NO_ABS)
|
|
&& (forall i:int::{TV(i)} TV(i) ==> Ti <= i && i < Tj && $r2[i] != NO_ABS ==>
|
|
$toAbs[i] != NO_ABS && $toAbs[i] == $r2[i]
|
|
&& reached($toAbs[i], $Time)
|
|
&& ObjInv(i, $r2, $r2, $toAbs, $AbsMem, $GcMem, $gcSlice)
|
|
&& !IsFwdPtr($GcMem[i + 4])
|
|
)
|
|
&& (Tj != _tj ==> (forall j:int::{TO(j)} TO(j) ==> 0 <= j && Tj + 4 * j < _tj ==>
|
|
gcAddr(Tj + 4 * j) && $gcSlice[Tj + 4 * j] == Tj)) // REVIEW: gcAddr necessary?
|
|
&& (forall i:int::{TV(i)} TV(i) ==> Tj < i && i < _tj ==> $r2[i] == NO_ABS)
|
|
&& (forall i:int::{TV(i)} TV(i) ==> _tj <= i && i < Tk && $r2[i] != NO_ABS ==>
|
|
$toAbs[i] != NO_ABS && $toAbs[i] == $r2[i]
|
|
&& reached($toAbs[i], $Time)
|
|
&& ObjInv(i, $r2, $r1, $toAbs, $AbsMem, $GcMem, $gcSlice)
|
|
&& !IsFwdPtr($GcMem[i + 4])
|
|
)
|
|
&& (forall i:int::{TV(i)} TV(i) ==> gcAddr(i) ==> $toAbs[i] != $freshAbs && $r2[i] != $freshAbs)
|
|
}
|
|
|
|
function MutatorInv(BF:int, BT:int, HeapLo:int, Fi:int, Fk:int, Fl:int, Ti:int, Tj:int, Tk:int, Tl:int,
|
|
$GcMem:[int]int, $toAbs:[int]int, $AbsMem:[int][int]int, $gcSlice:[int]int) returns (bool)
|
|
{
|
|
?gcLo <= HeapLo
|
|
&& HeapLo <= ?gcHi
|
|
&& ((Fi == HeapLo && Ti == Fl && BF == ?gcLo) || (Ti == HeapLo && Fi == Tl && BT == ?gcLo))
|
|
&& (Fi == HeapLo ==> ?gcLo + BitIndex(HeapLo, Fl) == BT && ?gcLo + BitIndex(HeapLo, Tl) == HeapLo)
|
|
&& (Ti == HeapLo ==> ?gcLo + BitIndex(HeapLo, Tl) == BF && ?gcLo + BitIndex(HeapLo, Fl) == HeapLo)
|
|
&& Fi <= Fk && Fk <= Fl && Fl <= ?gcHi
|
|
&& Ti <= Tj && Tj <= Tk && Tk <= Tl && Tl <= ?gcHi
|
|
&& Aligned(Fi) && Aligned(Fk) && Aligned(Ti) && Aligned(Tj) && Aligned(Tk)
|
|
&& Aligned(?gcLo + BitIndex(HeapLo, Fi)) && Aligned(?gcLo + BitIndex(HeapLo, Ti))
|
|
&& ?gcLo <= ?gcLo + BitIndex(HeapLo, Fi) && ?gcLo + BitIndex(HeapLo, Fl) <= HeapLo
|
|
&& ?gcLo <= ?gcLo + BitIndex(HeapLo, Ti) && ?gcLo + BitIndex(HeapLo, Tl) <= HeapLo
|
|
&& BF == ?gcLo + BitIndex(HeapLo, Fi) && BT == ?gcLo + BitIndex(HeapLo, Ti)
|
|
&& (Fl - Fi) == Mult(32, (BitIndex(HeapLo, Fl) - BitIndex(HeapLo, Fi))) // Mult is faster than "*" here
|
|
&& (Tl - Ti) == Mult(32, (BitIndex(HeapLo, Tl) - BitIndex(HeapLo, Ti))) // Mult is faster than "*" here
|
|
&& bbvec4($toAbs, NO_ABS, Fi, $GcMem, Fi, Fi, Fl, ?gcLo + BitIndex(HeapLo, Fi), ?gcLo + BitIndex(HeapLo, Fl))
|
|
&& WellFormed($toAbs)
|
|
&& ObjectSpc(Fi, Fk, $toAbs)
|
|
&& EmptySeq( Fk, Fl, $toAbs, $toAbs)
|
|
&& EmptySeq( Ti, Tl, $toAbs, $toAbs)
|
|
&& (forall i:int::{TV(i)} TV(i) ==> gcAddr(i) ==> ($toAbs[i] != NO_ABS ==> Fi <= i && i < Fk))
|
|
&& (forall i:int::{TV(i)} TV(i) ==> Fi <= i && i < Fk && $toAbs[i] != NO_ABS ==>
|
|
$toAbs[i] != NO_ABS
|
|
&& ObjInv(i, $toAbs, $toAbs, $toAbs, $AbsMem, $GcMem, $gcSlice)
|
|
&& !IsFwdPtr($GcMem[i + 4])
|
|
)
|
|
&& (forall i:int::{TV(i)} TV(i) ==> Fi <= i && i < Fl && $toAbs[i] != NO_ABS ==> $toAbs[i] != NO_ABS)
|
|
&& (forall i:int::{TV(i)} TV(i) ==> Ti <= i && i < Tl && $toAbs[i] != NO_ABS ==> false)
|
|
}
|
|
|
|
procedure BB4Zero($a:[int]int, $on:int, $off: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)] == $off);
|
|
requires Aligned($g1) && Aligned($g2);
|
|
requires $i2 - $i1 == 32 * ($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 bbvec4($a, $off, $aBase, $GcMem, $i0, $i1, $i2, $g1, $g2);
|
|
ensures (forall i:int::{TV(i)} TV(i) && !between($g1, $g2, i) ==> $GcMem[i] == old($GcMem)[i]);
|
|
ensures (forall i:int::{TV(i)} TV(i) && !between($g1, $g2, i + 4) ==> $GcMem[i + 4] == old($GcMem)[i + 4]); // REVIEW: HACK?
|
|
ensures (forall i:int,j:int::{TV(i),TO(j)} TV(i) && TO(j) && !between($g1, $g2, i + 4 * j) ==> $GcMem[i + 4 * j] == old($GcMem)[i + 4 * j]); // REVIEW: HACK?
|
|
ensures (forall i:int::{TV(i)} TV(i) && !between($g1, $g2, $_g1 + BitIndex($_i0, i)) ==> $GcMem[$_g1 + BitIndex($_i0, i)] == old($GcMem)[$_g1 + BitIndex($_i0, i)]); // REVIEW: HACK?
|
|
{
|
|
var $iter:int;
|
|
esi := eax;
|
|
$iter := $i1;
|
|
//while (esi < $g2)
|
|
loop:
|
|
assert Aligned(esi) && TV(esi);
|
|
assert $g1 <= esi && esi <= $g2;
|
|
assert $iter - $i1 == 32 * (esi - $g1);
|
|
assert bbvec4($a, $off, $aBase, $GcMem, $i0, $i1, $iter, $g1, $g2);
|
|
assert (forall i:int::{TV(i)} TV(i) && !between($g1, $g2, i) ==> $GcMem[i] == old($GcMem)[i]);
|
|
assert (forall i:int::{TV(i)} TV(i) && !between($g1, $g2, i + 4) ==> $GcMem[i + 4] == old($GcMem)[i + 4]); // REVIEW: HACK?
|
|
assert (forall i:int,j:int::{TV(i),TO(j)} TV(i) && TO(j) && !between($g1, $g2, i + 4 * j) ==> $GcMem[i + 4 * j] == old($GcMem)[i + 4 * j]); // REVIEW: HACK?
|
|
assert (forall i:int::{TV(i)} TV(i) && !between($g1, $g2, $_g1 + BitIndex($_i0, i)) ==> $GcMem[$_g1 + BitIndex($_i0, i)] == old($GcMem)[$_g1 + BitIndex($_i0, i)]); // REVIEW: HACK?
|
|
if (esi >= ebx) { goto loopEnd; }
|
|
|
|
call __notAligned(esi);
|
|
call __bb4Zero($a, $off, $aBase, $GcMem, $i0, $i1, $iter, $g1, $g2, esi);
|
|
call GcStore(esi, 0);//$GcMem[esi] := 0;
|
|
$iter := $iter + 128;
|
|
call esi := Add(esi, 4);
|
|
assert TO(1);
|
|
goto loop;
|
|
loopEnd:
|
|
|
|
assert esi == $g2;
|
|
assert $iter == $i2;
|
|
esp := esp + 4; return;
|
|
}
|
|
|
|
procedure bb4GetBit($a:[int]int, $off:int, $aBase:int, $i0:int, $i1:int, $i2:int, $k:int, $g1:int, $g2:int)
|
|
requires bbvec4($a, $off, $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 == 0 <==> $a[$aBase + ($k - $i0)] == $off;
|
|
{
|
|
var $idx:int;
|
|
var $bbb:int;
|
|
$idx := $g1 + 4 * shr($k - $i0, 7);
|
|
$bbb := and($GcMem[$idx], shl(1, and(shr($k - $i0, 2), 31)));
|
|
call __subAligned($k, $i0);
|
|
call __bb4GetBit($a, $off, $aBase, $GcMem, $i0, $i1, $i2, $k, $idx, $bbb, $g1, $g2);
|
|
|
|
edx := ebx;
|
|
assert TV($g1);
|
|
assert TO(shr(ebx, 7));
|
|
call ebx := Shr(ebx, 7);
|
|
call edx := Shr(edx, 2);
|
|
call ebx := Add(ebx, ebx);
|
|
call ebx := Add(ebx, ebx);
|
|
call ebx := Add(ebx, eax);
|
|
call ebx := GcLoad(ebx);
|
|
call edx := And(edx, 31);
|
|
ecx := edx;
|
|
edx := 1;
|
|
call edx := Shl(edx, ecx);
|
|
call ebx := And(ebx, edx);
|
|
}
|
|
|
|
procedure bb4SetBit($a:[int]int, $on:int, $off:int, $aBase:int, $i0:int, $i1:int, $i2:int, $k:int, $g1:int, $g2:int)
|
|
requires bbvec4($a, $off, $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 $on != $off;
|
|
requires word($i2 - $i0);
|
|
requires esi == $k - $i0;
|
|
requires edi == $g1;
|
|
requires Aligned($g1) && ?gcLo <= $g1 && $g2 <= ?gcHi;
|
|
requires word($i1 - $i0) && word($i2 - $i0);
|
|
modifies esi, edi, ecx, $GcMem;
|
|
ensures bbvec4($a[$aBase + ($k - $i0) := $on], $off, $aBase, $GcMem, $i0, $i1, $i2, $g1, $g2);
|
|
ensures $GcMem == old($GcMem)[$g1 + BitIndex($i0, $k) := edi];
|
|
ensures Aligned($k - $i0);
|
|
{
|
|
var $idx:int;
|
|
var $bbb:int;
|
|
$idx := $g1 + 4 * shr($k - $i0, 7);
|
|
$bbb := or($GcMem[$idx], shl(1, and(shr($k - $i0, 2), 31)));
|
|
call __subAligned($k, $i0);
|
|
call __bb4SetBit($a, $on, $off, $aBase, $GcMem, $i0, $i1, $i2, $k, $idx, $bbb, $GcMem[$idx := $bbb], $g1, $g2);
|
|
|
|
ecx := esi;
|
|
assert TV($g1);
|
|
assert TO(shr(esi, 7));
|
|
call esi := Shr(esi, 7);
|
|
call ecx := Shr(ecx, 2);
|
|
call esi := Add(esi, esi);
|
|
call esi := Add(esi, esi);
|
|
call esi := Add(esi, edi);
|
|
call ecx := And(ecx, 31);
|
|
edi := 1;
|
|
call edi := Shl(edi, ecx);
|
|
ecx := edi; // REVIEW: optimize this more
|
|
call edi := GcLoad(esi);
|
|
call edi := Or(edi, ecx);
|
|
call GcStore(esi, edi);
|
|
}
|
|
|
|
procedure copyWord($ptr:int, $_tj:int, $ret:int, $ind:int, $s:int)
|
|
requires ecx == $ptr && esi == $ret && edi == $ind;
|
|
requires Pointer($r1, $ptr, $r1[$ptr]) && TV($ptr);
|
|
requires !IsFwdPtr($GcMem[$ptr + 4]);
|
|
requires $_tj <= Tk;
|
|
|
|
requires $s == 4 * numFields($r1[$ptr]);
|
|
requires Tk == $ret + $s;
|
|
requires Tk <= Tl;
|
|
|
|
requires TO($ind) && 0 <= $ind && $ind < numFields($r1[$ptr]);
|
|
requires CopyGcInv($freshAbs, BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, $_tj, $ret, Tk, Tl, $Time, $r1, $r2, true, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
requires (forall j:int::{TO(j)} TO(j) ==> 0 <= j && j < $ind ==> gcAddr($ret + 4 * j) && $gcSlice[$ret + 4 * j] == $ret); // REVIEW: gcAddr necessary?
|
|
requires EmptySeq($ret + 4 * $ind, Tk, $r2, $toAbs);
|
|
requires (forall j:int::{TO(j)} TO(j) ==>
|
|
0 <= j && j < $ind ==> Value(VFieldPtr($r1[$ptr], j), $r1, $GcMem[$ret + 4 * j], $AbsMem[$toAbs[$ptr]][j]));
|
|
requires (forall i:int::{TV(i)} TV(i) ==> $ret < i && i < $ret + 4 * $ind ==> $r2[i] == NO_ABS);
|
|
requires $r2[$ret] == NO_ABS;
|
|
|
|
modifies $GcMem, $gcSlice;
|
|
modifies eax, ebx;
|
|
|
|
ensures CopyGcInv($freshAbs, BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, $_tj, $ret, Tk, Tl, $Time, $r1, $r2, true, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
ensures (forall j:int::{TO(j)} TO(j) ==> 0 <= j && j < $ind + 1 ==> gcAddr($ret + 4 * j) && $gcSlice[$ret + 4 * j] == $ret); // REVIEW: gcAddr necessary?
|
|
ensures (forall j:int::{TO(j)} TO(j) ==>
|
|
0 <= j && j < $ind + 1 ==> Value(VFieldPtr($r1[$ptr], j), $r1, $GcMem[$ret + 4 * j], $AbsMem[$toAbs[$ptr]][j]));
|
|
ensures (forall j:int::{TO(j)} TO(j) ==> 0 <= j && Tj + 4 * j < $_tj ==>
|
|
$GcMem[Tj + 4 * j] == old($GcMem)[Tj + 4 * j] && $gcSlice[Tj + 4 * j] == old($gcSlice[Tj + 4 * j]));
|
|
|
|
ensures RExtend(old($r2), $r2);
|
|
{
|
|
assert TO(numFields($r1[$ptr]));
|
|
assert TV($ret);
|
|
|
|
call eax := GcLoad(ecx + 4 * edi);
|
|
assert TV($ret + 4 * $ind);
|
|
$gcSlice[$ret + 4 * $ind] := $ret;
|
|
call GcStore(esi + 4 * edi, eax);
|
|
assert TO(1);
|
|
}
|
|
|
|
procedure CopyAndForward($ptr:int, $_tj:int)
|
|
requires ecx == $ptr;
|
|
requires CopyGcInv($freshAbs, BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, $_tj, Tk, Tk, Tl, $Time, $r1, $r2, true, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
requires Pointer($r1, $ptr, $r1[$ptr]) && TV($ptr);
|
|
requires !IsFwdPtr($GcMem[$ptr + 4]);
|
|
requires $_tj <= Tk;
|
|
requires reached($toAbs[$ptr], $Time);
|
|
modifies $r2, $GcMem, $toAbs, Tk, $gcSlice;
|
|
modifies eax, ebx, ecx, edx, esi, edi, ebp, esp;
|
|
ensures CopyGcInv($freshAbs, BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, $_tj, Tk, Tk, Tl, $Time, $r1, $r2, true, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
ensures RExtend(old($r2), $r2);
|
|
ensures Pointer($r2, eax, $r1[$ptr]);
|
|
ensures Tj == old(Tj);
|
|
ensures Tk >= old(Tk);
|
|
ensures old($toAbs)[Tj] != NO_ABS ==> $toAbs[Tj] != NO_ABS && $toAbs[Tj] == old($toAbs)[Tj];
|
|
ensures (forall j:int::{TO(j)} TO(j) ==> 0 <= j && Tj + 4 * j < $_tj ==>
|
|
$GcMem[Tj + 4 * j] == old($GcMem)[Tj + 4 * j] && $gcSlice[Tj + 4 * j] == old($gcSlice[Tj + 4 * j]));
|
|
ensures Ti <= eax && eax < Tk && gcAddrEx(eax + 4);
|
|
{
|
|
var tmp:int;
|
|
|
|
call edx := GcLoad(ecx + 4);
|
|
esp := esp - 4; call GetSize($ptr, edx, $r1, $r1);
|
|
ebp := eax;
|
|
assert TO(numFields($r1[$ptr]));
|
|
|
|
esi := Tk;
|
|
call Tk := AddChecked(Tk, ebp);
|
|
assert TV(esi);
|
|
|
|
eax := Tl;
|
|
if (Tk <= eax) { goto skip1; }
|
|
// out of memory
|
|
call DebugBreak();
|
|
skip1:
|
|
|
|
edi := 0;
|
|
edx := 0;
|
|
// while (edx < ebp)
|
|
loop:
|
|
assert 4 * edi == edx;
|
|
assert TO(edi) && 0 <= edi && edi <= numFields($r1[$ptr]);
|
|
assert CopyGcInv($freshAbs, BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, $_tj, esi, Tk, Tl, $Time, $r1, $r2, true, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
assert RExtend(old($r2), $r2);
|
|
assert (forall j:int::{TO(j)} TO(j) ==> 0 <= j && j < edi ==> gcAddr(esi + 4 * j) && $gcSlice[esi + 4 * j] == esi); // REVIEW: gcAddr necessary?
|
|
assert EmptySeq(esi + 4 * edi, Tk, $r2, $toAbs);
|
|
assert (forall j:int::{TO(j)} TO(j) ==>
|
|
0 <= j && j < edi ==> Value(VFieldPtr($r1[$ptr], j), $r1, $GcMem[esi + 4 * j], $AbsMem[$toAbs[$ptr]][j]));
|
|
assert (forall i:int::{TV(i)} TV(i) ==> esi < i && i < esi + 4 * edi ==> $r2[i] == NO_ABS);
|
|
assert (forall j:int::{TO(j)} TO(j) ==> 0 <= j && Tj + 4 * j < $_tj ==>
|
|
$GcMem[Tj + 4 * j] == old($GcMem)[Tj + 4 * j] && $gcSlice[Tj + 4 * j] == old($gcSlice[Tj + 4 * j]));
|
|
assert $r2[esi] == NO_ABS;
|
|
if (edx >= ebp) { goto loopEnd; }
|
|
|
|
call copyWord($ptr, $_tj, esi, edi, ebp);
|
|
call edi := Add(edi, 1);
|
|
call edx := Add(edx, 4);
|
|
goto loop;
|
|
loopEnd:
|
|
|
|
call eax := Lea(esi + 4);
|
|
call GcStore(ecx + 4, eax);
|
|
|
|
eax := esi;
|
|
|
|
call esi := Sub(esi, Ti);
|
|
|
|
edi := BT;
|
|
call bb4SetBit($toAbs, $r1[$ptr], NO_ABS, Ti, Ti, Ti, Tl, eax, ?gcLo + BitIndex(HeapLo, Ti), ?gcLo + BitIndex(HeapLo, Tl));
|
|
|
|
$r2[eax] := $r1[$ptr];
|
|
$toAbs[eax] := $toAbs[$ptr];
|
|
$toAbs[$ptr] := NO_ABS;
|
|
assert TO(1);
|
|
|
|
assert TV(eax - Ti);
|
|
|
|
esp := esp + 4; return;
|
|
}
|
|
|
|
procedure forwardFromspacePtr($ptr:int, $abs:int, $_tj:int)
|
|
requires ecx == $ptr;
|
|
requires CopyGcInv($freshAbs, BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, $_tj, Tk, Tk, Tl, $Time, $r1, $r2, true, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
requires word($ptr);
|
|
requires Pointer($r1, $ptr - 4, $abs);
|
|
requires $_tj <= Tk;
|
|
requires IsFwdPtr($GcMem[$ptr]) || reached($toAbs[$ptr - 4], $Time);
|
|
modifies $r2, $GcMem, $toAbs, Tk, $gcSlice;
|
|
modifies eax, ebx, ecx, edx, esi, edi, ebp, esp;
|
|
ensures CopyGcInv($freshAbs, BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, $_tj, Tk, Tk, Tl, $Time, $r1, $r2, true, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
ensures RExtend(old($r2), $r2);
|
|
ensures Pointer($r2, eax - 4, $abs);
|
|
ensures Tj == old(Tj);
|
|
ensures Tk >= old(Tk);
|
|
ensures old($toAbs)[Tj] != NO_ABS ==> $toAbs[Tj] != NO_ABS && $toAbs[Tj] == old($toAbs)[Tj];
|
|
ensures (forall j:int::{TO(j)} TO(j) ==> 0 <= j && Tj + 4 * j < $_tj ==>
|
|
$GcMem[Tj + 4 * j] == old($GcMem)[Tj + 4 * j] && $gcSlice[Tj + 4 * j] == old($gcSlice[Tj + 4 * j]));
|
|
ensures Ti <= eax - 4 && eax - 4 < Tk;
|
|
ensures gcAddrEx(eax);
|
|
{
|
|
assert TV($ptr - 4);
|
|
call eax := GcLoad(ecx);
|
|
|
|
if (?gcLo > eax) { goto skip; }
|
|
if (?gcHi >= eax) { goto done; }
|
|
skip:
|
|
call ecx := Sub(ecx, 4);
|
|
esp := esp - 4; call CopyAndForward($ptr - 4, $_tj);
|
|
call eax := Add(eax, 4);
|
|
done:
|
|
assert TV(eax - 4);
|
|
}
|
|
|
|
procedure scanObjectDense($vt:int)
|
|
requires ecx == $vt;
|
|
requires CopyGcInv($freshAbs, BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, Tj, Tk, Tk, Tl, $Time, $r1, $r2, true, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
requires Tj < Tk;
|
|
requires TV(Tj);
|
|
requires $vt == $AbsMem[$r2[Tj]][1];
|
|
requires tag($vt) == ?DENSE_TAG;
|
|
modifies $r2, $GcMem, $toAbs, Tj, Tk, $gcSlice;
|
|
modifies eax, ebx, ecx, edx, esi, edi, ebp, esp;
|
|
ensures CopyGcInv($freshAbs, BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, Tj, Tk, Tk, Tl, $Time, $r1, $r2, true, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
ensures RExtend(old($r2), $r2);
|
|
{
|
|
var save1:int;
|
|
var save2:int;
|
|
var save3:int;
|
|
assert TO(numFields($r2[Tj]));
|
|
|
|
esi := 2;
|
|
assert TVT($r2[Tj], $vt);
|
|
assert TVL($r2[Tj]);
|
|
call ebp := RoLoad32(ecx + ?VT_BASE_LENGTH);
|
|
call edx := RoLoad32(ecx + ?VT_MASK);
|
|
edi := Tj;
|
|
call edi := Add(edi, 8);
|
|
call ebp := Add(ebp, Tj);
|
|
|
|
//while (edi < ebp)
|
|
loop:
|
|
assert TO(esi);// && 0 < esi;
|
|
assert edi == Tj + 4 * esi && ebp == Tj + 4 * numFields($r2[Tj]) && edx == mask($vt);
|
|
assert 2 <= esi && esi <= numFields($r2[Tj]);
|
|
assert Pointer($r2, Tj, $r2[Tj]);
|
|
assert CopyGcInv($freshAbs, BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, Tj + 4 * numFields($r2[Tj]), Tk, Tk, Tl, $Time, $r1, $r2, true, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
assert RExtend(old($r2), $r2);
|
|
assert ObjInvPartial(Tj, 0, esi, $r2, $r2, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
assert ObjInvPartial(Tj, esi, numFields($r2[Tj]), $r2, $r1, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
assert $toAbs[Tj] != NO_ABS && $toAbs[Tj] == $r2[Tj];
|
|
if (edi >= ebp) { goto loopEnd; }
|
|
if (esi >= 30) { goto loopEnd; }
|
|
|
|
assert TO(0) && TO(1);
|
|
assert TVT($r2[Tj], $vt);
|
|
assert TVL($r2[Tj]);
|
|
//assert getBit(mask($vt), 2 + esi) == VFieldPtr($r2[Tj], esi);
|
|
//if (getBit(mask, 2 + esi))
|
|
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[Tj], esi, $Time);
|
|
|
|
save1 := esi;
|
|
save2 := ebp;
|
|
save3 := edx;
|
|
call forwardFromspacePtr(ecx, $AbsMem[$toAbs[Tj]][esi], Tj + 4 * numFields($r2[Tj]));
|
|
esi := save1;
|
|
ebp := save2;
|
|
edx := save3;
|
|
edi := Tj;
|
|
call edi := Lea(edi + 4 * esi);
|
|
|
|
call GcStore(edi, eax);
|
|
skip2:
|
|
skip1:
|
|
|
|
call esi := Add(esi, 1);
|
|
call edi := Add(edi, 4);
|
|
goto loop;
|
|
loopEnd:
|
|
|
|
assert TVT($r2[Tj], $vt);
|
|
assert TVL($r2[Tj]);
|
|
Tj := ebp;
|
|
assert TO(1);
|
|
}
|
|
|
|
procedure scanObjectSparse($vt:int)
|
|
requires ecx == $vt;
|
|
requires CopyGcInv($freshAbs, BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, Tj, Tk, Tk, Tl, $Time, $r1, $r2, true, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
requires Tj < Tk;
|
|
requires TV(Tj);
|
|
requires $vt == $AbsMem[$r2[Tj]][1];
|
|
requires tag($vt) == ?SPARSE_TAG;
|
|
modifies $r2, $GcMem, $toAbs, Tj, Tk, $gcSlice;
|
|
modifies eax, ebx, ecx, edx, esi, edi, ebp, esp;
|
|
ensures CopyGcInv($freshAbs, BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, Tj, Tk, Tk, Tl, $Time, $r1, $r2, true, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
ensures RExtend(old($r2), $r2);
|
|
{
|
|
var save1:int;
|
|
var save2:int;
|
|
var save3:int;
|
|
var save4:int;
|
|
assert TO(numFields($r2[Tj]));
|
|
|
|
esi := 1;
|
|
|
|
assert TO(numFields($r2[Tj]));
|
|
assert TVT($toAbs[Tj], $vt);
|
|
call ebp := RoLoad32(ecx + ?VT_BASE_LENGTH);
|
|
call edx := RoLoad32(ecx + ?VT_MASK);
|
|
assert TVL($r2[Tj]);
|
|
|
|
esi := 1;
|
|
//while (esi < 8)
|
|
loop:
|
|
assert edx == mask($vt) && ebp == 4 * numFields($r2[Tj]);
|
|
assert TSlot(esi) && 0 < esi && esi <= 8;
|
|
assert Pointer($r2, Tj, $r2[Tj]);
|
|
assert CopyGcInv($freshAbs, BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, Tj + 4 * numFields($r2[Tj]), Tk, Tk, Tl, $Time, $r1, $r2, true, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
assert RExtend(old($r2), $r2);
|
|
assert ObjInvBase(Tj, $r2, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
assert (forall j:int::{TO(j)} TO(j) ==> 0 <= j && j < numFields($r2[Tj]) ==>
|
|
between(1, esi, fieldToSlot($vt, j - 2)) ==>
|
|
ObjInvField(Tj, j, $r2, $r2, $toAbs, $AbsMem, $GcMem, $gcSlice));
|
|
assert (forall j:int::{TO(j)} TO(j) ==> 0 <= j && j < numFields($r2[Tj]) ==>
|
|
!between(1, esi, fieldToSlot($vt, j - 2)) ==>
|
|
ObjInvField(Tj, j, $r2, $r1, $toAbs, $AbsMem, $GcMem, $gcSlice));
|
|
assert $toAbs[Tj] != NO_ABS && $toAbs[Tj] == $r2[Tj];
|
|
if (esi >= 8) { goto loopEnd; }
|
|
|
|
assert TO(0) && TO(1);
|
|
assert TVT($toAbs[Tj], $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 := Tj;
|
|
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[Tj], 1 + ebx, $Time);
|
|
|
|
save1 := esi;
|
|
save2 := ebp;
|
|
save3 := edx;
|
|
save4 := ebx;
|
|
call forwardFromspacePtr(ecx, $AbsMem[$toAbs[Tj]][1 + getNib(edx, 4 * esi)], Tj + ebp);
|
|
esi := save1;
|
|
ebp := save2;
|
|
edx := save3;
|
|
ebx := save4;
|
|
|
|
ecx := Tj;
|
|
call GcStore(ecx + 4 * ebx + 4, eax);
|
|
skip2:
|
|
skip1:
|
|
|
|
call esi := Add(esi, 1);
|
|
goto loop;
|
|
loopEnd:
|
|
|
|
assert TVT($toAbs[Tj], $vt);
|
|
assert TVL($r2[Tj]);
|
|
call Tj := Add(Tj, ebp);
|
|
assert TO(1);
|
|
}
|
|
|
|
procedure scanObjectOtherVectorNoPointers($vt:int)
|
|
requires ecx == $vt;
|
|
requires CopyGcInv($freshAbs, BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, Tj, Tk, Tk, Tl, $Time, $r1, $r2, true, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
requires Tj < Tk;
|
|
requires TV(Tj);
|
|
requires $vt == $AbsMem[$r2[Tj]][1];
|
|
requires tag($vt) == ?OTHER_VECTOR_TAG;
|
|
requires arrayOf($vt) != ?TYPE_STRUCT || (arrayOf($vt) == ?TYPE_STRUCT && mask(arrayElementClass($vt)) == ?SPARSE_TAG);
|
|
modifies $r2, $GcMem, $toAbs, Tj, Tk, $gcSlice;
|
|
modifies eax, ebx, ecx, edx, esi, edi, ebp, esp;
|
|
ensures CopyGcInv($freshAbs, BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, Tj, Tk, Tk, Tl, $Time, $r1, $r2, true, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
ensures RExtend(old($r2), $r2);
|
|
{
|
|
edx := ecx;
|
|
ecx := Tj;
|
|
esp := esp - 4; call GetSize(Tj, $vt, $r2, $r1);
|
|
|
|
assert TO(numFields($r2[Tj]));
|
|
assert TVT($r2[Tj], $vt);
|
|
call Tj := Add(Tj, eax);
|
|
}
|
|
|
|
procedure scanObjectOtherVectorPointersSparseFields($vt:int, $jj:int, $index:int)
|
|
requires edx == mask(arrayElementClass($vt));
|
|
requires edi == $jj;
|
|
requires Tj < Tk;
|
|
requires TV(Tj);
|
|
requires $vt == $AbsMem[$r2[Tj]][1];
|
|
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($r2[Tj]);
|
|
requires TO($index) && 0 <= $index; // && $index <= nElems;
|
|
requires Mult(arrayElementWords($vt), $index) >= 0;
|
|
requires reached($toAbs[Tj], $Time);
|
|
requires Pointer($r2, Tj, $r2[Tj]);
|
|
requires CopyGcInv($freshAbs, BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, Tj + 4 * numFields($r2[Tj]), Tk, Tk, Tl, $Time, $r1, $r2, true, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
requires ObjInvPartial(Tj, 0, $jj, $r2, $r2, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
requires ObjInvPartial(Tj, $jj, numFields($r2[Tj]), $r2, $r1, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
requires $toAbs[Tj] != NO_ABS && $toAbs[Tj] == $r2[Tj];
|
|
requires (forall j:int::{TO(j)} TO(j) ==>
|
|
between(0, arrayElementWords($vt), j - $jj) ==>
|
|
ObjInvField(Tj, j, $r2, $r1, $toAbs, $AbsMem, $GcMem, $gcSlice));
|
|
|
|
modifies $r2, $GcMem, $toAbs, Tk, $gcSlice;
|
|
modifies eax, ebx, ecx, edx, esi, edi, ebp, esp;
|
|
|
|
ensures Pointer($r2, Tj, $r2[Tj]);
|
|
ensures CopyGcInv($freshAbs, BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, Tj + 4 * numFields($r2[Tj]), Tk, Tk, Tl, $Time, $r1, $r2, true, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
ensures RExtend(old($r2), $r2);
|
|
ensures ObjInvPartial(Tj, 0, $jj, $r2, $r2, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
ensures ObjInvPartial(Tj, $jj + arrayElementWords($vt), numFields($r2[Tj]), $r2, $r1, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
ensures $toAbs[Tj] != NO_ABS && $toAbs[Tj] == $r2[Tj];
|
|
ensures (forall j:int::{TO(j)} TO(j) ==>
|
|
between(0, arrayElementWords($vt), j - $jj) ==>
|
|
between(1, 8, fieldToSlot(arrayElementClass($vt), j - $jj)) ==>
|
|
ObjInvField(Tj, 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(Tj, 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;
|
|
|
|
assert TO(numFields($r2[Tj]));
|
|
assert TO(2);
|
|
assert TVT($r2[Tj], $vt);
|
|
assert TVL($r2[Tj]);
|
|
|
|
esi := 1;
|
|
//while (esi < 8)
|
|
loop:
|
|
assert TSlot(esi) && 0 < esi && esi <= 8;
|
|
assert edx == mask(arrayElementClass($vt));
|
|
assert edi == $jj;
|
|
assert Pointer($r2, Tj, $r2[Tj]);
|
|
assert CopyGcInv($freshAbs, BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, Tj + 4 * numFields($r2[Tj]), Tk, Tk, Tl, $Time, $r1, $r2, true, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
assert RExtend(old($r2), $r2);
|
|
assert ObjInvPartial(Tj, 0, $jj, $r2, $r2, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
assert ObjInvPartial(Tj, $jj + arrayElementWords($vt), numFields($r2[Tj]), $r2, $r1, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
assert $toAbs[Tj] != NO_ABS && $toAbs[Tj] == $r2[Tj];
|
|
assert (forall j:int::{TO(j)} TO(j) ==>
|
|
between(0, arrayElementWords($vt), j - $jj) ==>
|
|
between(1, esi, fieldToSlot(arrayElementClass($vt), j - $jj)) ==>
|
|
ObjInvField(Tj, 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(Tj, 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 := Tj;
|
|
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[Tj], ebx, $Time);
|
|
|
|
assert TO(0);
|
|
assert TO(1);
|
|
|
|
save1 := esi;
|
|
save2 := edi;
|
|
save3 := edx;
|
|
save4 := ebx;
|
|
call forwardFromspacePtr(ecx, $AbsMem[$toAbs[Tj]][ebx], Tj + 4 * numFields($r2[Tj]));
|
|
esi := save1;
|
|
edi := save2;
|
|
edx := save3;
|
|
ebx := save4;
|
|
|
|
ecx := Tj;
|
|
call GcStore(ecx + 4 * ebx, eax);
|
|
|
|
skip2:
|
|
skip1:
|
|
call esi := Add(esi, 1);
|
|
goto loop;
|
|
loopEnd:
|
|
}
|
|
|
|
procedure scanObjectOtherVectorPointers($vt:int)
|
|
requires ecx == $vt;
|
|
requires CopyGcInv($freshAbs, BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, Tj, Tk, Tk, Tl, $Time, $r1, $r2, true, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
requires Tj < Tk;
|
|
requires TV(Tj);
|
|
requires $vt == $AbsMem[$r2[Tj]][1];
|
|
requires tag($vt) == ?OTHER_VECTOR_TAG;
|
|
requires arrayOf($vt) == ?TYPE_STRUCT && tag(arrayElementClass($vt)) == ?SPARSE_TAG;
|
|
modifies $r2, $GcMem, $toAbs, Tj, Tk, $gcSlice;
|
|
modifies eax, ebx, ecx, edx, esi, edi, ebp, esp;
|
|
ensures CopyGcInv($freshAbs, BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, Tj, Tk, Tk, Tl, $Time, $r1, $r2, true, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
ensures RExtend(old($r2), $r2);
|
|
{
|
|
var save1:int;
|
|
var save2:int;
|
|
|
|
var $index:int;
|
|
|
|
assert TO(numFields($r2[Tj]));
|
|
assert TO(2);
|
|
assert TVT($r2[Tj], $vt);
|
|
assert TVL($r2[Tj]);
|
|
|
|
$index := 0;
|
|
|
|
call edi := RoLoad32(ecx + ?VT_BASE_LENGTH);
|
|
call ebx := RoLoad32(ecx + ?VT_ARRAY_ELEMENT_SIZE);
|
|
edx := Tj;
|
|
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[Tj]);
|
|
assert edx == mask(arrayElementClass($vt));
|
|
assert ebx == arrayElementWords($vt);
|
|
assert 4 * edi <= ebp;
|
|
|
|
assert Pointer($r2, Tj, $r2[Tj]);
|
|
assert CopyGcInv($freshAbs, BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, Tj + 4 * numFields($r2[Tj]), Tk, Tk, Tl, $Time, $r1, $r2, true, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
assert RExtend(old($r2), $r2);
|
|
assert ObjInvPartial(Tj, 0, edi, $r2, $r2, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
assert ObjInvPartial(Tj, edi, numFields($r2[Tj]), $r2, $r1, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
assert $toAbs[Tj] != NO_ABS && $toAbs[Tj] == $r2[Tj];
|
|
eax := 0;
|
|
call eax := Lea(eax + 4 * edi);
|
|
if (eax >= ebp) { goto loopEnd; }
|
|
|
|
save1 := ebx;
|
|
save2 := ebp;
|
|
call scanObjectOtherVectorPointersSparseFields($vt, 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:
|
|
|
|
call Tj := Add(Tj, ebp);
|
|
assert TO(1);
|
|
}
|
|
|
|
procedure scanObjectPtrArray($vt:int)
|
|
requires ecx == $vt;
|
|
requires CopyGcInv($freshAbs, BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, Tj, Tk, Tk, Tl, $Time, $r1, $r2, true, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
requires Tj < Tk;
|
|
requires TV(Tj);
|
|
requires $vt == $AbsMem[$r2[Tj]][1];
|
|
requires tag($vt) == ?PTR_ARRAY_TAG;
|
|
modifies $r2, $GcMem, $toAbs, Tj, Tk, $gcSlice;
|
|
modifies eax, ebx, ecx, edx, esi, edi, ebp, esp;
|
|
ensures CopyGcInv($freshAbs, BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, Tj, Tk, Tk, Tl, $Time, $r1, $r2, true, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
ensures RExtend(old($r2), $r2);
|
|
{
|
|
var $ind:int;
|
|
var save1:int;
|
|
var save2:int;
|
|
|
|
assert TO(numFields($r2[Tj]));
|
|
assert TO(3);
|
|
assert TVT($r2[Tj], $vt);
|
|
assert TVL($r2[Tj]);
|
|
|
|
ebx := Tj;
|
|
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 == Tj + 4 * $ind;
|
|
assert ebp == Tj + 4 * numFields($r2[Tj]);
|
|
assert TO($ind) && baseWords($vt) <= $ind; // && $ind <= nElems + 3;
|
|
assert Pointer($r2, Tj, $r2[Tj]);
|
|
assert CopyGcInv($freshAbs, BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, Tj + 4 * numFields($r2[Tj]), Tk, Tk, Tl, $Time, $r1, $r2, true, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
assert RExtend(old($r2), $r2);
|
|
assert ObjInvPartial(Tj, 0, $ind, $r2, $r2, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
assert ObjInvPartial(Tj, $ind, numFields($r2[Tj]), $r2, $r1, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
assert $toAbs[Tj] != NO_ABS && $toAbs[Tj] == $r2[Tj];
|
|
if (edi >= ebp) { goto loopEnd; }
|
|
|
|
assert TO(0) && TO(1) && TO(3);
|
|
assert TVT($r2[Tj], $vt);
|
|
assert TVL($r2[Tj]);
|
|
call ecx := GcLoad(edi);
|
|
//if (gcAddrEx(ecx))
|
|
if (ecx < ?gcLo) { goto skip1; }
|
|
if (ecx > ?gcHi) { goto skip1; }
|
|
assert TV(ecx - 4);
|
|
call reach($toAbs[Tj], $ind, $Time);
|
|
|
|
save1 := edi;
|
|
save2 := ebp;
|
|
call forwardFromspacePtr(ecx, $AbsMem[$toAbs[Tj]][$ind], ebp);
|
|
edi := save1;
|
|
ebp := save2;
|
|
|
|
call GcStore(edi, eax);
|
|
skip1:
|
|
|
|
$ind := $ind + 1;
|
|
call edi := Add(edi, 4);
|
|
goto loop;
|
|
loopEnd:
|
|
|
|
Tj := ebp;
|
|
}
|
|
|
|
procedure scanObjectPtrVector($vt:int)
|
|
requires ecx == $vt;
|
|
requires CopyGcInv($freshAbs, BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, Tj, Tk, Tk, Tl, $Time, $r1, $r2, true, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
requires Tj < Tk;
|
|
requires TV(Tj);
|
|
requires $vt == $AbsMem[$r2[Tj]][1];
|
|
requires tag($vt) == ?PTR_VECTOR_TAG;
|
|
modifies $r2, $GcMem, $toAbs, Tj, Tk, $gcSlice;
|
|
modifies eax, ebx, ecx, edx, esi, edi, ebp, esp;
|
|
ensures CopyGcInv($freshAbs, BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, Tj, Tk, Tk, Tl, $Time, $r1, $r2, true, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
ensures RExtend(old($r2), $r2);
|
|
{
|
|
var $ind:int;
|
|
var save1:int;
|
|
var save2:int;
|
|
assert TO(numFields($r2[Tj]));
|
|
assert TO(2);
|
|
assert TVT($r2[Tj], $vt);
|
|
assert TVL($r2[Tj]);
|
|
|
|
ebx := Tj;
|
|
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 == Tj + 4 * $ind;
|
|
assert ebp == Tj + 4 * numFields($r2[Tj]);
|
|
assert TO($ind) && baseWords($vt) <= $ind; // && $ind <= nElems + 3;
|
|
assert Pointer($r2, Tj, $r2[Tj]);
|
|
assert CopyGcInv($freshAbs, BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, Tj + 4 * numFields($r2[Tj]), Tk, Tk, Tl, $Time, $r1, $r2, true, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
assert RExtend(old($r2), $r2);
|
|
assert ObjInvPartial(Tj, 0, $ind, $r2, $r2, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
assert ObjInvPartial(Tj, $ind, numFields($r2[Tj]), $r2, $r1, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
assert $toAbs[Tj] != NO_ABS && $toAbs[Tj] == $r2[Tj];
|
|
if (edi >= ebp) { goto loopEnd; }
|
|
|
|
assert TO(0) && TO(1) && TO(2);
|
|
assert TVT($r2[Tj], $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[Tj], $ind, $Time);
|
|
|
|
save1 := edi;
|
|
save2 := ebp;
|
|
call forwardFromspacePtr(ecx, $AbsMem[$toAbs[Tj]][$ind], ebp);
|
|
edi := save1;
|
|
ebp := save2;
|
|
|
|
call GcStore(edi, eax);
|
|
skip1:
|
|
|
|
$ind := $ind + 1;
|
|
call edi := Add(edi, 4);
|
|
goto loop;
|
|
loopEnd:
|
|
|
|
Tj := ebp;
|
|
}
|
|
|
|
procedure scanObjectOtherArrayNoPointers($vt:int)
|
|
requires ecx == $vt;
|
|
requires CopyGcInv($freshAbs, BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, Tj, Tk, Tk, Tl, $Time, $r1, $r2, true, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
requires Tj < Tk;
|
|
requires TV(Tj);
|
|
requires $vt == $AbsMem[$r2[Tj]][1];
|
|
requires tag($vt) == ?OTHER_ARRAY_TAG;
|
|
requires arrayOf($vt) != ?TYPE_STRUCT;
|
|
modifies $r2, $GcMem, $toAbs, Tj, Tk, $gcSlice;
|
|
modifies eax, ebx, ecx, edx, esi, edi, ebp, esp;
|
|
ensures CopyGcInv($freshAbs, BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, Tj, Tk, Tk, Tl, $Time, $r1, $r2, true, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
ensures RExtend(old($r2), $r2);
|
|
{
|
|
edx := ecx;
|
|
ecx := Tj;
|
|
esp := esp - 4; call GetSize(Tj, $vt, $r2, $r1);
|
|
|
|
assert TO(numFields($r2[Tj]));
|
|
assert TVT($r2[Tj], $vt);
|
|
call Tj := Add(Tj, eax);
|
|
}
|
|
|
|
procedure scanObjectString($vt:int)
|
|
requires ecx == $vt;
|
|
requires CopyGcInv($freshAbs, BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, Tj, Tk, Tk, Tl, $Time, $r1, $r2, true, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
requires Tj < Tk;
|
|
requires TV(Tj);
|
|
requires $vt == $AbsMem[$r2[Tj]][1];
|
|
requires tag($vt) == ?STRING_TAG;
|
|
modifies $r2, $GcMem, $toAbs, Tj, Tk, $gcSlice;
|
|
modifies eax, ebx, ecx, edx, esi, edi, ebp, esp;
|
|
ensures CopyGcInv($freshAbs, BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, Tj, Tk, Tk, Tl, $Time, $r1, $r2, true, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
ensures RExtend(old($r2), $r2);
|
|
{
|
|
edx := ecx;
|
|
ecx := Tj;
|
|
esp := esp - 4; call GetSize(Tj, $vt, $r2, $r1);
|
|
|
|
assert TO(numFields($r2[Tj]));
|
|
assert TVT($r2[Tj], $vt);
|
|
call Tj := Add(Tj, eax);
|
|
}
|
|
|
|
procedure scanObjectOther($vt:int)
|
|
requires ecx == $vt;
|
|
requires CopyGcInv($freshAbs, BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, Tj, Tk, Tk, Tl, $Time, $r1, $r2, true, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
requires Tj < Tk;
|
|
requires TV(Tj);
|
|
requires $vt == $AbsMem[$r2[Tj]][1];
|
|
requires isOtherTag(tag($vt));
|
|
modifies $r2, $GcMem, $toAbs, Tj, Tk, $gcSlice;
|
|
modifies eax, ebx, ecx, edx, esi, edi, ebp, esp;
|
|
ensures CopyGcInv($freshAbs, BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, Tj, Tk, Tk, Tl, $Time, $r1, $r2, true, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
ensures RExtend(old($r2), $r2);
|
|
{
|
|
var save1:int;
|
|
var save2:int;
|
|
var save3:int;
|
|
var save4:int;
|
|
var save5:int;
|
|
|
|
assert TO(numFields($r2[Tj]));
|
|
assert TVT($toAbs[Tj], $vt);
|
|
assert TVL($r2[Tj]);
|
|
|
|
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($r2[Tj]);
|
|
assert edx == mask($vt);
|
|
assert edi == ro32(mask($vt));
|
|
assert TSlot(esi) && 0 < esi && esi <= ro32(mask($vt)) + 1;
|
|
assert Pointer($r2, Tj, $r2[Tj]);
|
|
assert CopyGcInv($freshAbs, BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, Tj + 4 * numFields($r2[Tj]), Tk, Tk, Tl, $Time, $r1, $r2, true, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
assert RExtend(old($r2), $r2);
|
|
assert ObjInvBase(Tj, $r2, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
assert (forall j:int::{TO(j)} TO(j) ==> 0 <= j && j < numFields($r2[Tj]) ==>
|
|
between(1, esi, fieldToSlot($vt, j)) ==>
|
|
ObjInvField(Tj, j, $r2, $r2, $toAbs, $AbsMem, $GcMem, $gcSlice));
|
|
assert (forall j:int::{TO(j)} TO(j) ==> 0 <= j && j < numFields($r2[Tj]) ==>
|
|
!between(1, esi, fieldToSlot($vt, j)) ==>
|
|
ObjInvField(Tj, j, $r2, $r1, $toAbs, $AbsMem, $GcMem, $gcSlice));
|
|
assert $toAbs[Tj] != NO_ABS && $toAbs[Tj] == $r2[Tj];
|
|
if (esi > edi) { goto loopEnd; }
|
|
|
|
assert TO(0) && TO(1);
|
|
assert TVT($toAbs[Tj], $vt);
|
|
assert TVL($r2[Tj]);
|
|
assert TO(ro32(mask($vt) + 4 * esi) + 1);
|
|
call ebx := RoLoad32(edx + 4 * esi);
|
|
//if (ebx != 0)
|
|
if (ebx == 0) { goto skip1; }
|
|
eax := Tj;
|
|
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[Tj], 1 + ro32(edx + 4 * esi), $Time);
|
|
|
|
save1 := ebx;
|
|
save2 := esi;
|
|
save3 := edi;
|
|
save4 := ebp;
|
|
save5 := edx;
|
|
call forwardFromspacePtr(ecx, $AbsMem[$toAbs[Tj]][1 + ro32(edx + 4 * esi)], Tj + ebp);
|
|
ebx := save1;
|
|
esi := save2;
|
|
edi := save3;
|
|
ebp := save4;
|
|
edx := save5;
|
|
|
|
ecx := Tj;
|
|
call GcStore(ecx + 4 * ebx + 4, eax);
|
|
skip2:
|
|
skip1:
|
|
call esi := AddChecked(esi, 1);
|
|
goto loop;
|
|
loopEnd:
|
|
|
|
assert TVT($toAbs[Tj], $vt);
|
|
assert TVL($r2[Tj]);
|
|
call Tj := Add(Tj, ebp);
|
|
}
|
|
|
|
procedure scanObject()
|
|
requires CopyGcInv($freshAbs, BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, Tj, Tk, Tk, Tl, $Time, $r1, $r2, true, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
requires Tj < Tk;
|
|
requires TV(Tj);
|
|
modifies $r2, $GcMem, $toAbs, Tj, Tk, $gcSlice;
|
|
modifies eax, ebx, ecx, edx, esi, edi, ebp, esp;
|
|
ensures CopyGcInv($freshAbs, BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, Tj, Tk, Tk, Tl, $Time, $r1, $r2, true, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
ensures RExtend(old($r2), $r2);
|
|
{
|
|
var $vt:int;
|
|
|
|
assert TO(1);
|
|
ecx := Tj;
|
|
call ecx := GcLoad(ecx + 4);
|
|
$vt := ecx;
|
|
|
|
assert TO(numFields($r2[Tj]));
|
|
|
|
call readTag($toAbs[Tj], $vt);
|
|
|
|
if (eax != ?SPARSE_TAG) { goto skip1; }
|
|
call scanObjectSparse($vt);
|
|
goto end;
|
|
skip1:
|
|
|
|
if (eax != ?DENSE_TAG) { goto skip2; }
|
|
call scanObjectDense($vt);
|
|
goto end;
|
|
skip2:
|
|
|
|
if (eax != ?STRING_TAG) { goto skip3; }
|
|
call scanObjectString($vt);
|
|
goto end;
|
|
skip3:
|
|
|
|
if (eax != ?PTR_VECTOR_TAG) { goto skip4; }
|
|
call scanObjectPtrVector($vt);
|
|
goto end;
|
|
skip4:
|
|
|
|
if (eax != ?OTHER_VECTOR_TAG) { goto skip5; }
|
|
call readArrayOf($r2[Tj], $vt);
|
|
call readElementInfo($r2[Tj], $vt);
|
|
if (ebp != ?TYPE_STRUCT) { goto noPoint; }
|
|
if (ebp != ?TYPE_STRUCT) { goto vecSkip1; }
|
|
if (edi != ?SPARSE_TAG) { goto vecSkip1; }
|
|
noPoint:
|
|
call scanObjectOtherVectorNoPointers($vt);
|
|
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);
|
|
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);
|
|
goto end;
|
|
skip6:
|
|
|
|
if (eax != ?OTHER_ARRAY_TAG) { goto skip7; }
|
|
call readArrayOf($r2[Tj], $vt);
|
|
if (ebp == ?TYPE_STRUCT) { goto arraySkip1; }
|
|
call scanObjectOtherArrayNoPointers($vt);
|
|
goto end;
|
|
arraySkip1:
|
|
call DebugBreak();
|
|
goto end;
|
|
skip7:
|
|
|
|
call scanObjectOther($vt);
|
|
|
|
end:
|
|
}
|
|
|
|
procedure scanObjects()
|
|
requires CopyGcInv($freshAbs, BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, Tj, Tk, Tk, Tl, $Time, $r1, $r2, true, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
modifies $r2, $GcMem, $toAbs, Tj, Tk, $gcSlice;
|
|
modifies eax, ebx, ecx, edx, esi, edi, ebp, esp;
|
|
ensures CopyGcInv($freshAbs, BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, Tj, Tk, Tk, Tl, $Time, $r1, $r2, true, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
ensures RExtend(old($r2), $r2);
|
|
ensures Tj == Tk;
|
|
{
|
|
entry:
|
|
loop:
|
|
assert CopyGcInv($freshAbs, BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, Tj, Tk, Tk, Tl, $Time, $r1, $r2, true, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
assert RExtend(old($r2), $r2);
|
|
eax := Tk;
|
|
if (Tj >= eax) { goto exit; }
|
|
call scanObject();
|
|
goto loop;
|
|
exit:
|
|
}
|
|
|
|
procedure FromInteriorPointer($iptr:int, $offset:int, $abs:int)
|
|
requires ecx == $iptr;
|
|
requires CopyGcInv($freshAbs, BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, Tj, Tk, Tk, Tl, $Time, $r1, $r2, true, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
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, Fi);
|
|
edx := ebx;
|
|
call edx := And(edx, 3);
|
|
call __andAligned(ebx);
|
|
call __addAligned(Fi, ebx);
|
|
if (edx != 0)
|
|
{
|
|
goto skip1;
|
|
}
|
|
|
|
save1 := eax;
|
|
save2 := ecx;
|
|
eax := BF;
|
|
call bb4GetBit($r1, NO_ABS, Fi, Fi, Fi, Fl, $iptr - save1 - 4, ?gcLo + BitIndex(HeapLo, Fi), ?gcLo + BitIndex(HeapLo, Fl));
|
|
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 scanStackWordDenseCopy($frame:int, $addr:int, $desc:int, $addrp:int, $p:int, $args:int)
|
|
requires ecx == $addrp;
|
|
requires CopyGcInv($freshAbs, BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, Tj, Tk, Tk, Tl, $Time, $r1, $r2, true, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
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, $GcMem, $toAbs, Tk, $gcSlice, $FrameMem;
|
|
modifies eax, ebx, ecx, edx, esi, edi, ebp, esp;
|
|
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 CopyGcInv($freshAbs, BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, Tj, Tk, Tk, Tl, $Time, $r1, $r2, true, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
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 forwardFromspacePtr(ecx, $FrameAbs[$frame][$p], Tj);
|
|
|
|
assert TV(eax - 4);
|
|
call eax := Add(eax, offset);
|
|
call scanStackUpdateInvs($r1, 0, $frame, $frame, $addrp, eax);
|
|
call scanStackUpdateInvs($r2, $frame + 1, $FrameCount, $frame, $addrp, eax);
|
|
|
|
ecx := save1;
|
|
call FrameStore(($frame), ecx, eax);
|
|
skip1:
|
|
}
|
|
|
|
procedure scanStackDenseCopy($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 CopyGcInv($freshAbs, BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, Tj, Tk, Tk, Tl, $Time, $r1, $r2, true, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
modifies $r2, $GcMem, $toAbs, Tk, $gcSlice, $FrameMem;
|
|
modifies eax, ebx, ecx, edx, esi, edi, ebp, esp;
|
|
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 CopyGcInv($freshAbs, BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, Tj, Tk, Tk, Tl, $Time, $r1, $r2, true, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
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 CopyGcInv($freshAbs, BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, Tj, Tk, Tk, Tl, $Time, $r1, $r2, true, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
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 scanStackWordDenseCopy($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 CopyGcInv($freshAbs, BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, Tj, Tk, Tk, Tl, $Time, $r1, $r2, true, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
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 scanStackWordDenseCopy($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 scanStackSparse8Copy($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 CopyGcInv($freshAbs, BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, Tj, Tk, Tk, Tl, $Time, $r1, $r2, true, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
modifies $r2, $GcMem, $toAbs, Tk, $gcSlice, $FrameMem;
|
|
modifies eax, ebx, ecx, edx, esi, edi, ebp, esp;
|
|
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 CopyGcInv($freshAbs, BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, Tj, Tk, Tk, Tl, $Time, $r1, $r2, true, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
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 CopyGcInv($freshAbs, BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, Tj, Tk, Tk, Tl, $Time, $r1, $r2, true, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
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 forwardFromspacePtr(ecx, $FrameAbs[$frame][roS8(desc + 6 + p)], Tj);
|
|
assert TV(eax - 4);
|
|
call eax := Add(eax, offset);
|
|
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;
|
|
call FrameStore(($frame), ebx, eax);
|
|
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 scanStackCopy($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 CopyGcInv($freshAbs, BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, Tj, Tk, Tk, Tl, $Time, $r1, $r2, true, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
modifies $r2, $GcMem, $toAbs, Tk, $gcSlice, $FrameMem;
|
|
modifies eax, ebx, ecx, edx, esi, edi, ebp, esp;
|
|
ensures StackInv($r2, $FrameCount, $FrameAddr, $FrameLayout, $FrameSlice, $FrameMem, $FrameAbs, $FrameOffset, $Time);
|
|
ensures CopyGcInv($freshAbs, BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, Tj, Tk, Tk, Tl, $Time, $r1, $r2, true, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
ensures RExtend(old($r2), $r2);
|
|
{
|
|
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 CopyGcInv($freshAbs, BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, Tj, Tk, Tk, Tl, $Time, $r1, $r2, true, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
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 scanStackDenseCopy($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 scanStackSparse8Copy($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 scanStaticSectionCopy($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));
|
|
requires CopyGcInv($freshAbs, BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, Tj, Tk, Tk, Tl, $Time, $r1, $r2, true, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
modifies $r2, $GcMem, $toAbs, Tk, $gcSlice, $SectionMem;
|
|
modifies eax, ebx, ecx, edx, esi, edi, ebp, esp;
|
|
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));
|
|
ensures CopyGcInv($freshAbs, BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, Tj, Tk, Tk, Tl, $Time, $r1, $r2, true, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
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 CopyGcInv($freshAbs, BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, Tj, Tk, Tk, Tl, $Time, $r1, $r2, true, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
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 forwardFromspacePtr(ecx, $SectionAbs[section][esi], Tj);
|
|
edi := save1;
|
|
esi := save2;
|
|
edx := save3;
|
|
|
|
call SectionStore(edi, eax);
|
|
skip2:
|
|
skip1:
|
|
|
|
call esi := Add(esi, 1);
|
|
call edi := AddChecked(edi, 4);
|
|
goto loop;
|
|
loopEnd:
|
|
}
|
|
|
|
procedure scanStaticCopy()
|
|
requires StaticInv($r1, $SectionMem, $SectionAbs, $Time);
|
|
requires CopyGcInv($freshAbs, BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, Tj, Tk, Tk, Tl, $Time, $r1, $r2, true, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
modifies $r2, $GcMem, $toAbs, Tk, $gcSlice, $SectionMem;
|
|
modifies eax, ebx, ecx, edx, esi, edi, ebp, esp;
|
|
ensures StaticInv($r2, $SectionMem, $SectionAbs, $Time);
|
|
ensures CopyGcInv($freshAbs, BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, Tj, Tk, Tk, Tl, $Time, $r1, $r2, true, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
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 CopyGcInv($freshAbs, BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, Tj, Tk, Tk, Tl, $Time, $r1, $r2, true, $toAbs, $AbsMem, $GcMem, $gcSlice);
|
|
assert RExtend(old($r2), $r2);
|
|
ecx := section;
|
|
if (ecx >= ?sectionCount) { goto loopEnd; }
|
|
|
|
call scanStaticSectionCopy(section);
|
|
call section := AddChecked(section, 1);
|
|
goto loop;
|
|
loopEnd:
|
|
}
|
|
|
|
procedure GarbageCollectCopying($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(BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, Tk, Tl, $GcMem, $toAbs, $AbsMem, $gcSlice);
|
|
requires $freshAbs != NO_ABS;
|
|
requires (forall i:int::{TV(i)} TV(i) ==> gcAddr(i) ==> $toAbs[i] != $freshAbs);
|
|
|
|
modifies $r1, $r2, $GcMem, $toAbs, $gcSlice, $SectionMem, $FrameMem;
|
|
modifies Ti, Tj, Tk, Tl, Fi, Fk, Fl, BF, BT;
|
|
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(BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, Tk, Tl, $GcMem, $toAbs, $AbsMem, $gcSlice);
|
|
ensures (forall i:int::{TV(i)} TV(i) ==> gcAddr(i) ==> $toAbs[i] != $freshAbs);
|
|
ensures (forall i:int::{TV(i)} TV(i) ==> Fi <= i && i < Fk && $toAbs[i] != NO_ABS ==>
|
|
reached($toAbs[i], $Time));
|
|
ensures ebp == old(ebp);
|
|
{
|
|
var saveEbp:int;
|
|
saveEbp := ebp;
|
|
|
|
$r1 := $toAbs;
|
|
$r2 := MAP_NO_ABS;
|
|
eax := Ti;
|
|
Tj := eax;
|
|
Tk := eax;
|
|
|
|
eax := BT;
|
|
ebx := Fi;
|
|
if (ebx != HeapLo) { goto skip1; }
|
|
ebx := HeapLo;
|
|
assert ?gcLo + BitIndex(HeapLo, Tl) == ebx;
|
|
goto skip2;
|
|
skip1:
|
|
ebx := BF;
|
|
assert ?gcLo + BitIndex(HeapLo, Tl) == ebx;
|
|
skip2:
|
|
assert TVM(32, (BitIndex(HeapLo, Fl) - BitIndex(HeapLo, Fi)));
|
|
assert TVM(32, (BitIndex(HeapLo, Tl) - BitIndex(HeapLo, Ti)));
|
|
|
|
esp := esp - 4; call BB4Zero($toAbs, 0, NO_ABS, Ti, Ti, Ti, Tl, 0, ?gcLo + BitIndex(HeapLo, Ti), ?gcLo + BitIndex(HeapLo, Tl), Fi, ?gcLo + BitIndex(HeapLo, Fi));
|
|
|
|
call scanStackCopy($ra, $nextFp);
|
|
call scanStaticCopy();
|
|
call scanObjects();
|
|
|
|
$toAbs := $r2;
|
|
|
|
eax := Fi;
|
|
ebx := Ti;
|
|
Fi := ebx;
|
|
Ti := eax;
|
|
|
|
eax := Fl;
|
|
ebx := Tl;
|
|
Fl := ebx;
|
|
Tl := eax;
|
|
|
|
eax := Tk;
|
|
Fk := eax;
|
|
|
|
eax := Ti;
|
|
Tk := eax;
|
|
Tj := eax;
|
|
|
|
eax := BF;
|
|
ebx := BT;
|
|
BF := ebx;
|
|
BT := eax;
|
|
|
|
ebp := saveEbp;
|
|
esp := esp + 4; return;
|
|
}
|
|
|
|
procedure doAllocCopyingWord($ret:int, $ind:int)
|
|
requires esi == $ret + 4 * $ind;
|
|
|
|
requires TO($ind) && $ind >= 0;
|
|
requires Aligned($ret) && Fk <= $ret && $ret + 4 * $ind + 4 <= Fl;
|
|
requires MutatorInv(BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, Tk, Tl, $GcMem, $toAbs, $AbsMem, $gcSlice);
|
|
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);
|
|
|
|
modifies $GcMem, $gcSlice;
|
|
|
|
ensures MutatorInv(BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, Tk, Tl, $GcMem, $toAbs, $AbsMem, $gcSlice);
|
|
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 doAllocCopyingWords($ret:int, $size:int, $nf:int)
|
|
requires eax == $ret;
|
|
requires ebx == $ret + $size;
|
|
requires $size == $nf * 4;
|
|
requires $nf >= 0;
|
|
requires MutatorInv(BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, Tk, Tl, $GcMem, $toAbs, $AbsMem, $gcSlice);
|
|
requires Aligned($ret) && Fk <= $ret && $ret + $size <= Fl;
|
|
|
|
modifies $GcMem, $gcSlice;
|
|
modifies esi;
|
|
|
|
ensures MutatorInv(BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, Tk, Tl, $GcMem, $toAbs, $AbsMem, $gcSlice);
|
|
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 MutatorInv(BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, Tk, Tl, $GcMem, $toAbs, $AbsMem, $gcSlice);
|
|
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 doAllocCopyingWord($ret, $ind);
|
|
$ind := $ind + 1;
|
|
call esi := Add(esi, 4);
|
|
if (esi < ebx) { goto loop; }
|
|
loopEnd:
|
|
}
|
|
|
|
procedure doAllocObjectCopying($ra:int, $nextFp:int, $abs:int, $vt:int, $size:int)
|
|
requires eax == $size;
|
|
requires ebx == Fk + $size;
|
|
requires ecx == $vt;
|
|
requires Fk + 4 * numFields($abs) <= Fl;
|
|
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(BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, Tk, Tl, $GcMem, $toAbs, $AbsMem, $gcSlice);
|
|
|
|
// 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, Fk;
|
|
modifies eax, ebx, ecx, edx, esi, edi, ebp, esp;
|
|
|
|
ensures MutatorInv(BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, Tk, Tl, $GcMem, $toAbs, $AbsMem, $gcSlice);
|
|
ensures old($toAbs)[eax - 4] == NO_ABS;
|
|
ensures $toAbs == old($toAbs)[eax - 4 := $abs];
|
|
ensures Pointer($toAbs, eax - 4, $abs);
|
|
ensures ebp == old(ebp);
|
|
{
|
|
eax := Fk;
|
|
|
|
assert TV(eax + 0) && TV(eax + 4);
|
|
assert TO(1) && TO(2);
|
|
assert TO(numFields($abs));
|
|
|
|
call doAllocCopyingWords(eax, $size, numFields($abs));
|
|
|
|
call GcStore(eax + 4, ecx);
|
|
|
|
esi := eax;
|
|
call esi := Sub(esi, Fi);
|
|
edi := BF;
|
|
call bb4SetBit($toAbs, $abs, NO_ABS, Fi, Fi, Fi, Fl, Fk, ?gcLo + BitIndex(HeapLo, Fi), ?gcLo + BitIndex(HeapLo, Fl));
|
|
assert TV(Fk - Fi);
|
|
|
|
$toAbs[eax] := $abs;
|
|
assert TV(Fk);
|
|
assert TO(numFields($abs));
|
|
|
|
Fk := ebx;
|
|
call eax := Add(eax, 4);
|
|
|
|
assert TV(eax + 4);
|
|
assert TO(0);
|
|
}
|
|
|
|
procedure doAllocStringCopying($ra:int, $nextFp:int, $abs:int, $vt:int, $nElems:int)
|
|
requires ecx == pad(16 + 2 * $nElems);
|
|
requires ebx == Fk + pad(16 + 2 * $nElems);
|
|
requires edx == $nElems;
|
|
requires $vt == ?STRING_VTABLE;
|
|
requires Fk + pad(16 + 2 * $nElems) + 0 <= Fl;
|
|
requires MutatorInv(BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, Tk, Tl, $GcMem, $toAbs, $AbsMem, $gcSlice);
|
|
|
|
// 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, Fk;
|
|
modifies eax, ebx, ecx, edx, esi, edi, ebp, esp;
|
|
|
|
ensures MutatorInv(BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, Tk, Tl, $GcMem, $toAbs, $AbsMem, $gcSlice);
|
|
ensures old($toAbs)[eax - 4] == NO_ABS;
|
|
ensures $toAbs == old($toAbs)[eax - 4 := $abs];
|
|
ensures Pointer($toAbs, eax - 4, $abs);
|
|
ensures ebp == old(ebp);
|
|
{
|
|
eax := Fk;
|
|
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 doAllocCopyingWords(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);
|
|
|
|
esi := eax;
|
|
call esi := Sub(esi, Fi);
|
|
edi := BF;
|
|
call bb4SetBit($toAbs, $abs, NO_ABS, Fi, Fi, Fi, Fl, Fk, ?gcLo + BitIndex(HeapLo, Fi), ?gcLo + BitIndex(HeapLo, Fl));
|
|
assert TV(Fk - Fi);
|
|
|
|
$toAbs[eax] := $abs;
|
|
assert TV(Fk);
|
|
assert TO(numFields($abs));
|
|
|
|
Fk := ebx;
|
|
call eax := Add(eax, 4);
|
|
|
|
assert TV(eax + 4);
|
|
assert TO(0);
|
|
}
|
|
|
|
procedure fromArrayInfo($abs:int, $vt:int)
|
|
requires VTable($abs, $vt);
|
|
requires tag($vt) == ?PTR_ARRAY_TAG || tag($vt) == ?OTHER_ARRAY_TAG;
|
|
ensures !VFieldPtr($abs, 0);
|
|
ensures !VFieldPtr($abs, 1);
|
|
ensures !VFieldPtr($abs, 2);
|
|
ensures !VFieldPtr($abs, 3);
|
|
{
|
|
assert TO(0) && TO(1) && TO(2) && TO(3) && TO(4);
|
|
assert TVL($abs);
|
|
assert TVT($abs, $vt);
|
|
}
|
|
|
|
procedure doAllocArrayCopyingHelper($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 doAllocArrayCopying($ra:int, $nextFp:int, $abs:int, $vt:int, $rank:int, $nElems:int, $size:int)
|
|
// requires eax == $size;
|
|
requires ebx == Fk + $size;
|
|
requires ecx == $vt;
|
|
requires edx == $rank;
|
|
requires esi == $nElems;
|
|
requires Fk + 4 * numFields($abs) <= Fl;
|
|
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(BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, Tk, Tl, $GcMem, $toAbs, $AbsMem, $gcSlice);
|
|
|
|
// 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, Fk;
|
|
modifies eax, ebx, ecx, edx, esi, edi, ebp, esp;
|
|
|
|
ensures MutatorInv(BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, Tk, Tl, $GcMem, $toAbs, $AbsMem, $gcSlice);
|
|
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;
|
|
eax := Fk;
|
|
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 doAllocCopyingWords(eax, $size, numFields($abs));
|
|
|
|
esi := nElems;
|
|
call GcStore(eax + 4, ecx);
|
|
call GcStore(eax + 8, edx);
|
|
call GcStore(eax + 12, esi);
|
|
|
|
esi := eax;
|
|
call esi := Sub(esi, Fi);
|
|
edi := BF;
|
|
call bb4SetBit($toAbs, $abs, NO_ABS, Fi, Fi, Fi, Fl, Fk, ?gcLo + BitIndex(HeapLo, Fi), ?gcLo + BitIndex(HeapLo, Fl));
|
|
assert TV(Fk - Fi);
|
|
|
|
$toAbs[eax] := $abs;
|
|
assert TV(Fk);
|
|
assert TO(numFields($abs));
|
|
|
|
Fk := ebx;
|
|
call eax := Add(eax, 4);
|
|
|
|
assert TV(eax + 4);
|
|
assert TO(0);
|
|
}
|
|
|
|
procedure doAllocVectorCopyingHelper($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 doAllocVectorCopying($ra:int, $nextFp:int, $abs:int, $vt:int, $nElems:int, $size:int)
|
|
// requires eax == $size;
|
|
requires ebx == Fk + $size;
|
|
requires ecx == $vt;
|
|
requires edx == $nElems;
|
|
requires Fk + 4 * numFields($abs) <= Fl;
|
|
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(BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, Tk, Tl, $GcMem, $toAbs, $AbsMem, $gcSlice);
|
|
|
|
// 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, Fk;
|
|
modifies eax, ebx, ecx, edx, esi, edi, ebp, esp;
|
|
|
|
ensures MutatorInv(BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, Tk, Tl, $GcMem, $toAbs, $AbsMem, $gcSlice);
|
|
ensures old($toAbs)[eax - 4] == NO_ABS;
|
|
ensures $toAbs == old($toAbs)[eax - 4 := $abs];
|
|
ensures Pointer($toAbs, eax - 4, $abs);
|
|
ensures ebp == old(ebp);
|
|
{
|
|
eax := Fk;
|
|
|
|
assert TV(eax + 0) && TV(eax + 4) && TV(eax + 8);
|
|
assert TO(1) && TO(2) && TO(3);
|
|
assert TO(numFields($abs));
|
|
|
|
call doAllocCopyingWords(eax, $size, numFields($abs));
|
|
|
|
call GcStore(eax + 4, ecx);
|
|
call GcStore(eax + 8, edx);
|
|
|
|
esi := eax;
|
|
call esi := Sub(esi, Fi);
|
|
edi := BF;
|
|
call bb4SetBit($toAbs, $abs, NO_ABS, Fi, Fi, Fi, Fl, Fk, ?gcLo + BitIndex(HeapLo, Fi), ?gcLo + BitIndex(HeapLo, Fl));
|
|
assert TV(Fk - Fi);
|
|
|
|
$toAbs[eax] := $abs;
|
|
assert TV(Fk);
|
|
assert TO(numFields($abs));
|
|
|
|
Fk := ebx;
|
|
call eax := Add(eax, 4);
|
|
|
|
assert TV(eax + 4);
|
|
assert TO(0);
|
|
}
|
|
|
|
procedure doAllocObjectCopyingHelper($abs:int, $vt:int)
|
|
requires ecx == $vt;
|
|
requires VTable($abs, $vt);
|
|
requires ObjSize($abs, $vt, 0, 0);
|
|
requires !isVarSize(tag($vt));
|
|
modifies eax;
|
|
ensures !VFieldPtr($abs, 0);
|
|
ensures !VFieldPtr($abs, 1);
|
|
ensures 2 <= numFields($abs);
|
|
ensures eax == 4 * numFields($abs);
|
|
ensures ObjSize($abs, $vt, $AbsMem[$abs][2], $AbsMem[$abs][3]);
|
|
{
|
|
assert TO(2);
|
|
assert TVL($abs);
|
|
assert TVT($abs, $vt);
|
|
call eax := RoLoad32(ecx + ?VT_BASE_LENGTH);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// 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, Ti, Tj, Tk, Tl, Fi, Fk, Fl, HeapLo, BF, BT;
|
|
modifies eax, ebx, ecx, edx, esi, edi, ebp, esp;
|
|
modifies $GcMem;
|
|
ensures MutatorInv(BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, Tk, Tl, $GcMem, $toAbs, $AbsMem, $gcSlice);
|
|
ensures WellFormed($toAbs);
|
|
ensures ebp == old(ebp);
|
|
{
|
|
var save:int;
|
|
var unitSize:int;
|
|
save := ebp;
|
|
|
|
// The heap consists of two bitmaps, followed by two semispaces:
|
|
// <--4--><--4--><--128--><--128-->
|
|
// Each bit map must consist of at least 4 bytes.
|
|
// For each bit in the bit map, there is one word in the corresponding semispace.
|
|
// Thus, the total gc memory size must be a multiple of:
|
|
// 4 + 4 + 128 + 128 = 8 + 256 = 264 bytes
|
|
|
|
// Compute gcMem size, in bytes and words
|
|
esi := ?gcHi;
|
|
call esi := Sub(esi, ?gcLo);
|
|
edi := esi;
|
|
|
|
// Break into 264-byte units. Let ebp be the number of units.
|
|
edx := 0;
|
|
eax := edi;
|
|
ebx := 264;
|
|
call eax, edx := Div(eax, edx, ebx);
|
|
ebp := eax;
|
|
unitSize := ebp;
|
|
assert 264 * unitSize <= (?gcHi - ?gcLo);
|
|
|
|
// Divide heap into ?gcLo <--4--> eax <--4--> ebx <--128--> ecx <--128--> ?gcHi
|
|
edx := 0;
|
|
call ebp := Lea(edx + 4 * ebp);
|
|
eax := ?gcLo;
|
|
BF := eax;
|
|
call eax := Add(eax, ebp);
|
|
BT := eax;
|
|
call ebx := Lea(eax + ebp);
|
|
call ebp := Lea(edx + 4 * ebp);
|
|
call ecx := Lea(ebx + 8 * ebp);
|
|
call edx := Lea(ecx + 8 * ebp);
|
|
|
|
$toAbs := MAP_NO_ABS;
|
|
HeapLo := ebx;
|
|
Fi := ebx;
|
|
Fk := ebx;
|
|
Fl := ecx;
|
|
Ti := ecx;
|
|
Tj := ecx;
|
|
Tk := ecx;
|
|
Tl := edx;
|
|
|
|
call __initialize(unitSize, HeapLo);
|
|
|
|
assert TV(?gcLo);
|
|
assert TV(HeapLo);
|
|
assert TO(0);
|
|
assert TO(unitSize);
|
|
assert TO(2 * unitSize);
|
|
assert TO(32 * unitSize);
|
|
eax := ?gcLo;
|
|
esi := unitSize;
|
|
call ebx := Lea(eax + 4 * esi);
|
|
esp := esp - 4; call BB4Zero($toAbs, 0, NO_ABS, Fi, Fi, Fi, Fl, 0, ?gcLo, ?gcLo + 4 * unitSize, 0, 0);
|
|
|
|
assert TVM(32, (BitIndex(HeapLo, Fl) - BitIndex(HeapLo, Fi)));
|
|
assert TVM(32, (BitIndex(HeapLo, Tl) - BitIndex(HeapLo, Ti)));
|
|
|
|
ebp := save;
|
|
esp := esp + 4; return;
|
|
}
|
|
|
|
// Prepare to call GcLoad (don't actually call it -- let the mutator call it)
|
|
procedure readCopying($ptr:int, $fld:int) returns ($val:int)
|
|
requires MutatorInv(BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, Tk, Tl, $GcMem, $toAbs, $AbsMem, $gcSlice);
|
|
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);
|
|
}
|
|
|
|
procedure writeCopying($ptr:int, $fld:int, $val:int, $abs:int) returns ($_gcData:[int]int, $_absData:[int][int]int)
|
|
requires MutatorInv(BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, Tk, Tl, $GcMem, $toAbs, $AbsMem, $gcSlice);
|
|
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(BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, Tk, Tl, $_gcData, $toAbs, $_absData, $gcSlice);
|
|
{
|
|
// 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(BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, Tk, Tl, $GcMem, $toAbs, $AbsMem, $gcSlice);
|
|
|
|
// 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, $SectionMem, $FrameMem, $freshAbs;
|
|
modifies Ti, Tj, Tk, Tl, Fi, Fk, Fl, BF, BT;
|
|
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(BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, Tk, Tl, $GcMem, $toAbs, $AbsMem, $gcSlice);
|
|
ensures Pointer($toAbs, eax - 4, $abs);
|
|
ensures WellFormed($toAbs);
|
|
ensures ebp == old(ebp);
|
|
{
|
|
var size:int;
|
|
var vt:int;
|
|
call doAllocObjectCopyingHelper($abs, $vt);
|
|
|
|
$freshAbs := $abs;
|
|
|
|
ebx := Fk;
|
|
call ebx := AddChecked(ebx, eax);
|
|
|
|
//if (!(Fk + size <= Fl))
|
|
if (ebx <= Fl) { goto skip1; }
|
|
size := eax;
|
|
vt := ecx;
|
|
|
|
call ecx := FrameLoad(($FrameCount), esp);
|
|
edx := ebp;
|
|
esp := esp - 4; call GarbageCollectCopying($ra, ebp);
|
|
|
|
eax := size;
|
|
ecx := vt;
|
|
|
|
ebx := Fk;
|
|
call ebx := AddChecked(ebx, eax);
|
|
if (ebx <= Fl) { goto skip1; }
|
|
// Out of memory
|
|
call DebugBreak();
|
|
skip1:
|
|
|
|
call doAllocObjectCopying($ra, ebp, $abs, $vt, eax);
|
|
esp := esp + 4; return;
|
|
}
|
|
|
|
procedure AllocString($ra:int, $abs:int, $vt:int, $nElems:int)
|
|
// GC invariant:
|
|
requires MutatorInv(BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, Tk, Tl, $GcMem, $toAbs, $AbsMem, $gcSlice);
|
|
|
|
// 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, $SectionMem, $FrameMem, $freshAbs;
|
|
modifies Ti, Tj, Tk, Tl, Fi, Fk, Fl, BF, BT;
|
|
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(BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, Tk, Tl, $GcMem, $toAbs, $AbsMem, $gcSlice);
|
|
ensures Pointer($toAbs, eax - 4, $abs);
|
|
ensures WellFormed($toAbs);
|
|
ensures ebp == old(ebp);
|
|
{
|
|
var size:int;
|
|
var nElems:int;
|
|
|
|
$freshAbs := $abs;
|
|
|
|
call ecx := AddChecked(ecx, 1);
|
|
edx := ecx;
|
|
call ecx := AddChecked(ecx, ecx);
|
|
call ecx := AddChecked(ecx, 19);
|
|
eax := 3;
|
|
call eax := Not(eax);
|
|
call ecx := And(ecx, eax);
|
|
ebx := Fk;
|
|
call ebx := AddChecked(ebx, ecx);
|
|
//if (!(Fk + pad(16 + 2 * $nElems) + 0 <= Fl))
|
|
if (ebx <= Fl) { goto skip1; }
|
|
size := ecx;
|
|
nElems := edx;
|
|
|
|
call ecx := FrameLoad(($FrameCount), esp);
|
|
edx := ebp;
|
|
esp := esp - 4; call GarbageCollectCopying($ra, ebp);
|
|
|
|
ecx := size;
|
|
edx := nElems;
|
|
ebx := Fk;
|
|
call ebx := AddChecked(ebx, ecx);
|
|
if (ebx <= Fl) { goto skip1; }
|
|
// Out of memory
|
|
call DebugBreak();
|
|
skip1:
|
|
|
|
call doAllocStringCopying($ra, ebp, $abs, $vt, $nElems);
|
|
esp := esp + 4; return;
|
|
}
|
|
|
|
procedure AllocArray($ra:int, $abs:int, $vt:int, $rank:int, $nElems:int)
|
|
// GC invariant:
|
|
requires MutatorInv(BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, Tk, Tl, $GcMem, $toAbs, $AbsMem, $gcSlice);
|
|
|
|
// 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, $SectionMem, $FrameMem, $freshAbs;
|
|
modifies Ti, Tj, Tk, Tl, Fi, Fk, Fl, BF, BT;
|
|
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(BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, Tk, Tl, $GcMem, $toAbs, $AbsMem, $gcSlice);
|
|
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;
|
|
|
|
$freshAbs := $abs;
|
|
|
|
call esi := FrameLoad(($FrameCount), esp + 4);
|
|
|
|
rank := edx;
|
|
call doAllocArrayCopyingHelper($abs, $vt, $rank, $nElems);
|
|
ebx := Fk;
|
|
call ebx := AddChecked(ebx, eax);
|
|
|
|
//if (!(Fk + size <= Fl))
|
|
if (ebx <= Fl) { goto skip1; }
|
|
size := eax;
|
|
vt := ecx;
|
|
nElems := esi;
|
|
|
|
call ecx := FrameLoad(($FrameCount), esp);
|
|
edx := ebp;
|
|
esp := esp - 4; call GarbageCollectCopying($ra, ebp);
|
|
|
|
eax := size;
|
|
ecx := vt;
|
|
esi := nElems;
|
|
ebx := Fk;
|
|
call ebx := AddChecked(ebx, eax);
|
|
if (ebx <= Fl) { goto skip1; }
|
|
// Out of memory
|
|
call DebugBreak();
|
|
skip1:
|
|
|
|
edx := rank;
|
|
call doAllocArrayCopying($ra, ebp, $abs, $vt, $rank, $nElems, eax);
|
|
esp := esp + 4; return;
|
|
}
|
|
|
|
procedure AllocVector($ra:int, $abs:int, $vt:int, $nElems:int)
|
|
// GC invariant:
|
|
requires MutatorInv(BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, Tk, Tl, $GcMem, $toAbs, $AbsMem, $gcSlice);
|
|
|
|
// 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);
|
|
requires MutatorInv(BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, Tk, Tl, $GcMem, $toAbs, $AbsMem, $gcSlice);
|
|
|
|
// 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, $SectionMem, $FrameMem, $freshAbs;
|
|
modifies Ti, Tj, Tk, Tl, Fi, Fk, Fl, BF, BT;
|
|
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(BF, BT, HeapLo, Fi, Fk, Fl, Ti, Tj, Tk, Tl, $GcMem, $toAbs, $AbsMem, $gcSlice);
|
|
ensures Pointer($toAbs, eax - 4, $abs);
|
|
ensures WellFormed($toAbs);
|
|
ensures ebp == old(ebp);
|
|
{
|
|
var size:int;
|
|
var vt:int;
|
|
var nElems:int;
|
|
|
|
nElems := edx;
|
|
call doAllocVectorCopyingHelper($abs, $vt, $nElems);
|
|
|
|
$freshAbs := $abs;
|
|
|
|
ebx := Fk;
|
|
call ebx := AddChecked(ebx, eax);
|
|
|
|
//if (!(Fk + size <= Fl))
|
|
if (ebx <= Fl) { goto skip1; }
|
|
size := eax;
|
|
vt := ecx;
|
|
|
|
call ecx := FrameLoad(($FrameCount), esp);
|
|
edx := ebp;
|
|
esp := esp - 4; call GarbageCollectCopying($ra, ebp);
|
|
|
|
eax := size;
|
|
ecx := vt;
|
|
|
|
ebx := Fk;
|
|
call ebx := AddChecked(ebx, eax);
|
|
if (ebx <= Fl) { goto skip1; }
|
|
// Out of memory
|
|
call DebugBreak();
|
|
skip1:
|
|
|
|
edx := nElems;
|
|
call doAllocVectorCopying($ra, ebp, $abs, $vt, $nElems, eax);
|
|
esp := esp + 4; return;
|
|
}
|
|
|