Subversion Repositories Kolibri OS

Rev

Rev 5195 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
5195 clevermous 1
; System allocator.
2
; Based on dlmalloc 2.8.6.
3
; dlmalloc is written by Doug Lea and released to the public domain.
4
 
5
; Algorithms are the same as in dlmalloc, with the following differences:
6
; * segment management uses large segments,
7
;   since segments can never be merged;
8
; * top chunk is usually large, so the code tries mmap
9
;   for chunks with size >= mmap_threshold before allocating from top;
10
; * there is additional bookkeeping for releasing physical memory
11
;   instead of relying on unmapping entire segments:
12
;   tree chunks have additional field in the end,
13
;   all recently expanded tree chunks are linked in one list for sys_trim;
14
; * there is an additional list of all mmapped chunks,
15
;   so that mspace_destroy can free everything, including mmapped chunks;
16
; * realloc and memalign can give back a space before a free chunk
17
;   (extending that chunk) even if a space is less than minimal chunk size.
18
 
19
; Statistics:
20
;   Alignment: 8 bytes
21
;   Minimum overhead per allocated chunk: 4 or 8 bytes,
22
;     depending on whether FOOTERS is defined.
23
;   Minimum allocated size: 16 bytes (including overhead)
24
; See details at http://gee.cs.oswego.edu/dl/html/malloc.html.
25
 
26
; The KolibriOS kernel provides functions similar to mmap/mremap/munmap,
27
; they are used as base for allocations.
28
 
29
FOOTERS = 0
30
;  If true, provide extra checking and dispatching by placing
31
;  information in the footers of allocated chunks. This adds
32
;  space and time overhead, but can be useful for debugging.
33
 
34
DEFAULT_MMAP_THRESHOLD = 256*1024
35
;  The request size threshold for using MMAP to directly service a
36
;  request. Requests of at least this size that cannot be allocated
37
;  using already-existing space will be serviced via mmap.  (If enough
38
;  normal freed space already exists it is used instead.)  Using mmap
39
;  segregates relatively large chunks of memory so that they can be
40
;  individually obtained and released from the host system. A request
41
;  serviced through mmap is never reused by any other request (at least
42
;  not directly; the system may just so happen to remap successive
43
;  requests to the same locations).  Segregating space in this way has
44
;  the benefits that: Mmapped space can always be individually released
45
;  back to the system, which helps keep the system level memory demands
46
;  of a long-lived program low.  Also, mapped memory doesn't become
47
;  `locked' between other chunks, as can happen with normally allocated
48
;  chunks, which means that even trimming via malloc_trim would not
49
;  release them.  However, it has the disadvantage that the space
50
;  cannot be reclaimed, consolidated, and then used to service later
51
;  requests, as happens with normal chunks.  The advantages of mmap
52
;  nearly always outweigh disadvantages for "large" chunks, but the
53
;  value of "large" may vary across systems.  The default is an
54
;  empirically derived value that works well in most systems. You can
55
;  disable mmap by setting to 0xFFFFFFFF.
56
 
57
RELEASE_CHECK_RATE = 64
58
;  The number of consolidated frees between checks to release
59
;  unused segments when freeing. When using non-contiguous segments,
60
;  especially with multiple mspaces, checking only for topmost space
61
;  doesn't always suffice to trigger trimming. To compensate for this,
62
;  free() will, with a period of MAX_RELEASE_CHECK_RATE (or the
63
;  current number of segments, if greater) try to release unused
64
;  segments to the OS when freeing chunks that result in
65
;  consolidation. The best value for this parameter is a compromise
66
;  between slowing down frees with relatively costly checks that
67
;  rarely trigger versus holding on to unused memory. To effectively
68
;  disable, set to MAX_SIZE_T. This may lead to a very slight speed
69
;  improvement at the expense of carrying around more memory.
70
 
71
DEFAULT_MSPACE_SIZE = 1024*1024
72
 
73
include 'malloc_internal.inc'
74
 
75
prologue@proc equ fpo_prologue
76
epilogue@proc equ fpo_epilogue
77
 
78
;  void* create_mspace(size_t capacity, int locked)
79
;  create_mspace creates and returns a new independent space with the
80
;  given initial capacity, or, if 0, the default mspace size.  It
81
;  returns null if there is no system memory available to create the
82
;  space.  If argument locked is non-zero, the space uses a separate
83
;  lock to control access. The capacity of the space will grow
84
;  dynamically as needed to service mspace_malloc requests.
85
proc create_mspace stdcall uses ebx, capacity, locked
86
        do_create_mspace
87
endp
88
 
89
;  void destroy_mspace(mspace msp)
90
;  destroy_mspace destroys the given space, and attempts to return all
91
;  of its memory back to the system, returning the total number of
92
;  bytes freed. After destruction, the results of access to all memory
93
;  used by the space become undefined.
94
proc destroy_mspace stdcall uses ebx, msp
95
        do_destroy_mspace
96
endp
97
 
98
 
99
macro set_default_heap
100
{
6767 clevermous 101
        mov     ebp, [default_heap]
5195 clevermous 102
.got_mspace:
103
}
104
 
105
macro set_explicit_heap
106
{
107
        mov     ebp, [msp]
108
}
109
 
110
macro mspace_adapter common_label
111
{
112
        mov     eax, [esp]
113
        mov     [esp], ebp
114
        mov     ebp, [esp+4]
115
        mov     [esp+4], eax
116
        push    ebx
117
        push    esi
118
        jmp     common_label
119
}
120
 
121
;  void* malloc(size_t bytes)
122
;  Returns a pointer to a newly allocated chunk of at least n bytes, or
123
;  null if no space is available, in which case errno is set to ENOMEM
124
;  on ANSI C systems.
125
;
126
;  If n is zero, malloc returns a minimum-sized chunk. (The minimum
127
;  size is 16 bytes on most 32bit systems, and 32 bytes on 64bit
128
;  systems.)  Note that size_t is an unsigned type, so calls with
129
;  arguments that would be negative if signed are interpreted as
130
;  requests for huge amounts of space, which will often fail. The
131
;  maximum supported value of n differs across systems, but is in all
132
;  cases less than the maximum representable value of a size_t.
133
align 16
134
proc malloc stdcall uses ebp ebx esi, bytes
135
        set_default_heap
136
        do_malloc
137
endp
138
 
139
;  void free(void* mem)
140
;  Releases the chunk of memory pointed to by mem, that had been previously
141
;  allocated using malloc or a related routine such as realloc.
142
;  It has no effect if mem is null. If mem was not malloced or already
143
;  freed, free(mem) will by default cause the current program to abort.
144
align 16
145
proc free stdcall uses ebp ebx esi, mem
146
        set_default_heap
147
        do_free
148
endp
149
 
150
;  void* calloc(size_t n_elements, size_t elem_size);
151
;  Returns a pointer to n_elements * elem_size bytes, with all locations
152
;  set to zero.
153
align 16
154
proc calloc stdcall, n_elements, elem_size
155
        do_calloc 
156
endp
157
 
158
;  void* realloc(void* oldmem, size_t bytes)
159
;  Returns a pointer to a chunk of size bytes that contains the same data
160
;  as does chunk oldmem up to the minimum of (bytes, oldmem's size) bytes, or null
161
;  if no space is available.
162
;
163
;  The returned pointer may or may not be the same as oldmem. The algorithm
164
;  prefers extending oldmem in most cases when possible, otherwise it
165
;  employs the equivalent of a malloc-copy-free sequence.
166
;
167
;  If oldmem is null, realloc is equivalent to malloc.
168
;
169
;  If space is not available, realloc returns null, errno is set (if on
170
;  ANSI) and oldmem is NOT freed.
171
;
172
;  if bytes is for fewer bytes than already held by oldmem, the newly unused
173
;  space is lopped off and freed if possible.  realloc with a size
174
;  argument of zero (re)allocates a minimum-sized chunk.
175
;
176
;  The old unix realloc convention of allowing the last-free'd chunk
177
;  to be used as an argument to realloc is not supported.
178
align 16
179
proc realloc stdcall uses ebp ebx esi, oldmem, bytes
180
        set_default_heap
181
if used mspace_realloc
182
        do_realloc , 
183
else
184
        do_realloc , 
185
end if
186
endp
187
 
188
;  void* realloc_in_place(void* oldmem, size_t bytes)
189
;  Resizes the space allocated for oldmem to size bytes, only if this can be
190
;  done without moving oldmem (i.e., only if there is adjacent space
191
;  available if bytes is greater than oldmem's current allocated size, or bytes is
192
;  less than or equal to oldmem's size). This may be used instead of plain
193
;  realloc if an alternative allocation strategy is needed upon failure
194
;  to expand space; for example, reallocation of a buffer that must be
195
;  memory-aligned or cleared. You can use realloc_in_place to trigger
196
;  these alternatives only when needed.
197
;
198
;  Returns oldmem if successful; otherwise null.
199
align 16
200
proc realloc_in_place stdcall uses ebp ebx esi, oldmem, bytes
201
        set_default_heap
202
        do_realloc_in_place
203
endp
204
 
205
;  void* memalign(size_t alignment, size_t bytes);
206
;  Returns a pointer to a newly allocated chunk of bytes argument, aligned
207
;  in accord with the alignment argument.
208
;
209
;  The alignment argument should be a power of two. If the argument is
210
;  not a power of two, the nearest greater power is used.
211
;  8-byte alignment is guaranteed by normal malloc calls, so don't
212
;  bother calling memalign with an argument of 8 or less.
213
;
214
;  Overreliance on memalign is a sure way to fragment space.
215
align 16
216
proc memalign stdcall uses ebp ebx esi, alignment, bytes
217
        set_default_heap
218
if used mspace_memalign
219
        do_memalign 
220
else
221
        do_memalign 
222
end if
223
endp
224
 
225
;  void* mspace_malloc(mspace msp, size_t bytes)
226
;  mspace_malloc behaves as malloc, but operates within
227
;  the given space.
228
align 16
229
proc mspace_malloc ;stdcall uses ebp ebx esi, msp, bytes
230
;       set_explicit_heap
231
;       do_malloc
232
        mspace_adapter malloc.got_mspace
233
endp
234
 
235
;  void mspace_free(mspace msp, void* mem)
236
;  mspace_free behaves as free, but operates within
237
;  the given space.
238
align 16
239
proc mspace_free ;stdcall uses ebp ebx esi, msp, mem
240
;       set_explicit_heap
241
;       do_free
242
        mspace_adapter free.got_mspace
243
endp
244
 
245
;  void* mspace_calloc(mspace msp, size_t n_elements, size_t elem_size)
246
;  mspace_calloc behaves as calloc, but operates within
247
;  the given space.
248
align 16
249
proc mspace_calloc stdcall, msp, n_elements, elem_size
250
        do_calloc 
251
endp
252
 
253
;  void* mspace_realloc(mspace msp, void* oldmem, size_t bytes)
254
;  mspace_realloc behaves as realloc, but operates within
255
;  the given space.
256
align 16
257
proc mspace_realloc ;stdcall uses ebp ebx esi, msp, oldmem, bytes
258
;       set_explicit_heap
259
;       do_realloc , 
260
        mspace_adapter realloc.got_mspace
261
endp
262
 
263
;  void* mspace_realloc_in_place(mspace msp, void* oldmem, size_t bytes)
264
align 16
265
proc mspace_realloc_in_place ;stdcall uses ebp ebx esi, msp, oldmem, bytes
266
;       set_explicit_heap
267
;       do_realloc_in_place
268
        mspace_adapter realloc_in_place.got_mspace
269
endp
270
 
271
;  void* mspace_memalign(mspace msp, size_t alignment, size_t bytes)
272
;  mspace_memalign behaves as memalign, but operates within
273
;  the given space.
274
align 16
275
proc mspace_memalign ;stdcall uses ebp ebx esi, msp, alignment, bytes
276
;       set_explicit_heap
277
;       do_memalign 
278
        mspace_adapter memalign.got_mspace
279
endp
280
 
281
assert MALLOC_ALIGNMENT >= 8
282
assert MALLOC_ALIGNMENT and (MALLOC_ALIGNMENT - 1) = 0
283
assert MCHUNK_SIZE and (MCHUNK_SIZE - 1) = 0
284
; in: edx = initial size of the process heap
285
macro malloc_init
286
{
287
if FOOTERS
288
        mov     eax, 26
289
        mov     ebx, 9
290
        call    FS_SYSCALL_PTR
291
        xor     eax, 0x55555555
292
        or      eax, 8
293
        and     eax, not 7
294
        mov     [malloc_magic], eax
295
end if
296
        stdcall create_mspace, edx, 1
6767 clevermous 297
        mov     [default_heap], eax
5195 clevermous 298
}
299
 
300
proc heap_corrupted
301
        sub     esp, 400h
302
        mov     eax, 9
303
        mov     ebx, esp
304
        or      ecx, -1
305
        call    FS_SYSCALL_PTR
306
        lea     esi, [ebx+10]
307
        lea     edx, [ebx+10+11]
308
        mov     eax, 63
309
        mov     ebx, 1
310
        mov     cl, '['
311
        call    FS_SYSCALL_PTR
312
@@:
313
        mov     cl, [esi]
314
        test    cl, cl
315
        jz      @f
316
        call    FS_SYSCALL_PTR
317
        inc     esi
6767 clevermous 318
        cmp     esi, edx
5195 clevermous 319
        jb      @b
320
@@:
321
        mov     esi, heap_corrupted_msg
322
@@:
323
        mov     cl, [esi]
324
        inc     esi
325
        test    cl, cl
326
        jz      @f
327
        mov     eax, 63
328
        mov     ebx, 1
329
        call    FS_SYSCALL_PTR
330
        jmp     @b
331
@@:
332
        or      eax, -1
333
        or      ebx, -1
334
        call    FS_SYSCALL_PTR
335
endp
336
 
337
heap_corrupted_msg      db      '] Heap corrupted, aborting',13,10,0