1 \ tag
: forth memory allocation
3 \
Copyright (C) 2002-2003 Stefan Reinauer
5 \
See the file
"COPYING" for further information about
6 \
the copyright and warranty status
of this
work.
9 \
7.3.3.2 memory allocation
11 \ these
need to be
initialized by
the forth kernel
by now
.
12 variable
start-mem
0 start-mem
! \
start of memory
13 variable
end-mem
0 end-mem
! \
end of memory
14 variable
free-list
0 free-list
! \
free list head
16 \ initialize
necessary variables
and write
a valid
17 \
free-list entry containing all
of the memory.
18 \
start-mem
: pointer
to start of memory.
19 \
end-mem
: pointer
to end of memory.
20 \
free-list: head
of linked
free list
22 : init
-mem
( start-addr size
)
24 start-mem
! \ write
start-mem
25 free-list ! \ write
first freelist
entry
26 2dup /n
- swap
! \ write
'len' entry
27 over cell
+ 0 swap
! \ write
'next' entry
28 + end-mem
! \ write
end-mem
31 \
--------------------------------------------------------------------
33 \ return pointer
to smallest
free block that
contains
34 \ at
least nb bytes
and the block previous
the the
35 \ actual
block. On failure
the pointer
to the smallest
38 : smallest-free-block ( nb
-- prev ptr
| 0 0 )
44 ( nb prev pp
R: best_nb best_pp
)
45 dup
@ 3 pick r
@ within
if
47 r
> r
> r
> 3drop \ drop old
smallest
48 2dup >r
>r dup
@ >r \
new smallest
51 cell
+ @ \ pp
= pp
->next
57 \
--------------------------------------------------------------------
59 \ allocate
size bytes
of memory
60 \ return pointer
to memory (or throws
an exception on failure
).
62 : alloc
-mem
( size -- addr
)
64 \ make
it legal
(and fast
) to allocate
0 bytes
67 aligned \ keep
memory aligned
.
68 dup
smallest-free-block \ look up
smallest free block.
72 -15 throw \ out
of memory
77 \
If the smallest fitting
block found is
bigger than
78 \
the size of the requested block plus
2*cellsize
we
79 \ can split
the block in 2 parts
. otherwise
return a
80 \ slightly
bigger block than
requested.
82 dup
@ ( d
->len
) 3 pick cell
+ cell
+ > if
84 \ splitting
the block in 2 pieces
.
85 \
new block = old
block + len field
+ size of requested mem
86 dup
3 pick cell
+ + ( al
-size prev addr nd
)
88 \
new block len
= old
block len
- req
. mem
size - 1 cell
89 over
@ ( al
-size prev addr nd addr
->len
)
90 4 pick
( ... al
-size )
91 cell
+ - ( al
-size prev addr nd nd nd
->len
)
92 over
! ( al
-size prev addr nd
)
94 over cell
+ @ ( al
-size prev addr nd addr
->next
)
95 \ write
addr->next
to nd
->next
96 over cell
+ ! ( al
-size prev addr nd
)
99 \ don
't split the block, it's
too small
.
103 ( al
-size prev addr nd
)
105 \
If the free block we got is
the first one rewrite
free-list
106 \ pointer instead
of the previous entry's next field.
107 rot dup 0= if drop free-list else cell+ then
108 ( al-size addr nd prev->next|fl )
110 nip cell+ \ remove al-size and skip len field of returned pointer
115 \ --------------------------------------------------------------------
117 \ free block given by addr. The length of the
118 \ given block is stored at addr - cellsize.
120 \ merge with blocks to the left and right
121 \ immediately, if they are free.
123 : free-mem ( addr len -- )
125 \ we define that it is legal to free 0-byte areas
129 \ check if the address to free is somewhere within
130 \ our available memory. This fails badly on discontigmem
131 \ architectures. If we need more RAM than fits on one
132 \ contiguous memory area we are too bloated anyways. ;)
134 dup start-mem @ end-mem @ within 0= if
135 \ ." free-mem: no such memory: 0x" u. cr
139 /n - \ get real block address
140 0 free-list @ ( addr prev l )
142 begin \ now scan the free list
143 dup 0<> if \ only check len, if block ptr != 0
144 dup dup @ cell+ + 3 pick <
155 dup 0<> if \ do we have free memory to merge with?
157 dup dup @ cell+ + 3 pick = if \ hole hit. adding bytes.
158 \ freeaddr = end of current block -> merge
160 rot @ cell+ ( prev l f->len+cellsize )
161 over @ + \ add l->len
163 swap over cell+ @ \ f = l; l = l->next;
165 \ The free list is sorted by addresses. When merging at the
166 \ start of our block we might also want to merge at the end
167 \ of it. Therefore we fall through to the next border check
168 \ instead of returning.
169 true \ fallthrough value
171 false \ no fallthrough
173 >r \ store fallthrough on ret stack
177 dup 3 pick dup @ cell+ + = if \ hole hit. real merging.
178 \ current block starts where block to free ends.
179 \ end of free block addr = current block -> merge and exit
181 2 pick dup @ ( f f->len )
182 2 pick @ cell+ + ( f newlen )
183 swap ! ( addr prev l )
189 then ( value prev->next|free-list )
191 cell+ @ rot ( prev l->next addr )
193 r> drop exit \ clean up return stack
196 r> if 3drop exit then \ fallthrough? -> exit
199 \ loose block - hang it before current.
203 \ hang block to free in front of the current entry.
204 dup 3 pick cell+ ! \ f->next = l;
205 free-list @ = if \ is block to free new list head?
210 dup 0<> if \ if (prev) prev->next=f
213 2drop \ no fixup needed. clean up.