fpc/rtl/i386/heap.inc

1126 lines
32 KiB
PHP
Raw Blame History

{
$Id$
This file is part of the Free Pascal run time library.
Copyright (c) 1993,97 by the Free Pascal development team.
See the file COPYING.FPC, included in this distribution,
for details about the copyright.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
**********************************************************************}
{****************************************************************************
functions for heap management in the data segment
****************************************************************************}
{**** 10/06/97 added checkings and corrected some bugs in getmem/freemem ****}
{**** Pierre Muller *********************************************************}
{ three conditionnals here }
{ TEMPHEAP to allow to split the heap in two parts for easier release}
{ started for the compiler }
{ USEBLOCKS if you want special allocation for small blocks }
{ CHECKHEAP if you want to test the heap integrity }
{$IfDef CHECKHEAP}
{ 4 levels of tracing }
const tracesize = 4;
type pheap_mem_info = ^heap_mem_info;
heap_mem_info = record
next,previous : pheap_mem_info;
size : longint;
sig : longint; {dummy number for test }
calls : array [1..tracesize] of longint;
end;
{ size 8*4 = 32 }
{ help variables for debugging with GDB }
const check : boolean = false;
const last_assigned : pheap_mem_info = nil;
const growheapstop : boolean = false;
const free_nothing : boolean = false;
const trace : boolean = true;
const getmem_nb : longint = 0;
const freemem_nb : longint = 0;
{$EndIf CHECKHEAP}
const
heap_split : boolean = false;
max_size = 256;
maxblock = max_size div 8;
freerecord_list_length : longint = 0;
var
_memavail : longint;
_heapsize : longint;
type
{$ifdef UseBlocks}
tblocks = array[1..maxblock] of pointer;
pblocks = ^tblocks;
tnblocks = array[1..maxblock] of longint;
pnblocks = ^tnblocks;
{$endif UseBlocks}
pheapinfo = ^theapinfo;
theapinfo = record
heaporg,heapptr,heapend,freelist : pointer;
memavail,heapsize : longint;
{$ifdef UseBlocks}
block : pblocks;
nblock : pnblocks;
{$endif UseBlocks}
{$IfDef CHECKHEAP}
last_mem : pheap_mem_info;
nb_get,nb_free : longint;
{$EndIf CHECKHEAP}
end;
type
pfreerecord = ^tfreerecord;
tfreerecord = record
next : pfreerecord;
size : longint;
end;
var
baseheap : theapinfo;
curheap : pheapinfo;
{$ifdef TEMPHEAP}
tempheap : theapinfo;
otherheap : pheapinfo;
{$endif TEMPHEAP}
{$ifdef UseBlocks}
baseblocks : tblocks;
basenblocks : tnblocks;
{$endif UseBlocks}
{ this is not supported by FPK <v093
const
blocks : pblocks = @baseblocks;
nblocks : pnblocks = @basenblocks; }
type
ppointer = ^pointer;
{$ifdef UseBlocks}
var blocks : pblocks;
nblocks : pnblocks;
{$endif UseBlocks}
{$ifndef OS2}
{ OS2 function getheapstart is in sysos2.pas }
function getheapstart : pointer;
begin
asm
leal HEAP,%eax
leave
ret
end ['EAX'];
end;
{$endif}
function getheapsize : longint;
begin
asm
movl HEAPSIZE,%eax
leave
ret
end ['EAX'];
end;
function heapsize : longint;
begin
heapsize:=_heapsize;
end;
{$IfDef CHECKHEAP}
procedure call_stack(p : pointer);
var i : longint;
pp : pheap_mem_info;
begin
if trace then
begin
pp:=pheap_mem_info(p-sizeof(heap_mem_info));
writeln('Call trace of 0x',hexstr(longint(p),8));
writeln('of size ',pp^.size);
for i:=1 to tracesize do
begin
writeln(i,' 0x',hexstr(pp^.calls[i],8));
end;
end
else
writeln('tracing not enabled, sorry !!');
end;
procedure dump_heap(mark : boolean);
var pp : pheap_mem_info;
begin
pp:=last_assigned;
while pp<>nil do
begin
call_stack(pp+sizeof(heap_mem_info));
if mark then
pp^.sig:=$AAAAAAAA;
pp:=pp^.previous;
end;
end;
procedure dump_free(p : pheap_mem_info);
var ebp : longint;
begin
Writeln('Marked memory at ',HexStr(longint(p),8),' released');
call_stack(p+sizeof(heap_mem_info));
asm
movl (%ebp),%eax
movl (%eax),%eax
movl %eax,ebp
end;
dump_stack(ebp);
end;
function is_in_getmem_list (p : pointer) : boolean;
var pp : pheap_mem_info;
i : longint;
begin
is_in_getmem_list:=false;
pp:=last_assigned;
i:=0;
while pp<>nil do
begin
if (pp^.sig<>$DEADBEEF) and (pp^.sig <> $AAAAAAAA) then
begin
writeln('error in linked list of heap_mem_info');
runerror(204);
end;
if pp=p then
begin
is_in_getmem_list:=true;
end;
pp:=pp^.previous;
inc(i);
if i > getmem_nb - freemem_nb then
writeln('error in linked list of heap_mem_info');
end;
end;
function is_in_free(p : pointer) : boolean;
var
hp : pfreerecord;
begin
if p>heapptr then
begin
is_in_free:=true;
exit;
end
else
begin
hp:=freelist;
while assigned(hp) do
begin
if (p>=hp) and (p<hp+hp^.size) then
begin
is_in_free:=true;
exit;
end;
hp:=hp^.next;
end;
is_in_free:=false;
end;
end;
{$EndIf CHECKHEAP}
function cal_memavail : longint;
var
hp : pfreerecord;
ma : longint;
{$ifdef UseBlocks}
i : longint;
{$endif UseBlocks}
begin
ma:=heapend-heapptr;
{$ifdef UseBlocks}
for i:=1 to maxblock do
ma:=ma+i*8*nblocks^[i];
{$endif UseBlocks}
hp:=freelist;
while assigned(hp) do
begin
ma:=ma+hp^.size;
{$IfDef CHECKHEAP}
if (longint(hp^.next)=0) then
begin
if ((longint(hp)+hp^.size)>longint(heapptr)) then
writeln('freerecordlist bad at end ')
end
else
if ((longint(hp^.next)<=(longint(hp)+hp^.size)) or
((hp^.size and 7) <> 0)) then
writeln('error in freerecord list ');
{$EndIf CHECKHEAP}
hp:=hp^.next;
end;
cal_memavail:=ma;
end;
{$ifdef TEMPHEAP}
procedure split_heap;
var i :longint;
begin
if not heap_split then
begin
baseheap.heaporg:=heaporg;
baseheap.heapptr:=heapptr;
baseheap.freelist:=freelist;
baseheap.block:=blocks;
baseheap.nblock:=nblocks;
longint(baseheap.heapend):=((longint(heapend)+longint(heapptr)) div 16)*8;
tempheap.heaporg:=baseheap.heapend;
tempheap.freelist:=nil;
tempheap.heapptr:=tempheap.heaporg;
{$IfDef CHECKHEAP}
tempheap.last_mem:=nil;
tempheap.nb_get:=0;
tempheap.nb_free:=0;
{$EndIf CHECKHEAP}
tempheap.heapend:=heapend;
tempheap.memavail:=longint(tempheap.heapend) - longint(tempheap.heaporg);
tempheap.heapsize:=tempheap.memavail;
getmem(tempheap.block,sizeof(tblocks));
getmem(tempheap.nblock,sizeof(tnblocks));
for i:=1 to maxblock do
begin
tempheap.block^[i]:=nil;
tempheap.nblock^[i]:=0;
end;
heapend:=baseheap.heapend;
_memavail:=cal_memavail;
baseheap.memavail:=_memavail;
baseheap.heapsize:=longint(baseheap.heapend)-longint(baseheap.heaporg);
curheap:=@baseheap;
otherheap:=@tempheap;
heap_split:=true;
end;
end;
procedure switch_to_temp_heap;
begin
if curheap = @baseheap then
begin
baseheap.heaporg:=heaporg;
baseheap.heapend:=heapend;
baseheap.heapptr:=heapptr;
baseheap.freelist:=freelist;
baseheap.memavail:=_memavail;
baseheap.block:=blocks;
baseheap.nblock:=nblocks;
{$IfDef CHECKHEAP}
baseheap.last_mem:=last_assigned;
last_assigned:=tempheap.last_mem;
baseheap.nb_get:=getmem_nb;
baseheap.nb_free:=freemem_nb;
getmem_nb:=tempheap.nb_get;
freemem_nb:=tempheap.nb_free;
{$EndIf CHECKHEAP}
heaporg:=tempheap.heaporg;
heapptr:=tempheap.heapptr;
freelist:=tempheap.freelist;
heapend:=tempheap.heapend;
blocks:=tempheap.block;
nblocks:=tempheap.nblock;
_memavail:=cal_memavail;
curheap:=@tempheap;
otherheap:=@baseheap;
end;
end;
procedure switch_to_base_heap;
begin
if curheap = @tempheap then
begin
tempheap.heaporg:=heaporg;
tempheap.heapend:=heapend;
tempheap.heapptr:=heapptr;
tempheap.freelist:=freelist;
tempheap.memavail:=_memavail;
{$IfDef CHECKHEAP}
tempheap.last_mem:=last_assigned;
last_assigned:=baseheap.last_mem;
tempheap.nb_get:=getmem_nb;
tempheap.nb_free:=freemem_nb;
getmem_nb:=baseheap.nb_get;
freemem_nb:=baseheap.nb_free;
{$EndIf CHECKHEAP}
heaporg:=baseheap.heaporg;
heapptr:=baseheap.heapptr;
freelist:=baseheap.freelist;
heapend:=baseheap.heapend;
blocks:=baseheap.block;
nblocks:=baseheap.nblock;
_memavail:=cal_memavail;
curheap:=@baseheap;
otherheap:=@tempheap;
end;
end;
procedure switch_heap;
begin
if not heap_split then split_heap;
if curheap = @tempheap then
switch_to_base_heap
else
switch_to_temp_heap;
end;
procedure gettempmem(var p : pointer;size : longint);
begin
split_heap;
switch_to_temp_heap;
allow_special:=true;
getmem(p,size);
allow_special:=false;
end;
{$endif TEMPHEAP}
function memavail : longint;
begin
memavail:=_memavail;
end;
{$ifdef TEMPHEAP}
procedure unsplit_heap;
var hp,hp2,thp : pfreerecord;
begin
{heapend can be modified by HeapError }
if not heap_split then exit;
if baseheap.heapend = tempheap.heaporg then
begin
switch_to_base_heap;
hp:=pfreerecord(freelist);
if assigned(hp) then
while assigned(hp^.next) do hp:=hp^.next;
if tempheap.heapptr<>tempheap.heaporg then
begin
if hp<>nil then
hp^.next:=heapptr;
hp:=pfreerecord(heapptr);
hp^.size:=heapend-heapptr;
hp^.next:=tempheap.freelist;
heapptr:=tempheap.heapptr;
end;
heapend:=tempheap.heapend;
_memavail:=cal_memavail;
heap_split:=false;
end else
begin
hp:=pfreerecord(baseheap.freelist);
hp2:=pfreerecord(tempheap.freelist);
while assigned(hp) and assigned(hp2) do
begin
if hp=hp2 then break;
if hp>hp2 then
begin
thp:=hp2;
hp2:=hp;
hp:=thp;
end;
while assigned(hp^.next) and (hp^.next<hp2) do
hp:=hp^.next;
if assigned(hp^.next) then
begin
thp:=hp^.next;
hp^.next:=hp2;
hp:=thp;
end else
begin
hp^.next:=hp2;
hp:=nil;
end;
end ;
if heapend < tempheap.heapend then
heapend:=tempheap.heapend;
if heapptr < tempheap.heapptr then
heapptr:=tempheap.heapptr;
freemem(tempheap.block,sizeof(tblocks));
freemem(tempheap.nblock,sizeof(tnblocks));
_memavail:=cal_memavail;
heap_split:=false;
end;
end;
procedure releasetempheap;
begin
switch_to_temp_heap;
{$ifdef CHECKHEAP}
if heapptr<>heaporg then
writeln('Warning in releasetempheap : ',longint(tempheap.heapsize)-longint(tempheap.memavail),' bytes used !');
dump_heap(true);
{ release(heaporg);
fillchar(heaporg^,longint(heapend)-longint(heaporg),#0);}
{$endif CHECKHEAP }
unsplit_heap;
split_heap;
end;
{$endif TEMPHEAP}
function maxavail : longint;
var
hp : pfreerecord;
begin
maxavail:=heapend-heapptr;
hp:=freelist;
while assigned(hp) do
begin
if hp^.size>maxavail then
maxavail:=hp^.size;
hp:=hp^.next;
end;
end;
{$ifdef CHECKHEAP}
procedure test_memavail;
begin
if check and (_memavail<>cal_memavail) then
begin
writeln('Memavail error in getmem/freemem');
end;
end;
{$endif CHECKHEAP}
procedure getmem(var p : pointer;size : longint);[public,alias: 'GETMEM'];
{$IfDef CHECKHEAP}
var i,bp,orsize : longint;
label check_new;
{$endif CHECKHEAP}
{ changed to removed the OS conditionnals }
function call_heaperror(addr : pointer; size : longint) : integer;
begin
asm
pushl size
movl addr,%eax
{ movl HEAPERROR,%eax doesn't work !!}
call %eax
movw %ax,__RESULT
end;
end;
var
last,hp : pfreerecord;
nochmal : boolean;
{$ifdef UseBlocks}
s : longint;
{$endif}
begin
{$ifdef CHECKHEAP}
if trace then
begin
orsize:=size;
size:=size+sizeof(heap_mem_info);
end;
{$endif CHECKHEAP}
if size=0 then
begin
p:=heapend;
{$ifdef CHECKHEAP}
goto check_new;
{$else CHECKHEAP}
exit;
{$endif CHECKHEAP}
end;
{$ifdef TEMPHEAP}
if heap_split and not allow_special then
begin
if (@p < otherheap^.heapend) and
(@p > otherheap^.heaporg) then
{ useful line for the debugger }
writeln('warning : p and @p are in different heaps !');
end;
{$endif TEMPHEAP}
{ calc to multiply of 8 }
if (size and 7)<>0 then
size:=size+(8-(size and 7));
dec(_memavail,size);
{$ifdef UseBlocks}
{ search cache }
if size<=max_size then
begin
s:=size div 8;
if assigned(blocks^[s]) then
begin
p:=blocks^[s];
{$ifdef VER0_6}
move(blocks^[s]^,blocks^[s],4);
{$else VER0_6}
blocks^[s]:=pointer(blocks^[s]^);
{$endif VER0_6}
dec(nblocks^[s]);
{$ifdef CHECKHEAP}
goto check_new;
{$else CHECKHEAP}
exit;
{$endif CHECKHEAP}
end;
end;
{$endif UseBlocks}
repeat
nochmal:=false;
{ search the freelist }
if assigned(freelist) then
begin
last:=nil;
hp:=freelist;
while assigned(hp) do
begin
{ take the first fitting block }
if hp^.size>=size then
begin
p:=hp;
{ need we the whole block ? }
if hp^.size>size then
begin
{$ifdef UseBlocks}
{ we must check if we are still below the limit !! }
if hp^.size-size<=max_size then
begin
{ adjust the list }
if assigned(last) then
last^.next:=hp^.next
else
freelist:=hp^.next;
{ insert in chain }
s:=(hp^.size-size) div 8;
ppointer(hp+size)^:=blocks^[s];
blocks^[s]:=hp+size;
inc(nblocks^[s]);
end
else
{$endif UseBlocks}
begin
(hp+size)^.size:=hp^.size-size;
(hp+size)^.next:=hp^.next;
if assigned(last) then
last^.next:=hp+size
else
freelist:=hp+size;
end;
end
else
begin
{$IfDef CHECKHEAP}
dec(freerecord_list_length);
{$endif CHECKHEAP}
if assigned(last) then
last^.next:=hp^.next
else
{this was wrong !!}
{freelist:=nil;}
freelist:=hp^.next;
end;
{$ifdef CHECKHEAP}
goto check_new;
{$else CHECKHEAP}
exit;
{$endif CHECKHEAP}
end;
last:=hp;
hp:=hp^.next;
end;
end;
{ Latly, the top of the heap is checked, to see if there is }
{ still memory available. }
if heapend-heapptr<size then
begin
if assigned(heaperror) then
begin
case call_heaperror(heaperror,size) of
0 : runerror(203);
1 : p:=nil;
2 : nochmal:=true;
end;
end
else
runerror(203);
end
else
begin
p:=heapptr;
heapptr:=heapptr+size;
end;
until not nochmal;
{$ifdef CHECKHEAP}
check_new:
inc(getmem_nb);
test_memavail;
if trace then
begin
asm
movl (%ebp),%eax
movl %eax,bp
end;
pheap_mem_info(p)^.sig:=$DEADBEEF;
pheap_mem_info(p)^.previous:=last_assigned;
if last_assigned<>nil then
last_assigned^.next:=pheap_mem_info(p);
last_assigned:=p;
pheap_mem_info(p)^.next:=nil;
pheap_mem_info(p)^.size:=orsize;
for i:=1 to tracesize do
begin
pheap_mem_info(p)^.calls[i]:=get_addr(bp);
bp:=get_next_frame(bp);
end;
p:=p+sizeof(heap_mem_info);
end;
{$endif CHECKHEAP}
end;
procedure freemem(var p : pointer;size : longint);[public,alias: 'FREEMEM'];
var
hp : pfreerecord;
{$ifdef TEMPHEAP}
heap_switched : boolean;
{$endif TEMPHEAP}
{$ifdef UseBlocks}
s : longint;
{$endif UseBlocks}
label freemem_exit;
begin
{$ifdef CHECKHEAP}
if free_nothing then
begin
p:=nil;
exit;
end;
if trace then
begin
size:=size+sizeof(heap_mem_info);
p:=p-sizeof(heap_mem_info);
{ made after heap_switch
if not (is_in_getmem_list(p)) then
runerror(204); }
end;
{$endif CHECKHEAP}
if size=0 then
begin
p:=nil;
exit;
end;
if p=nil then RunError (204);
{$ifdef TEMPHEAP}
heap_switched:=false;
if heap_split and not allow_special then
begin
if (p <= heapptr) and
( p >= heaporg) and
(@p <= otherheap^.heapend) and
(@p >= otherheap^.heaporg) then
begin
writeln('warning : p and @p are in different heaps !');
end;
end;
if (p<heaporg) or (p>heapptr) then
begin
if heap_split and (p<otherheap^.heapend) and
(p>otherheap^.heaporg) then
begin
if (@p >= heaporg) and
(@p <= heapptr) and
not allow_special then
writeln('warning : p and @p are in different heaps !');
switch_heap;
heap_switched:=true;
end
else
begin
writeln('pointer ',hexstr(longint(@p),8),' at ',
hexstr(longint(p),8),' doesn''t points to the heap');
runerror(204);
end;
end;
{$endif TEMPHEAP}
{$ifdef CHECKHEAP}
if trace then
begin
if not (is_in_getmem_list(p)) then
runerror(204);
if pheap_mem_info(p)^.sig=$AAAAAAAA then
dump_free(p);
if pheap_mem_info(p)^.next<>nil then
pheap_mem_info(p)^.next^.previous:=pheap_mem_info(p)^.previous;
if pheap_mem_info(p)^.previous<>nil then
pheap_mem_info(p)^.previous^.next:=pheap_mem_info(p)^.next;
if pheap_mem_info(p)=last_assigned then
last_assigned:=last_assigned^.previous;
end;
{$endif CHECKHEAP}
{ calc to multiple of 8 }
if (size and 7)<>0 then
size:=size+(8-(size and 7));
inc(_memavail,size);
if p+size>=heapptr then
heapptr:=p
{$ifdef UseBlocks}
{ insert into cache }
else if size<=max_size then
begin
s:=size div 8;
ppointer(p)^:=blocks^[s];
blocks^[s]:=p;
inc(nblocks^[s]);
end
{$endif UseBlocks}
else
begin
{ size can be allways set }
pfreerecord(p)^.size:=size;
{ if there is no free list }
if not assigned(freelist) then
begin
{ then generate one }
freelist:=p;
pfreerecord(p)^.next:=nil;
{$ifdef CHECKHEAP}
inc(freerecord_list_length);
{$endif CHECKHEAP}
goto freemem_exit;
end;
if p+size<freelist then
begin
pfreerecord(p)^.next:=freelist;
freelist:=p;
{$ifdef CHECKHEAP}
inc(freerecord_list_length);
{$endif CHECKHEAP}
goto freemem_exit;
end
else
if p+size=freelist then
begin
inc(pfreerecord(p)^.size,pfreerecord(freelist)^.size);
pfreerecord(p)^.next:=pfreerecord(freelist)^.next;
freelist:=p;
{ but now it can also connect the next block !!}
if p+pfreerecord(p)^.size=pfreerecord(p)^.next then
begin
inc(pfreerecord(p)^.size,pfreerecord(p)^.next^.size);
{$ifdef CHECKHEAP}
dec(freerecord_list_length);
{$endif CHECKHEAP}
pfreerecord(p)^.next:=pfreerecord(freelist)^.next^.next;
end;
goto freemem_exit;
end;
{ search the insert position }
hp:=freelist;
while assigned(hp) do
begin
if p<hp+hp^.size then
begin
writeln('pointer to dispose at ',hexstr(longint(p),8),
' has already been disposed');
runerror(204);
end;
{ connecting two blocks ? }
if hp+hp^.size=p then
begin
inc(hp^.size,size);
{ connecting also to next block ? }
if hp+hp^.size=hp^.next then
begin
inc(hp^.size,hp^.next^.size);
{$ifdef CHECKHEAP}
dec(freerecord_list_length);
{$endif CHECKHEAP}
hp^.next:=hp^.next^.next;
end
else
if (hp^.next<>nil) and (hp+hp^.size>hp^.next) then
begin
writeln('pointer to dispose at ',hexstr(longint(p),8),
' is too big !!');
runerror(204);
end;
break;
end
{ if the end is reached, then concat }
else if hp^.next=nil then
begin
hp^.next:=p;
{$ifdef CHECKHEAP}
inc(freerecord_list_length);
{$endif CHECKHEAP}
pfreerecord(p)^.next:=nil;
break;
end
{ falls der n<>chste Zeiger gr<67><72>er ist, dann }
{ Einh<6E>ngen }
else if hp^.next>p then
begin
{ connect to blocks }
if p+size=hp^.next then
begin
pfreerecord(p)^.next:=hp^.next^.next;
inc(pfreerecord(p)^.size,hp^.next^.size);
{ we have to reset the right position }
hp^.next:=pfreerecord(p);
end
else
begin
pfreerecord(p)^.next:=hp^.next;
hp^.next:=p;
{$ifdef CHECKHEAP}
inc(freerecord_list_length);
{$endif CHECKHEAP}
end;
break;
end;
hp:=hp^.next;
end;
end;
freemem_exit:
{$ifdef CHECKHEAP}
inc(freemem_nb);
test_memavail;
{$endif CHECKHEAP}
p:=nil;
{$ifdef TEMPHEAP}
if heap_switched then switch_heap;
{$endif TEMPHEAP}
end;
procedure release(var p : pointer);
begin
heapptr:=p;
freelist:=nil;
_memavail:=cal_memavail;
end;
procedure mark(var p : pointer);
begin
p:=heapptr;
end;
procedure markheap(var oldfreelist,oldheapptr : pointer);
begin
oldheapptr:=heapptr;
oldfreelist:=freelist;
freelist:=nil;
_memavail:=cal_memavail;
end;
procedure releaseheap(oldfreelist,oldheapptr : pointer);
begin
heapptr:=oldheapptr;
if longint(freelist) < longint(heapptr) then
begin
{here we should reget the freed blocks}
end;
freelist:=oldfreelist;
_memavail:=cal_memavail;
end;
{ the sbrk function is moved to the system.pp }
{ as it is system dependent !! }
function growheap(size :longint) : integer;
var NewPos,wantedsize : longint;
hp : pfreerecord;
Newlimit : longint;
begin
wantedsize:=size;
size:=size+$ffff;
size:=size and $ffff0000;
{ Allocate by 64K size }
{ first try 1Meg }
NewPos:=Sbrk($100000);
if NewPos=-1 then
NewPos:=Sbrk(size)
else
size:=$100000;
if (NewPos = -1) then
begin
GrowHeap:=0;
{$IfDef CHECKHEAP}
writeln('Call to GrowHeap failed');
readln;
{$EndIf CHECKHEAP}
Exit;
end
else
begin
{ make the room clean }
{$ifdef CHECKHEAP}
Fillword(pointer(NewPos)^,size div 2,$ABCD);
Newlimit:= (newpos+size) or $3fff;
{$else }
Fillchar(pointer(NewPos)^,size,#0);
{$endif }
hp:=pfreerecord(freelist);
if not assigned(hp) then
begin
if pointer(newpos) = heapend then
heapend:=pointer(newpos+size)
else
begin
if heapend - heapptr > 0 then
begin
freelist:=heapptr;
hp:=pfreerecord(freelist);
hp^.size:=heapend-heapptr;
hp^.next:=nil;
end;
heapptr:=pointer(newpos);
heapend:=pointer(newpos+size);
end;
end
else
begin
if pointer(newpos) = heapend then
heapend:=pointer(newpos+size)
else
begin
while assigned(hp^.next) and (longint(hp^.next) < longint(NewPos)) do
hp:=hp^.next;
if hp^.next = nil then
begin
hp^.next:=pfreerecord(heapptr);
hp:=pfreerecord(heapptr);
hp^.size:=heapend-heapptr;
hp^.next:=nil;
heapptr:=pointer(NewPos);
heapend:=pointer(NewPos+Size);
end
else
begin
pfreerecord(NewPos)^.Size:=Size;
pfreerecord(NewPos)^.Next:=hp^.next;
hp^.next:=pfreerecord(NewPos);
end;
end;
end;
{ the wanted size has to be substracted }
_memavail:=cal_memavail-wantedsize;
{ set the total new heap size }
asm
movl Size,%ebx
movl HEAPSIZE,%eax
addl %ebx,%eax
movl %eax,HEAPSIZE
end;
GrowHeap:=2;{ try again }
_Heapsize:=size+_heapsize;
{$IfDef CHECKHEAP}
writeln('Call to GrowHeap succedeed : HeapSize = ',_HeapSize,' MemAvail = ',memavail);
writeln('New heap part begins at ',Newpos,' with size ',size);
if growheapstop then
readln;
{$EndIf CHECKHEAP}
exit;
end;
end;
{ This function will initialize the Heap manager and need to be called from
the initialization of the system unit }
procedure InitHeap;
{$ifdef UseBlocks}
var
i : longint;
{$endif UseBlocks}
begin
{$ifdef UseBlocks}
Blocks:=@baseblocks;
Nblocks:=@basenblocks;
for i:=1 to maxblock do
begin
Blocks^[i]:=nil;
Nblocks^[i]:=0;
end;
{$endif UseBlocks}
Curheap := @baseheap;
{$ifdef TEMPHEAP}
Otherheap := @tempheap;
{$endif TEMPHEAP}
HeapOrg := GetHeapStart;
HeapPtr := HeapOrg;
_memavail := GetHeapSize;
HeapEnd := HeapOrg + _memavail;
HeapError := @GrowHeap;
_heapsize:=longint(heapend)-longint(heaporg);
Freelist := nil;
end;
{
$Log$
Revision 1.2 1998-03-31 19:01:41 daniel
* Replaced 'mod 8' with 'and 7'. Generates more efficient code.
Revision 1.1.1.1 1998/03/25 11:18:43 root
* Restored version
Revision 1.7 1998/01/26 11:59:20 michael
+ Added log at the end
Working file: rtl/i386/heap.inc
description:
----------------------------
revision 1.6
date: 1998/01/19 14:02:30; author: pierre; state: Exp; lines: +2 -2
* bug in initheap fixed
----------------------------
revision 1.5
date: 1998/01/05 16:51:21; author: michael; state: Exp; lines: +31 -1
+ Moved init of heap to heap.inc: INITheap() (From Peter Vreman)
----------------------------
revision 1.4
date: 1998/01/03 00:46:08; author: michael; state: Exp; lines: +9 -3
* put ifdef useblocks around some local vars (From Peter Vreman)
----------------------------
revision 1.3
date: 1997/12/10 12:21:47; author: michael; state: Exp; lines: +2 -1
* Put test for nil pointer in freemem() function.
----------------------------
revision 1.2
date: 1997/12/01 12:34:36; author: michael; state: Exp; lines: +11 -3
+ added copyright reference in header.
----------------------------
revision 1.1
date: 1997/11/27 08:33:48; author: michael; state: Exp;
Initial revision
----------------------------
revision 1.1.1.1
date: 1997/11/27 08:33:48; author: michael; state: Exp; lines: +0 -0
FPC RTL CVS start
=============================================================================
}