fpc/rtl/inc/pagemem.pp
2023-07-27 19:04:03 +02:00

887 lines
26 KiB
ObjectPascal

{
$Id: $
This file is part of the Free Pascal run time library.
Copyright (c) 2004 by Daniel Mantione
member of the Free Pascal development team
Implements a memory manager that makes use of the fact that
a program is running in a virtual address space where pages
can be allocated at random, instead of a more traditional
growing heap.
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.
**********************************************************************}
{$IFNDEF FPC_DOTTEDUNITS}
unit pagemem;
{$ENDIF FPC_DOTTEDUNITS}
{*****************************************************************************}
interface
{*****************************************************************************}
{*****************************************************************************}
implementation
{*****************************************************************************}
{$packrecords 1}
{$packenum 1}
type Tpage_type=(pt_8byte_with_bitmap,pt_suballocation,pt_direct_page);
Ppage_type=^Tpage_type;
Pcriterium=^Tcriterium;
Tcriterium=record
criterium1,criterium2:cardinal;
end;
Ptree_struct=^Ttree_struct;
Ttree_struct=record
left,right:ptruint;
end;
{This page layout is targeted at very short strings and linked lists
with very low payload. It uses fixed memory sizes of 8 byte. Memory
overhead should be avoided at all here. An allocation bitmap does this
very well, only 1 bit per memory block.}
Ppage_8byte_with_bitmap=^Tpage_8byte_with_bitmap;
Tpage_8byte_with_bitmap=record
page_type:Tpage_type;
search_index:byte;
free_count:word;
page_birthyear:cardinal;
freelist_prev,freelist_next:Ppage_8byte_with_bitmap;
block_allocation_map:array[0..15] of cardinal;
end;
Ppage_suballocation=^Tpage_suballocation;
Tpage_suballocation=record
page_type:Tpage_type;
reserved:array[1..3] of byte;
page_birthyear:cardinal;
end;
{This page layout is targeted at large memory blocks. We allocate
pages directly from the OS for such blocks.}
Ppage_direct=^Tpage_direct;
Tpage_direct=record
page_type:Tpage_type;
reserved:array[1..3] of byte;
size:cardinal;
end;
Pfree_block=^Tfree_block;
Tfree_block=record
size:cardinal;
tree_sizememloc:Ttree_struct;
tree_memlocation:Ttree_struct;
end;
Tsplay_status=(ts_not_found,ts_found_on_left,
ts_found_on_p,ts_found_on_right);
Psuballoc_header=^Tsuballoc_header;
Tsuballoc_header=record
alloc_size:ptruint;
end;
const tree_sizememloc_offset=4;
tree_memlocation_offset=12;
page_size=4096;
page_shift=12;
page_mask=$00000fff;
page_8byte_with_bitmap_maxspace=
(page_size-sizeof(Tpage_8byte_with_bitmap)) div 8;
memblock_align=4;
memblock_alignround=memblock_align-1;
min_suballoc_size=sizeof(Tfree_block);
const freelist_8byte_with_bitmap:Ppage_8byte_with_bitmap=nil;
page_8byte_with_bitmap_init:Tpage_8byte_with_bitmap=
(
page_type:pt_8byte_with_bitmap;
search_index:0;
free_count:page_8byte_with_bitmap_maxspace;
page_birthyear:0;
freelist_prev:nil;
freelist_next:nil;
block_allocation_map:($ffffffff,$ffffffff,$ffffffff,$ffffffff,
$ffffffff,$ffffffff,$ffffffff,$ffffffff,
$ffffffff,$ffffffff,$ffffffff,$ffffffff,
$ffffffff,$ffffffff,$ffffffff,$ffffffff)
);
var tree_sizememloc,tree_memlocation:Pfree_block;
{****************************************************************************
Page allocation/deallocation
****************************************************************************}
function fpmmap(adr:pointer;len,prot,flags,fd,off:sizeint):pointer;external name 'FPC_SYSC_MMAP';
function fpmunmap(adr:pointer;len:sizeint):pointer;external name 'FPC_SYSC_MUNMAP';
function geterrno:longint;external name 'FPC_SYS_GETERRNO';
const PROT_READ = $1; { page can be read }
PROT_WRITE = $2; { page can be written }
PROT_EXEC = $4; { page can be executed }
PROT_NONE = $0; { page can not be accessed }
MAP_SHARED = $1; { Share changes }
MAP_PRIVATE = $2; { Changes are private }
MAP_TYPE = $f; { Mask for type of mapping }
MAP_FIXED = $10; { Interpret addr exactly }
MAP_ANONYMOUS = $20; { don't use a file }
MAP_GROWSDOWN = $100; { stack-like segment }
MAP_DENYWRITE = $800; { ETXTBSY }
MAP_EXECUTABLE = $1000; { mark it as an executable }
MAP_LOCKED = $2000; { pages are locked }
MAP_NORESERVE = $4000; { don't check for reservations }
function req_pages(count:cardinal):pointer;
{Requests count consecutive pages from the OS.}
begin
req_pages:=fpmmap(nil,count shl page_shift,PROT_READ or PROT_WRITE,
MAP_PRIVATE or MAP_ANONYMOUS,0,0);
if geterrno<>0 then
req_pages:=nil; {This one can fail, so we can handle an out of memory
situation.}
end;
procedure sack_pages(p:pointer;count:cardinal);
begin
fpmunmap(p,count shl page_shift);
if geterrno<>0 then
runerror(204); {This one should succees.}
end;
{****************************************************************************
8-bit bitmap allocated memory
****************************************************************************}
procedure new_page_8byte_with_bitmap;
var page:Ppage_8byte_with_bitmap;
begin
page:=req_pages(1);
page^:=page_8byte_with_bitmap_init;
page^.freelist_next:=freelist_8byte_with_bitmap;
page^.freelist_prev:=nil;
if freelist_8byte_with_bitmap<>nil then
freelist_8byte_with_bitmap^.freelist_prev:=page;
freelist_8byte_with_bitmap:=page;
end;
function pgetmem_8byte_with_bitmap:pointer;
var page:Ppage_8byte_with_bitmap;
bit:cardinal;
begin
if freelist_8byte_with_bitmap=nil then
new_page_8byte_with_bitmap;
page:=freelist_8byte_with_bitmap;
with page^ do
begin
{Search a dword in which a bit is set.}
while block_allocation_map[search_index]=0 do
search_index:=(search_index+1) and 15;
ptrint(pgetmem_8byte_with_bitmap):=ptrint(page)+sizeof(page^)+search_index*256;
{Search for a set bit in the dword.}
bit:=1;
while block_allocation_map[search_index] and bit=0 do
begin
bit:=bit shl 1;
inc(ptrint(pgetmem_8byte_with_bitmap),8);
end;
{Allocate the block.}
block_allocation_map[search_index]:=block_allocation_map[search_index] and not bit;
dec(free_count);
if free_count=0 then
begin
{There is no space left in this page. Remove it from the freelist.}
if freelist_next<>nil then
freelist_next^.freelist_prev:=freelist_prev;
if freelist_prev<>nil then
freelist_prev^.freelist_next:=freelist_next;
if freelist_8byte_with_bitmap=page then
freelist_8byte_with_bitmap:=freelist_next;
freelist_prev:=nil;
freelist_next:=nil;
end;
end;
end;
function pfreemem_8byte_with_bitmap(page:Ppage_8byte_with_bitmap;p:pointer):ptrint;
var index,bit:cardinal;
begin
index:=(ptrint(p)-ptrint(page)-sizeof(page^)) div 8;
bit:=index and 31;
index:=index shr 5;
with page^ do
begin
if free_count=0 then
begin
{Page will get free slots. Must be included in freelist.}
if freelist_8byte_with_bitmap=nil then
freelist_8byte_with_bitmap:=page
else
begin
freelist_next:=freelist_8byte_with_bitmap;
freelist_8byte_with_bitmap^.freelist_prev:=page;
freelist_8byte_with_bitmap:=page;
end;
{Make sure the next allocation finds the slot without much searching.}
search_index:=index;
end;
block_allocation_map[index]:=block_allocation_map[index] or (1 shl bit);
inc(free_count);
if free_count=page_8byte_with_bitmap_maxspace then
begin
{The page is completely free. It can be returned to the OS, but
remove it from the freelist first.}
if freelist_next<>nil then
freelist_next^.freelist_prev:=freelist_prev;
if freelist_prev<>nil then
freelist_prev^.freelist_next:=freelist_next;
if freelist_8byte_with_bitmap=page then
freelist_8byte_with_bitmap:=freelist_next;
sack_pages(page,1);
end;
end;
pfreemem_8byte_with_bitmap:=8;
end;
{****************************************************************************
Splay tree stuff
****************************************************************************}
{ $define debug}
{$ifdef debug}
procedure write_sizememloc_tree(tree:Pfree_block;level:cardinal);
var i:cardinal;
begin
if tree=nil then
exit;
write_sizememloc_tree(Pfree_block(tree^.tree_sizememloc.left),level+1);
for i:=1 to level do
write(' ');
writeln(tree^.size,' ',hexstr(ptruint(tree),8));
write_sizememloc_tree(Pfree_block(tree^.tree_sizememloc.right),level+1);
end;
procedure write_memlocation_tree(tree:Pfree_block;level:cardinal);
var i:cardinal;
begin
if tree=nil then
exit;
write_memlocation_tree(Pfree_block(tree^.tree_memlocation.left),level+1);
for i:=1 to level do
write(' ');
writeln(hexstr(ptruint(tree),8));
write_memlocation_tree(Pfree_block(tree^.tree_memlocation.right),level+1);
end;
{$endif}
procedure rotate_l(var p:ptruint;offset:cardinal);
var p1:ptruint;
begin
p1:=Ptree_struct(p+offset)^.right;
Ptree_struct(p+offset)^.right:=Ptree_struct(p1+offset)^.left;
Ptree_struct(p1+offset)^.left:=p;
p:=p1;
end;
procedure rotate_r(var p:ptruint;offset:cardinal);
var p1:ptruint;
begin
p1:=Ptree_struct(p+offset)^.left;
Ptree_struct(p+offset)^.left:=Ptree_struct(p1+offset)^.right;
Ptree_struct(p1+offset)^.right:=p;
p:=p1;
end;
procedure zigzig(var p:ptruint;offset:cardinal);inline;
begin
rotate_r(p,offset);
rotate_r(p,offset);
end;
procedure zigzag(var p:ptruint;offset:cardinal);inline;
begin
rotate_l(Ptree_struct(p+offset)^.left,offset);
rotate_r(p,offset);
end;
procedure zagzig(var p:ptruint;offset:cardinal);inline;
begin
rotate_r(Ptree_struct(p+offset)^.right,offset);
rotate_l(p,offset);
end;
procedure zagzag(var p:ptruint;offset:cardinal);inline;
begin
rotate_l(p,offset);
rotate_l(p,offset);
end;
procedure delete_from_tree(var p:ptruint;offset:cardinal);
var p1:ptruint;
pp1:^ptruint;
begin
if Ptree_struct(p+offset)^.left=0 then
p:=Ptree_struct(p+offset)^.right
else
begin
if Ptree_struct(p+offset)^.right<>0 then
begin
{Both are occupied. Move right to rightmost leaf of left.}
p1:=Ptree_struct(p+offset)^.left;
repeat
pp1:=@Ptree_struct(p1+offset)^.right;
p1:=pp1^;
until p1=0;
pp1^:=Ptree_struct(p+offset)^.right;
end;
p:=Ptree_struct(p+offset)^.left;
end;
end;
function find_sizememloc(size:ptruint;var p:Pfree_block):Tsplay_status;
begin
find_sizememloc:=ts_found_on_p;
if p=nil then
find_sizememloc:=ts_not_found
else if size<p^.size then {Do nothing if equal...}
case find_sizememloc(size,Pfree_block(p^.tree_sizememloc.left)) of
ts_not_found:
if p^.size<size then
find_sizememloc:=ts_not_found;
ts_found_on_left:
zigzig(ptruint(p),tree_sizememloc_offset);
ts_found_on_p:
find_sizememloc:=ts_found_on_left;
ts_found_on_right:
zigzag(ptruint(p),tree_sizememloc_offset);
end
else if size>p^.size then
case find_sizememloc(size,Pfree_block(p^.tree_sizememloc.right)) of
ts_not_found:
if p^.size<size then
find_sizememloc:=ts_not_found;
ts_found_on_left:
zagzig(ptruint(p),tree_sizememloc_offset);
ts_found_on_p:
find_sizememloc:=ts_found_on_right;
ts_found_on_right:
zagzag(ptruint(p),tree_sizememloc_offset);
end;
end;
{$if 0}
function find_sizememloc(size,loc:ptruint;var p:Pfree_block):Tsplay_status;
var on_left:boolean;
begin
find_sizememloc:=ts_found_on_p;
if p=nil then
find_sizememloc:=ts_not_found
else
begin
on_left:=size<p^.size;
if size=p^.size then
if loc=ptruint(p) then
exit
else
on_left:=loc<ptruint(p);
if on_left then
case find_sizememloc(size,loc,Pfree_block(p^.tree_sizememloc.left)) of
ts_not_found:
find_sizememloc:=ts_not_found;
ts_found_on_left:
zigzig(ptruint(p),tree_sizememloc_offset);
ts_found_on_p:
find_sizememloc:=ts_found_on_left;
ts_found_on_right:
zigzag(ptruint(p),tree_sizememloc_offset);
end
else
case find_sizememloc(size,loc,Pfree_block(p^.tree_sizememloc.right)) of
ts_not_found:
find_sizememloc:=ts_not_found;
ts_found_on_left:
zagzig(ptruint(p),tree_sizememloc_offset);
ts_found_on_p:
find_sizememloc:=ts_found_on_right;
ts_found_on_right:
zagzag(ptruint(p),tree_sizememloc_offset);
end;
end;
end;
{$endif}
function insert_sizememloc(node:Pfree_block;var p:Pfree_block):Tsplay_status;
{Preconditions:
node^.size is set
node^.tree_sizememloc.left is set to nil
node^.tree_sizememloc.right is set to nil}
var on_left:boolean;
begin
insert_sizememloc:=ts_found_on_p;
if p=nil then
p:=node
else
begin
on_left:=node^.size<p^.size;
if node^.size=p^.size then
on_left:=ptruint(node)<ptruint(p);
if on_left then
case insert_sizememloc(node,Pfree_block(p^.tree_sizememloc.left)) of
ts_found_on_left:
zigzig(ptruint(p),tree_sizememloc_offset);
ts_found_on_p:
insert_sizememloc:=ts_found_on_left;
ts_found_on_right:
zigzag(ptruint(p),tree_sizememloc_offset);
end
else
case insert_sizememloc(node,Pfree_block(p^.tree_sizememloc.right)) of
ts_found_on_left:
zagzig(ptruint(p),tree_sizememloc_offset);
ts_found_on_p:
insert_sizememloc:=ts_found_on_right;
ts_found_on_right:
zagzag(ptruint(p),tree_sizememloc_offset);
end;
end;
{$ifdef debug}
writeln('sizememlocboom na insert');
write_sizememloc_tree(tree_sizememloc,1);
{$endif}
end;
{$if 0}
function find_memlocation(location:ptruint;var p:Pfree_block;
find_smaller:boolean):Tsplay_status;
begin
find_memlocation:=ts_found_on_p;
if p=nil then
find_memlocation:=ts_not_found
else if location<ptruint(p) then {Do nothing if equal...}
case find_memlocation(location,Pfree_block(p^.tree_memlocation.left),
find_smaller) of
ts_not_found:
if (ptruint(p)>location) or not find_smaller then
find_memlocation:=ts_not_found;
ts_found_on_left:
zigzig(ptruint(p),tree_memlocation_offset);
ts_found_on_p:
find_memlocation:=ts_found_on_left;
ts_found_on_right:
zigzag(ptruint(p),tree_memlocation_offset);
end
else if location>ptruint(p) then
case find_memlocation(location,Pfree_block(p^.tree_memlocation.right),
find_smaller) of
ts_not_found:
if (ptruint(p)>location) or not find_smaller then
find_memlocation:=ts_not_found;
ts_found_on_left:
zagzig(ptruint(p),tree_memlocation_offset);
ts_found_on_p:
find_memlocation:=ts_found_on_right;
ts_found_on_right:
zagzag(ptruint(p),tree_memlocation_offset);
end;
end;
{$endif}
function insert_memlocation(node:Pfree_block;var p:Pfree_block):Tsplay_status;
{Preconditions:
node^.size is set
node^.tree_sizememloc.left is set to nil
node^.tree_sizememloc.right is set to nil}
begin
insert_memlocation:=ts_found_on_p;
if p=nil then
p:=node
else if ptruint(node)<=ptruint(p) then {Equal? Insert on left.}
case insert_memlocation(node,Pfree_block(p^.tree_memlocation.left)) of
ts_found_on_left:
zigzig(ptruint(p),tree_memlocation_offset);
ts_found_on_p:
insert_memlocation:=ts_found_on_left;
ts_found_on_right: zigzag(ptruint(p),tree_memlocation_offset);
end
else if ptruint(node)>ptruint(p) then
case insert_memlocation(node,Pfree_block(p^.tree_memlocation.right)) of
ts_found_on_left:
zagzig(ptruint(p),tree_memlocation_offset);
ts_found_on_p:
insert_memlocation:=ts_found_on_right;
ts_found_on_right:
zagzag(ptruint(p),tree_memlocation_offset);
end;
{$ifdef debug}
writeln('memlocationboom na insert');
write_memlocation_tree(tree_memlocation,1);
{$endif}
end;
function get_memlocation(node:Pfree_block):Pfree_block;
{Iteratively delete node from tree without splaying.}
var p:^Pfree_block;
begin
p:=@tree_memlocation;
while (p^<>nil) and (p^<>node) do
if ptruint(node)<ptruint(p^) then
p:=@p^^.tree_memlocation.left
else
p:=@p^^.tree_memlocation.right;
get_memlocation:=p^;
if p^<>nil then
delete_from_tree(ptruint(p^),tree_memlocation_offset);
end;
function get_sizememloc(node:Pfree_block):Pfree_block;
{Iteratively delete node from tree without splaying.}
var p:^Pfree_block;
on_left:boolean;
begin
p:=@tree_sizememloc;
while (p^<>nil) and (p^<>node) do
begin
on_left:=node^.size<p^^.size;
if node^.size=p^^.size then
on_left:=ptruint(node)<ptruint(p^);
if on_left then
p:=@p^^.tree_sizememloc.left
else
p:=@p^^.tree_sizememloc.right;
end;
get_sizememloc:=p^;
if p^<>nil then
delete_from_tree(ptruint(p^),tree_sizememloc_offset);
end;
function get_block_by_size(size:cardinal):Pfree_block;
var what:^ptruint;
begin
case find_sizememloc(size,tree_sizememloc) of
ts_not_found:
begin
get_block_by_size:=nil;
exit;
end;
ts_found_on_left:
what:=@tree_sizememloc^.tree_sizememloc.left;
ts_found_on_p:
what:=@tree_sizememloc;
ts_found_on_right:
what:=@tree_sizememloc^.tree_sizememloc.right;
end;
get_block_by_size:=Pfree_block(what^);
delete_from_tree(what^,tree_sizememloc_offset);
if get_memlocation(get_block_by_size)=nil then
runerror(204);
end;
function get_block_by_memlocation(location:ptruint):Pfree_block;
var what:^ptruint;
begin
get_block_by_memlocation:=get_memlocation(Pfree_block(location));
if get_block_by_memlocation<>nil then
begin
get_sizememloc(get_block_by_memlocation);
{ case find_sizememloc(get_block_by_memlocation^.size,
ptruint(get_block_by_memlocation),tree_sizememloc) of
ts_not_found:
runerror(204);
ts_found_on_left:
what:=@tree_sizememloc^.tree_sizememloc.left;
ts_found_on_p:
what:=@tree_sizememloc;
ts_found_on_right:
what:=@tree_sizememloc^.tree_sizememloc.right;
end;
delete_from_tree(what^,tree_sizememloc_offset);}
end;
end;
function get_smaller_neighbour(location:ptruint):Pfree_block;
var p,what:^ptruint;
begin
{Find a smaller block. Don't splay as it will be deleted.}
p:=@tree_memlocation;
what:=nil;
while (p^<>0) do
if location<=p^ then
p:=@Pfree_block(p^)^.tree_memlocation.left
else
begin
what:=p;
p:=@Pfree_block(p^)^.tree_memlocation.right;
end;
if (what=nil) or (ptruint(what^)+Pfree_block(what^)^.size<>location) then
begin
get_smaller_neighbour:=nil;
exit;
end;
get_smaller_neighbour:=Pfree_block(what^);
delete_from_tree(ptruint(what^),tree_memlocation_offset);
get_sizememloc(get_smaller_neighbour);
end;
{function pgetmem_directpage(memsize:ptrint):pointer;
var npages:ptrint;
begin
npages:=(memsize+sizeof(Tpage_direct)+page_size-1) div page_size;
pgetmem_directpage:=req_pages(npages);
with Ppage_direct(pgetmem_directpage)^ do
begin
page_type:=pt_direct_page;
size:=memsize;
end;
end;
}
function pgetmem_suballocpage(memsize:ptrint):pointer;
var free_block:Pfree_block;
page:pointer;
needsize,remaining,block_start:ptruint;
begin
{$ifdef debug}
writeln('-------Getmem------- ',memsize);
{$endif}
{Constant parts on left because of constant evaluation.}
needsize:=(sizeof(Tsuballoc_header)+memblock_alignround+memsize) and not memblock_alignround;
if needsize<min_suballoc_size then
needsize:=min_suballoc_size;
{$ifdef debug}
writeln('sizememlocboom voor get:');
write_sizememloc_tree(tree_sizememloc,2);
{$endif}
free_block:=get_block_by_size(needsize);
if free_block=nil then
begin
page:=req_pages(1);
Ppage_suballocation(page)^.page_type:=pt_suballocation;
{Allocate at the end of the page, a free block at the start.}
free_block:=Pfree_block(ptruint(page)+sizeof(Tpage_suballocation));
remaining:=page_size-needsize-sizeof(Tpage_suballocation);
block_start:=ptruint(page)+page_size-needsize;
Psuballoc_header(block_start)^.alloc_size:=needsize;
pgetmem_suballocpage:=pointer(block_start+sizeof(Tsuballoc_header));
end
else
begin
block_start:=ptruint(free_block);
remaining:=free_block^.size-needsize;
if (remaining<min_suballoc_size) then
begin
needsize:=free_block^.size;
free_block:=nil;
end
else
inc(ptruint(free_block),needsize);
Psuballoc_header(block_start)^.alloc_size:=needsize;
pgetmem_suballocpage:=pointer(block_start+sizeof(Tsuballoc_header));
end;
if free_block<>nil then
begin
with free_block^ do
begin
size:=remaining;
tree_sizememloc.left:=0;
tree_sizememloc.right:=0;
tree_memlocation.left:=0;
tree_memlocation.right:=0;
end;
insert_sizememloc(free_block,tree_sizememloc);
insert_memlocation(free_block,tree_memlocation);
end;
end;
function pfreemem_suballoc_page(page:Ppage_direct;p:pointer):ptrint;
var free_block,neighbour:Pfree_block;
headerp:Psuballoc_header;
asize:ptruint;
begin
{$Ifdef debug}
write('-------Freemem------- ');
{$endif}
headerp:=Psuballoc_header(ptrint(p)-sizeof(Tsuballoc_header));
asize:=headerp^.alloc_size;
{$ifdef debug}
writeln(hexstr(ptruint(page),8),' ',asize);
{$endif}
free_block:=Pfree_block(headerp);
{Search neighbour to coalesce with above block.}
neighbour:=get_block_by_memlocation(ptruint(free_block)+asize);
if neighbour<>nil then
inc(asize,neighbour^.size);
{Search neighbour to coalesce with below block.}
neighbour:=get_smaller_neighbour(ptruint(free_block));
if neighbour<>nil then
begin
inc(asize,neighbour^.size);
free_block:=neighbour;
end;
{Page empty??}
if (ptruint(free_block) and page_mask=sizeof(Tpage_suballocation)) and
(asize=page_size-sizeof(Tpage_suballocation)) then
sack_pages(pointer(ptruint(free_block) and not page_mask),1)
else
begin
with free_block^ do
begin
size:=asize;
tree_sizememloc.left:=0;
tree_sizememloc.right:=0;
tree_memlocation.left:=0;
tree_memlocation.right:=0;
end;
insert_sizememloc(free_block,tree_sizememloc);
insert_memlocation(free_block,tree_memlocation);
end;
end;
function pgetmem(size:ptrint):pointer;
begin
if size<=8 then
pgetmem:=pgetmem_8byte_with_bitmap
else
pgetmem:=pgetmem_suballocpage(size);
end;
function pallocmem(size:ptrint):pointer;
begin
if size<=8 then
begin
pallocmem:=pgetmem_8byte_with_bitmap;
fillchar(Pbyte(pallocmem)^,8,0);
end
else
{Freshly allocated pages are allways already cleared.}
{ pgallocmem:=pgallocmem_directpage(size)};
end;
function pfreemem(p:pointer):ptrint;
var page:pointer;
begin
page:=pointer(ptrint(p) and not page_mask);
case Ppage_type(page)^ of
pt_8byte_with_bitmap:
pfreemem:=pfreemem_8byte_with_bitmap(page,p);
pt_suballocation:
pfreemem:=pfreemem_suballoc_page(page,p);
else
runerror(204);
end;
end;
function pfreememsize(p:pointer;size:ptrint):ptrint;
begin
{ runerror(204);}
pfreemem(p);
end;
function preallocmem(var p:pointer;size:ptrint):pointer;
begin
runerror(204);
end;
function pmemsize(p:pointer):ptrint;
begin
runerror(204);
end;
const page_memory_manager:Tmemorymanager=
(
needlock:false;
getmem:@pgetmem;
freemem:@pfreemem;
freememsize:@pfreememsize;
allocmem:@pallocmem;
reallocmem:@preallocmem;
memsize:@pmemsize;
{ memavail:@pmemavail;}
{ maxavail:@pmaxavail;}
{ heapsize:@pheapsize;}
);
var oldmemman:Tmemorymanager;
initialization
getmemorymanager(oldmemman);
setmemorymanager(page_memory_manager);
finalization
setmemorymanager(oldmemman);
end.