(trivial_regexp_p): New function.
[bpt/emacs.git] / src / ralloc.c
CommitLineData
dcfdbac7 1/* Block-relocating memory allocator.
c6c5df7f 2 Copyright (C) 1993 Free Software Foundation, Inc.
dcfdbac7
JB
3
4This file is part of GNU Emacs.
5
6GNU Emacs is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 1, or (at your option)
9any later version.
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Emacs; see the file COPYING. If not, write to
18the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20/* NOTES:
21
eb8c3be9 22 Only relocate the blocs necessary for SIZE in r_alloc_sbrk,
dcfdbac7
JB
23 rather than all of them. This means allowing for a possible
24 hole between the first bloc and the end of malloc storage. */
25
2c46d29f 26#ifdef emacs
aef4d570 27
18160b98 28#include <config.h>
956ace37 29#include "lisp.h" /* Needed for VALBITS. */
2c46d29f 30
aef4d570
RM
31#undef NULL
32
f275fd9a
RS
33/* The important properties of this type are that 1) it's a pointer, and
34 2) arithmetic on it should work as if the size of the object pointed
35 to has a size of 1. */
a8c0e5ea 36#if 0 /* Arithmetic on void* is a GCC extension. */
f275fd9a
RS
37#ifdef __STDC__
38typedef void *POINTER;
39#else
1df181b6
RM
40
41#ifdef HAVE_CONFIG_H
42#include "config.h"
43#endif
44
f275fd9a 45typedef char *POINTER;
1df181b6 46
f275fd9a 47#endif
a8c0e5ea
RS
48#endif /* 0 */
49
50/* Unconditionally use char * for this. */
51typedef char *POINTER;
f275fd9a
RS
52
53typedef unsigned long SIZE;
54
2c46d29f
RS
55/* Declared in dispnew.c, this version doesn't screw up if regions
56 overlap. */
57extern void safe_bcopy ();
2c46d29f 58
aef4d570
RM
59#include "getpagesize.h"
60
61#else /* Not emacs. */
62
2c46d29f 63#include <stddef.h>
aef4d570 64
2c46d29f
RS
65typedef size_t SIZE;
66typedef void *POINTER;
aef4d570 67
aef4d570
RM
68#include <unistd.h>
69#include <malloc.h>
70#include <string.h>
71
2c46d29f 72#define safe_bcopy(x, y, z) memmove (y, x, z)
2c46d29f 73
aef4d570 74#endif /* emacs. */
dcfdbac7
JB
75
76#define NIL ((POINTER) 0)
77
2c46d29f
RS
78/* A flag to indicate whether we have initialized ralloc yet. For
79 Emacs's sake, please do not make this local to malloc_init; on some
80 machines, the dumping procedure makes all static variables
81 read-only. On these machines, the word static is #defined to be
82 the empty string, meaning that r_alloc_initialized becomes an
83 automatic variable, and loses its value each time Emacs is started up. */
84static int r_alloc_initialized = 0;
85
86static void r_alloc_init ();
dcfdbac7 87\f
956ace37
JB
88/* Declarations for working with the malloc, ralloc, and system breaks. */
89
bbc60227
RM
90/* Function to set the real break value. */
91static POINTER (*real_morecore) ();
dcfdbac7
JB
92
93/* The break value, as seen by malloc (). */
94static POINTER virtual_break_value;
95
96/* The break value, viewed by the relocatable blocs. */
97static POINTER break_value;
98
99/* The REAL (i.e., page aligned) break value of the process. */
100static POINTER page_break_value;
101
7516b7d5
RS
102/* This is the size of a page. We round memory requests to this boundary. */
103static int page_size;
104
ad3bb3d2
JB
105/* Whenever we get memory from the system, get this many extra bytes. This
106 must be a multiple of page_size. */
7516b7d5
RS
107static int extra_bytes;
108
dcfdbac7
JB
109/* Macros for rounding. Note that rounding to any value is possible
110 by changing the definition of PAGE. */
111#define PAGE (getpagesize ())
f7a009a5
RM
112#define ALIGNED(addr) (((unsigned long int) (addr) & (page_size - 1)) == 0)
113#define ROUNDUP(size) (((unsigned long int) (size) + page_size - 1) \
114 & ~(page_size - 1))
7516b7d5 115#define ROUND_TO_PAGE(addr) (addr & (~(page_size - 1)))
dcfdbac7 116\f
956ace37
JB
117/* Functions to get and return memory from the system. */
118
dcfdbac7
JB
119/* Obtain SIZE bytes of space. If enough space is not presently available
120 in our process reserve, (i.e., (page_break_value - break_value)),
98b7fe02 121 this means getting more page-aligned space from the system.
dcfdbac7 122
98b7fe02
JB
123 Return non-zero if all went well, or zero if we couldn't allocate
124 the memory. */
125static int
dcfdbac7
JB
126obtain (size)
127 SIZE size;
128{
129 SIZE already_available = page_break_value - break_value;
130
131 if (already_available < size)
132 {
956ace37 133 SIZE get = ROUNDUP (size - already_available);
7516b7d5
RS
134 /* Get some extra, so we can come here less often. */
135 get += extra_bytes;
dcfdbac7 136
bbc60227 137 if ((*real_morecore) (get) == 0)
98b7fe02 138 return 0;
dcfdbac7
JB
139
140 page_break_value += get;
141 }
142
143 break_value += size;
98b7fe02
JB
144
145 return 1;
dcfdbac7
JB
146}
147
98b7fe02
JB
148/* Obtain SIZE bytes of space and return a pointer to the new area.
149 If we could not allocate the space, return zero. */
dcfdbac7
JB
150
151static POINTER
152get_more_space (size)
153 SIZE size;
154{
155 POINTER ptr = break_value;
98b7fe02
JB
156 if (obtain (size))
157 return ptr;
158 else
159 return 0;
dcfdbac7
JB
160}
161
162/* Note that SIZE bytes of space have been relinquished by the process.
956ace37 163 If SIZE is more than a page, return the space to the system. */
dcfdbac7
JB
164
165static void
166relinquish (size)
167 SIZE size;
168{
956ace37 169 POINTER new_page_break;
7516b7d5 170 int excess;
dcfdbac7 171
956ace37
JB
172 break_value -= size;
173 new_page_break = (POINTER) ROUNDUP (break_value);
7516b7d5 174 excess = (char *) page_break_value - (char *) new_page_break;
956ace37 175
7516b7d5 176 if (excess > extra_bytes * 2)
dcfdbac7 177 {
7516b7d5
RS
178 /* Keep extra_bytes worth of empty space.
179 And don't free anything unless we can free at least extra_bytes. */
180 if ((*real_morecore) (extra_bytes - excess) == 0)
dcfdbac7
JB
181 abort ();
182
7516b7d5 183 page_break_value += extra_bytes - excess;
dcfdbac7
JB
184 }
185
956ace37
JB
186 /* Zero the space from the end of the "official" break to the actual
187 break, so that bugs show up faster. */
188 bzero (break_value, ((char *) page_break_value - (char *) break_value));
dcfdbac7
JB
189}
190\f
956ace37
JB
191/* The meat - allocating, freeing, and relocating blocs. */
192
193/* These structures are allocated in the malloc arena.
194 The linked list is kept in order of increasing '.data' members.
195 The data blocks abut each other; if b->next is non-nil, then
196 b->data + b->size == b->next->data. */
dcfdbac7
JB
197typedef struct bp
198{
199 struct bp *next;
200 struct bp *prev;
201 POINTER *variable;
202 POINTER data;
203 SIZE size;
204} *bloc_ptr;
205
206#define NIL_BLOC ((bloc_ptr) 0)
207#define BLOC_PTR_SIZE (sizeof (struct bp))
208
209/* Head and tail of the list of relocatable blocs. */
210static bloc_ptr first_bloc, last_bloc;
211
956ace37 212/* Find the bloc referenced by the address in PTR. Returns a pointer
dcfdbac7
JB
213 to that block. */
214
215static bloc_ptr
216find_bloc (ptr)
217 POINTER *ptr;
218{
219 register bloc_ptr p = first_bloc;
220
221 while (p != NIL_BLOC)
222 {
223 if (p->variable == ptr && p->data == *ptr)
224 return p;
225
226 p = p->next;
227 }
228
229 return p;
230}
231
232/* Allocate a bloc of SIZE bytes and append it to the chain of blocs.
98b7fe02
JB
233 Returns a pointer to the new bloc, or zero if we couldn't allocate
234 memory for the new block. */
dcfdbac7
JB
235
236static bloc_ptr
237get_bloc (size)
238 SIZE size;
239{
98b7fe02
JB
240 register bloc_ptr new_bloc;
241
242 if (! (new_bloc = (bloc_ptr) malloc (BLOC_PTR_SIZE))
243 || ! (new_bloc->data = get_more_space (size)))
244 {
245 if (new_bloc)
246 free (new_bloc);
247
248 return 0;
249 }
dcfdbac7 250
dcfdbac7
JB
251 new_bloc->size = size;
252 new_bloc->next = NIL_BLOC;
8c7f1e35 253 new_bloc->variable = (POINTER *) NIL;
dcfdbac7
JB
254
255 if (first_bloc)
256 {
257 new_bloc->prev = last_bloc;
258 last_bloc->next = new_bloc;
259 last_bloc = new_bloc;
260 }
261 else
262 {
263 first_bloc = last_bloc = new_bloc;
264 new_bloc->prev = NIL_BLOC;
265 }
266
267 return new_bloc;
268}
269
270/* Relocate all blocs from BLOC on upward in the list to the zone
271 indicated by ADDRESS. Direction of relocation is determined by
272 the position of ADDRESS relative to BLOC->data.
273
ad3bb3d2
JB
274 If BLOC is NIL_BLOC, nothing is done.
275
dcfdbac7
JB
276 Note that ordering of blocs is not affected by this function. */
277
278static void
279relocate_some_blocs (bloc, address)
280 bloc_ptr bloc;
281 POINTER address;
282{
ad3bb3d2 283 if (bloc != NIL_BLOC)
dcfdbac7 284 {
ad3bb3d2
JB
285 register SIZE offset = address - bloc->data;
286 register SIZE data_size = 0;
287 register bloc_ptr b;
288
289 for (b = bloc; b != NIL_BLOC; b = b->next)
290 {
291 data_size += b->size;
292 b->data += offset;
293 *b->variable = b->data;
294 }
dcfdbac7 295
ad3bb3d2
JB
296 safe_bcopy (address - offset, address, data_size);
297 }
dcfdbac7
JB
298}
299
ad3bb3d2 300
dcfdbac7
JB
301/* Free BLOC from the chain of blocs, relocating any blocs above it
302 and returning BLOC->size bytes to the free area. */
303
304static void
305free_bloc (bloc)
306 bloc_ptr bloc;
307{
308 if (bloc == first_bloc && bloc == last_bloc)
309 {
310 first_bloc = last_bloc = NIL_BLOC;
311 }
312 else if (bloc == last_bloc)
313 {
314 last_bloc = bloc->prev;
315 last_bloc->next = NIL_BLOC;
316 }
317 else if (bloc == first_bloc)
318 {
319 first_bloc = bloc->next;
320 first_bloc->prev = NIL_BLOC;
dcfdbac7
JB
321 }
322 else
323 {
324 bloc->next->prev = bloc->prev;
325 bloc->prev->next = bloc->next;
dcfdbac7
JB
326 }
327
ad3bb3d2 328 relocate_some_blocs (bloc->next, bloc->data);
dcfdbac7
JB
329 relinquish (bloc->size);
330 free (bloc);
331}
332\f
956ace37
JB
333/* Interface routines. */
334
dcfdbac7
JB
335static int use_relocatable_buffers;
336
98b7fe02 337/* Obtain SIZE bytes of storage from the free pool, or the system, as
2c46d29f 338 necessary. If relocatable blocs are in use, this means relocating
98b7fe02
JB
339 them. This function gets plugged into the GNU malloc's __morecore
340 hook.
341
7516b7d5
RS
342 We provide hysteresis, never relocating by less than extra_bytes.
343
98b7fe02
JB
344 If we're out of memory, we should return zero, to imitate the other
345 __morecore hook values - in particular, __default_morecore in the
346 GNU malloc package. */
dcfdbac7
JB
347
348POINTER
349r_alloc_sbrk (size)
350 long size;
351{
7516b7d5
RS
352 /* This is the first address not currently available for the heap. */
353 POINTER top;
354 /* Amount of empty space below that. */
89ccd65a
RS
355 /* It is not correct to use SIZE here, because that is usually unsigned.
356 ptrdiff_t would be okay, but is not always available.
357 `long' will work in all cases, in practice. */
358 long already_available;
dcfdbac7
JB
359 POINTER ptr;
360
361 if (! use_relocatable_buffers)
bbc60227 362 return (*real_morecore) (size);
dcfdbac7 363
7516b7d5
RS
364 top = first_bloc ? first_bloc->data : page_break_value;
365 already_available = (char *) top - (char *) virtual_break_value;
366
367 /* Do we not have enough gap already? */
368 if (size > 0 && already_available < size)
dcfdbac7 369 {
7516b7d5
RS
370 /* Get what we need, plus some extra so we can come here less often. */
371 SIZE get = size - already_available + extra_bytes;
372
373 if (! obtain (get))
98b7fe02
JB
374 return 0;
375
dcfdbac7 376 if (first_bloc)
ad3bb3d2 377 relocate_some_blocs (first_bloc, first_bloc->data + get);
956ace37 378
ad3bb3d2
JB
379 /* Zero out the space we just allocated, to help catch bugs
380 quickly. */
381 bzero (virtual_break_value, get);
dcfdbac7 382 }
7516b7d5
RS
383 /* Can we keep extra_bytes of gap while freeing at least extra_bytes? */
384 else if (size < 0 && already_available - size > 2 * extra_bytes)
dcfdbac7 385 {
7516b7d5
RS
386 /* Ok, do so. This is how many to free. */
387 SIZE give_back = already_available - size - extra_bytes;
388
dcfdbac7 389 if (first_bloc)
7516b7d5
RS
390 relocate_some_blocs (first_bloc, first_bloc->data - give_back);
391 relinquish (give_back);
dcfdbac7
JB
392 }
393
394 ptr = virtual_break_value;
395 virtual_break_value += size;
7516b7d5 396
dcfdbac7
JB
397 return ptr;
398}
399
400/* Allocate a relocatable bloc of storage of size SIZE. A pointer to
401 the data is returned in *PTR. PTR is thus the address of some variable
98b7fe02
JB
402 which will use the data area.
403
404 If we can't allocate the necessary memory, set *PTR to zero, and
405 return zero. */
dcfdbac7
JB
406
407POINTER
408r_alloc (ptr, size)
409 POINTER *ptr;
410 SIZE size;
411{
412 register bloc_ptr new_bloc;
413
2c46d29f
RS
414 if (! r_alloc_initialized)
415 r_alloc_init ();
416
dcfdbac7 417 new_bloc = get_bloc (size);
98b7fe02
JB
418 if (new_bloc)
419 {
420 new_bloc->variable = ptr;
421 *ptr = new_bloc->data;
422 }
423 else
424 *ptr = 0;
dcfdbac7
JB
425
426 return *ptr;
427}
428
2c46d29f
RS
429/* Free a bloc of relocatable storage whose data is pointed to by PTR.
430 Store 0 in *PTR to show there's no block allocated. */
dcfdbac7
JB
431
432void
433r_alloc_free (ptr)
434 register POINTER *ptr;
435{
436 register bloc_ptr dead_bloc;
437
dcfdbac7
JB
438 dead_bloc = find_bloc (ptr);
439 if (dead_bloc == NIL_BLOC)
440 abort ();
441
442 free_bloc (dead_bloc);
2c46d29f 443 *ptr = 0;
dcfdbac7
JB
444}
445
16a5c729 446/* Given a pointer at address PTR to relocatable data, resize it to SIZE.
98b7fe02
JB
447 Do this by shifting all blocks above this one up in memory, unless
448 SIZE is less than or equal to the current bloc size, in which case
449 do nothing.
dcfdbac7 450
98b7fe02
JB
451 Change *PTR to reflect the new bloc, and return this value.
452
453 If more memory cannot be allocated, then leave *PTR unchanged, and
454 return zero. */
dcfdbac7
JB
455
456POINTER
457r_re_alloc (ptr, size)
458 POINTER *ptr;
459 SIZE size;
460{
16a5c729 461 register bloc_ptr bloc;
dcfdbac7 462
16a5c729
JB
463 bloc = find_bloc (ptr);
464 if (bloc == NIL_BLOC)
dcfdbac7
JB
465 abort ();
466
16a5c729 467 if (size <= bloc->size)
956ace37 468 /* Wouldn't it be useful to actually resize the bloc here? */
dcfdbac7
JB
469 return *ptr;
470
98b7fe02
JB
471 if (! obtain (size - bloc->size))
472 return 0;
473
16a5c729 474 relocate_some_blocs (bloc->next, bloc->data + size);
dcfdbac7 475
16a5c729
JB
476 /* Zero out the new space in the bloc, to help catch bugs faster. */
477 bzero (bloc->data + bloc->size, size - bloc->size);
0abf54e3 478
16a5c729
JB
479 /* Indicate that this block has a new size. */
480 bloc->size = size;
dcfdbac7
JB
481
482 return *ptr;
483}
484\f
485/* The hook `malloc' uses for the function which gets more space
486 from the system. */
487extern POINTER (*__morecore) ();
488
eb8c3be9 489/* Initialize various things for memory allocation. */
dcfdbac7 490
2c46d29f
RS
491static void
492r_alloc_init ()
dcfdbac7 493{
2c46d29f 494 if (r_alloc_initialized)
dcfdbac7
JB
495 return;
496
2c46d29f 497 r_alloc_initialized = 1;
bbc60227 498 real_morecore = __morecore;
dcfdbac7 499 __morecore = r_alloc_sbrk;
8c7f1e35 500
bbc60227 501 virtual_break_value = break_value = (*real_morecore) (0);
aef4d570 502 if (break_value == NIL)
2c46d29f 503 abort ();
8c7f1e35 504
7516b7d5
RS
505 page_size = PAGE;
506 extra_bytes = ROUNDUP (50000);
507
dcfdbac7 508 page_break_value = (POINTER) ROUNDUP (break_value);
0e93a7cf
RS
509
510 /* The extra call to real_morecore guarantees that the end of the
511 address space is a multiple of page_size, even if page_size is
512 not really the page size of the system running the binary in
513 which page_size is stored. This allows a binary to be built on a
514 system with one page size and run on a system with a smaller page
515 size. */
516 (*real_morecore) (page_break_value - break_value);
517
2c46d29f
RS
518 /* Clear the rest of the last page; this memory is in our address space
519 even though it is after the sbrk value. */
0e93a7cf
RS
520 /* Doubly true, with the additional call that explicitly adds the
521 rest of that page to the address space. */
dcfdbac7 522 bzero (break_value, (page_break_value - break_value));
0e93a7cf 523 virtual_break_value = break_value = page_break_value;
dcfdbac7 524 use_relocatable_buffers = 1;
2c46d29f 525}