forked from KolibriOS/kolibrios
initial import of metcc project
git-svn-id: svn://kolibrios.org@145 a494cfbc-eb01-0410-851d-a64ba20cac60
This commit is contained in:
536
programs/develop/metcc/trunk/libc/mem/memalloc.asm
Normal file
536
programs/develop/metcc/trunk/libc/mem/memalloc.asm
Normal file
@@ -0,0 +1,536 @@
|
||||
format ELF
|
||||
section '.text' executable
|
||||
public malloc
|
||||
public free
|
||||
public realloc
|
||||
public mf_init
|
||||
;multithread: ;uncomment this for thread-safe version
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Memory allocator for MenuetOS ;;
|
||||
;; Halyavin Andrey halyavin@land.ru, 2006 ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; allocated mem block structure ;;
|
||||
;; +0: bit 0 - used flag ;;
|
||||
;; bits 31..1 - block size ;;
|
||||
;; +4: address of prev block ;;
|
||||
;; +8 .. +(blocksize) - allocated memory ;;
|
||||
;; +(blocksize) - next block ;;
|
||||
;; ;;
|
||||
;; free mem block structure ;;
|
||||
;; +0: bit 0 - used flag ;;
|
||||
;; bits 31..1 - block size ;;
|
||||
;; +4: address of prev block ;;
|
||||
;; +8: prev free block ;;
|
||||
;; +12: next free block ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
memblock.size=0
|
||||
memblock.prevblock=4
|
||||
memblock.prevfreeblock=8
|
||||
memblock.nextfreeblock=12
|
||||
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; mf_init ;;
|
||||
;; Initialize memory map for dynamic use ;;
|
||||
;; input: eax: starting address or 0 ;;
|
||||
;; output: none ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
mf_init:
|
||||
push ebx
|
||||
push ecx
|
||||
test eax,eax
|
||||
jnz .noautodet
|
||||
sub esp,1024
|
||||
mov ebx,esp
|
||||
mov ecx,-1
|
||||
mov eax,9
|
||||
int 0x40
|
||||
mov eax,[esp+26]
|
||||
add esp,1024
|
||||
.noautodet:
|
||||
add eax,15
|
||||
and eax,not 15
|
||||
mov [heapsmallblocks],eax
|
||||
add eax,2048
|
||||
mov [heapstart],eax
|
||||
mov [heapfreelist],eax
|
||||
mov [heaplastblock],eax
|
||||
|
||||
mov ecx,eax
|
||||
if defined heapstartsize
|
||||
add ecx,heapstartsize
|
||||
else
|
||||
add ecx,4096
|
||||
end if
|
||||
add ecx,4095
|
||||
and ecx,not 4095
|
||||
push eax
|
||||
mov eax,64
|
||||
mov ebx,1
|
||||
int 0x40
|
||||
pop eax
|
||||
mov [eax+memblock.prevblock],dword 0
|
||||
mov [heapend],ecx
|
||||
mov [eax+memblock.size],ecx
|
||||
sub [eax+memblock.size],eax
|
||||
xor ebx,ebx
|
||||
mov dword [eax+memblock.prevfreeblock],heapfreelist-memblock.nextfreeblock
|
||||
mov [eax+memblock.nextfreeblock],ebx
|
||||
mov [heapmutex],ebx
|
||||
push edi
|
||||
mov edi,[heapsmallblocks]
|
||||
mov ecx,512
|
||||
xor eax,eax
|
||||
rep stosd
|
||||
pop edi
|
||||
pop ecx
|
||||
pop ebx
|
||||
ret
|
||||
|
||||
if defined multithread
|
||||
heaplock:
|
||||
push eax
|
||||
push ebx
|
||||
push ecx
|
||||
mov eax,68
|
||||
mov ebx,1
|
||||
.loop:
|
||||
xchg ecx,[heapmutex]
|
||||
test ecx,ecx
|
||||
jz .endloop
|
||||
int 0x40 ;change task
|
||||
jmp .loop
|
||||
.endloop:
|
||||
pop ecx
|
||||
pop ebx
|
||||
pop eax
|
||||
ret
|
||||
|
||||
heapunlock:
|
||||
mov [heapmutex],dword 0
|
||||
ret
|
||||
end if
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; heap_split_block ;;
|
||||
;; Split free block to allocated block and free one. ;;
|
||||
;; input: ;;
|
||||
;; eax - size of allocated block ;;
|
||||
;; ebx - block ;;
|
||||
;; output: ;;
|
||||
;; eax - real size of allocated block ;;
|
||||
;; ebx - pointer to new block ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
heap_split_block:
|
||||
push ecx
|
||||
mov ecx,[ebx+memblock.size]
|
||||
sub ecx,16
|
||||
cmp ecx,eax
|
||||
jge .norm
|
||||
inc dword [ebx+memblock.size]
|
||||
mov eax,ecx
|
||||
xor ebx,ebx
|
||||
pop ecx
|
||||
ret
|
||||
.norm:
|
||||
add ecx,16
|
||||
mov [ebx+memblock.size],eax
|
||||
inc dword [ebx+memblock.size]
|
||||
mov [ebx+eax+memblock.prevblock],ebx
|
||||
add ebx,eax
|
||||
sub ecx,eax
|
||||
mov [ebx+memblock.size],ecx
|
||||
mov ecx,eax
|
||||
mov eax,ebx
|
||||
call heap_fix_right
|
||||
mov eax,ecx
|
||||
pop ecx
|
||||
ret
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; heap_add_free_block ;;
|
||||
;; Add free block to one of free block lists. ;;
|
||||
;; input: ;;
|
||||
;; eax - address of free block ;;
|
||||
;; output: ;;
|
||||
;; none ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
heap_add_free_block:
|
||||
cmp dword [eax+memblock.size],4096
|
||||
push ebx
|
||||
jge .bigblock
|
||||
mov ebx,[eax+memblock.size]
|
||||
shr ebx,1
|
||||
add ebx,[heapsmallblocks]
|
||||
push dword [ebx]
|
||||
pop dword [eax+memblock.nextfreeblock]
|
||||
mov [ebx],eax
|
||||
mov dword [eax+memblock.prevfreeblock],ebx
|
||||
sub dword [eax+memblock.prevfreeblock],memblock.nextfreeblock
|
||||
mov ebx,[eax+memblock.nextfreeblock]
|
||||
test ebx,ebx
|
||||
jz .no_next_block
|
||||
mov [ebx+memblock.prevfreeblock],eax
|
||||
.no_next_block:
|
||||
pop ebx
|
||||
ret
|
||||
.bigblock:
|
||||
mov ebx,[heapfreelist]
|
||||
mov [eax+memblock.nextfreeblock],ebx
|
||||
mov [heapfreelist],eax
|
||||
mov dword [eax+memblock.prevfreeblock],heapfreelist-memblock.nextfreeblock
|
||||
; mov ebx,[eax+memblock.nextfreeblock]
|
||||
test ebx,ebx
|
||||
jz .no_next_big_block
|
||||
mov [ebx+memblock.prevfreeblock],eax
|
||||
.no_next_big_block:
|
||||
pop ebx
|
||||
ret
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; heap_remove_block ;;
|
||||
;; Remove free block from the list of free blocks. ;;
|
||||
;; input: ;;
|
||||
;; eax - free block ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
heap_remove_block:
|
||||
push ebx
|
||||
push ecx
|
||||
mov ecx,[eax+memblock.prevfreeblock]
|
||||
mov ebx,[eax+memblock.nextfreeblock]
|
||||
mov [ecx+memblock.nextfreeblock],ebx
|
||||
test ebx,ebx
|
||||
jz .no_next_block
|
||||
mov [ebx+memblock.prevfreeblock],ecx
|
||||
.no_next_block:
|
||||
pop ecx
|
||||
pop ebx
|
||||
ret
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; mf_alloc
|
||||
;; allocates a block of memory in heap
|
||||
;; intput: eax: size of block
|
||||
;; output: eax: address of allocated memory block or 0 if there's no mem.
|
||||
;; allocator will not create new nodes that contain less that 8b of space,
|
||||
;; and minimal allocation is actually 16 bytes - 8 for node and 8 for user.
|
||||
;; allocator will never create non-aligned memory blocks.
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
mf_alloc:
|
||||
test eax,eax
|
||||
jg .not_null ; test that we are not allocating null size block
|
||||
xor eax,eax
|
||||
ret
|
||||
.not_null:
|
||||
if defined multithread
|
||||
call heaplock
|
||||
end if
|
||||
push edi
|
||||
; push edx
|
||||
push ecx
|
||||
push ebx
|
||||
add eax,7
|
||||
and eax,not 7 ; make sure that block size is aligned
|
||||
|
||||
lea edi,[eax+8] ; desired block size
|
||||
cmp edi,4096
|
||||
jge .general_cycle
|
||||
|
||||
mov ebx,[heapsmallblocks]
|
||||
xor ecx,ecx
|
||||
shr edi,1
|
||||
|
||||
.smallloop:
|
||||
cmp [ebx+edi],ecx
|
||||
jnz .smallblockfound
|
||||
add edi,4
|
||||
cmp edi,2048
|
||||
jl .smallloop
|
||||
lea edi,[eax+8]
|
||||
jmp .general_cycle
|
||||
|
||||
.smallblockfound:
|
||||
lea ecx,[eax+8]
|
||||
mov eax,[ebx+edi]
|
||||
call heap_remove_block
|
||||
mov ebx,eax
|
||||
xchg eax,ecx
|
||||
call heap_split_block
|
||||
test ebx,ebx
|
||||
jz .perfect_small_block
|
||||
mov eax,ebx
|
||||
call heap_add_free_block
|
||||
.perfect_small_block:
|
||||
lea eax,[ecx+8]
|
||||
jmp .ret
|
||||
|
||||
.general_cycle:
|
||||
;edi - size needed
|
||||
mov eax,[heapfreelist]
|
||||
|
||||
.loop:
|
||||
test eax,eax
|
||||
jz .new_mem
|
||||
cmp [eax+memblock.size],edi
|
||||
jge .blockfound
|
||||
mov eax,[eax+memblock.nextfreeblock]
|
||||
jmp .loop
|
||||
|
||||
.blockfound:
|
||||
call heap_remove_block
|
||||
mov ebx,eax
|
||||
mov ecx,eax
|
||||
mov eax,edi
|
||||
call heap_split_block
|
||||
test ebx,ebx
|
||||
jz .perfect_block
|
||||
mov eax,ebx
|
||||
call heap_add_free_block
|
||||
.perfect_block:
|
||||
lea eax,[ecx+8]
|
||||
.ret:
|
||||
if defined multithread
|
||||
call heapunlock
|
||||
end if
|
||||
pop ebx
|
||||
pop ecx
|
||||
; pop edx
|
||||
pop edi
|
||||
ret
|
||||
|
||||
.new_mem:
|
||||
mov eax,edi
|
||||
add eax,4095
|
||||
and eax,not 4095
|
||||
mov ecx,[heapend]
|
||||
add [heapend],eax
|
||||
push eax
|
||||
mov eax,64
|
||||
push ebx
|
||||
push ecx
|
||||
mov ecx,[heapend]
|
||||
mov ebx,1
|
||||
int 0x40
|
||||
pop ecx
|
||||
pop ebx
|
||||
pop eax
|
||||
mov [ecx+memblock.size],eax
|
||||
mov eax,[heaplastblock]
|
||||
mov [ecx+memblock.prevblock],eax
|
||||
mov [heaplastblock],ecx
|
||||
mov eax,ecx
|
||||
call heap_add_free_block
|
||||
jmp .general_cycle
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; heap_fix_right ;;
|
||||
;; input: ;;
|
||||
;; eax - pointer to free block ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
heap_fix_right:
|
||||
push ebx
|
||||
mov ebx,eax
|
||||
add ebx,[eax+memblock.size]
|
||||
cmp ebx,[heapend]
|
||||
jz .endblock
|
||||
mov [ebx+memblock.prevblock],eax
|
||||
pop ebx
|
||||
ret
|
||||
.endblock:
|
||||
mov [heaplastblock],eax
|
||||
pop ebx
|
||||
ret
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; heap_merge_left ;;
|
||||
;; input: ;;
|
||||
;; eax - pointer to free block ;;
|
||||
;; output: ;;
|
||||
;; eax - pointer to merged block ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
heap_merge_left:
|
||||
push ebx
|
||||
mov ebx,[eax+memblock.prevblock]
|
||||
test ebx,ebx
|
||||
jz .ret
|
||||
test byte [ebx+memblock.size],1
|
||||
jnz .ret
|
||||
xchg eax,ebx
|
||||
call heap_remove_block
|
||||
mov ebx,[ebx+memblock.size]
|
||||
add [eax+memblock.size],ebx
|
||||
call heap_fix_right
|
||||
.ret:
|
||||
pop ebx
|
||||
ret
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; heap_merge_right ;;
|
||||
;; input: ;;
|
||||
;; eax - pointer to free block ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
heap_merge_right:
|
||||
push ebx
|
||||
mov ebx,eax
|
||||
add ebx,[eax+memblock.size]
|
||||
cmp ebx,[heapend]
|
||||
jz .ret
|
||||
test byte [ebx+memblock.size],1
|
||||
jnz .ret
|
||||
xchg eax,ebx
|
||||
call heap_remove_block
|
||||
xchg eax,ebx
|
||||
mov ebx,[ebx+memblock.size]
|
||||
add [eax+memblock.size],ebx
|
||||
call heap_fix_right
|
||||
.ret:
|
||||
pop ebx
|
||||
ret
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; mf_free ;;
|
||||
;; input: ;;
|
||||
;; eax - pointer ;;
|
||||
;; output: ;;
|
||||
;; eax=1 - ok ;;
|
||||
;; eax=0 - failed ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
mf_free:
|
||||
test eax,eax
|
||||
jnz .no_null
|
||||
inc eax
|
||||
ret
|
||||
.no_null:
|
||||
if defined multithread
|
||||
call heaplock
|
||||
end if
|
||||
sub eax,8
|
||||
dec dword [eax+memblock.size]
|
||||
call heap_merge_left
|
||||
call heap_merge_right
|
||||
call heap_add_free_block
|
||||
.ret:
|
||||
if defined multithread
|
||||
call heapunlock
|
||||
end if
|
||||
ret
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; heap_try_reloc
|
||||
;; input:
|
||||
;; eax - address
|
||||
;; ebx - new size
|
||||
;; output:
|
||||
;; ebx=1 - ok
|
||||
;; ebx=0 - failed
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
heap_try_reloc:
|
||||
push eax
|
||||
sub eax,8
|
||||
add ebx,15
|
||||
dec dword [eax+memblock.size]
|
||||
and ebx,not 7
|
||||
cmp [eax+memblock.size],ebx
|
||||
jge .truncate
|
||||
push ebx
|
||||
mov ebx,eax
|
||||
add ebx,[eax+memblock.size]
|
||||
cmp ebx,[heapend]
|
||||
jz .fail ;todo: we can allocate new mem here
|
||||
test [ebx+memblock.size],byte 1
|
||||
jnz .fail
|
||||
xchg eax,ebx
|
||||
call heap_remove_block
|
||||
mov eax,[eax+memblock.size]
|
||||
add [ebx+memblock.size],eax
|
||||
mov eax,ebx
|
||||
call heap_fix_right
|
||||
pop ebx
|
||||
.truncate:
|
||||
xchg eax,ebx
|
||||
call heap_split_block
|
||||
test ebx,ebx
|
||||
jz .no_last_block
|
||||
mov eax,ebx
|
||||
call heap_add_free_block
|
||||
call heap_merge_right
|
||||
.no_last_block:
|
||||
xor ebx,ebx
|
||||
pop eax
|
||||
inc ebx
|
||||
ret
|
||||
.fail:
|
||||
pop ebx
|
||||
xor ebx,ebx
|
||||
pop eax
|
||||
inc dword [eax-8+memblock.size]
|
||||
ret
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; mf_realloc
|
||||
;; input:
|
||||
;; eax - pointer
|
||||
;; ebx - new size
|
||||
;; output:
|
||||
;; eax - new pointer
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
mf_realloc:
|
||||
push ebx
|
||||
if defined multithread
|
||||
call heaplock
|
||||
end if
|
||||
call heap_try_reloc
|
||||
test ebx,ebx
|
||||
jnz .ret
|
||||
;allocate new memory
|
||||
push eax
|
||||
mov eax,[esp+4]
|
||||
call mf_alloc
|
||||
test eax,eax
|
||||
jz .fail
|
||||
push esi
|
||||
push edi
|
||||
push ecx
|
||||
mov edi,eax
|
||||
mov esi,[esp+12]
|
||||
mov ecx,[esi-8+memblock.size]
|
||||
shr ecx,2
|
||||
rep movsd
|
||||
pop ecx
|
||||
pop edi
|
||||
pop esi
|
||||
xchg eax,[esp]
|
||||
call mf_free
|
||||
.fail:
|
||||
pop eax
|
||||
.ret:
|
||||
if defined multithread
|
||||
call heapunlock
|
||||
end if
|
||||
pop ebx
|
||||
ret
|
||||
;C entries
|
||||
malloc:
|
||||
mov eax,[esp+4]
|
||||
call mf_alloc
|
||||
ret
|
||||
free:
|
||||
mov eax,[esp+4]
|
||||
call mf_free
|
||||
ret
|
||||
realloc:
|
||||
mov edx,ebx
|
||||
mov eax,[esp+4]
|
||||
mov ebx,[esp+8]
|
||||
call mf_realloc
|
||||
mov ebx,edx
|
||||
ret
|
||||
section '.bss' writeable
|
||||
heapsmallblocks rd 1
|
||||
heapstart rd 1
|
||||
heapend rd 1
|
||||
heapfreelist rd 1
|
||||
heapmutex rd 1
|
||||
heaplastblock rd 1
|
Reference in New Issue
Block a user