guile-elisp bootstrap (lisp)
[bpt/emacs.git] / src / ralloc.c
CommitLineData
177c0ea7 1/* Block-relocating memory allocator.
ba318903 2 Copyright (C) 1993, 1995, 2000-2014 Free Software Foundation, Inc.
dcfdbac7
JB
3
4This file is part of GNU Emacs.
5
9ec0b715 6GNU Emacs is free software: you can redistribute it and/or modify
dcfdbac7 7it under the terms of the GNU General Public License as published by
9ec0b715
GM
8the Free Software Foundation, either version 3 of the License, or
9(at your option) any later version.
dcfdbac7
JB
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
9ec0b715 17along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
dcfdbac7
JB
18
19/* NOTES:
20
eb8c3be9 21 Only relocate the blocs necessary for SIZE in r_alloc_sbrk,
dcfdbac7 22 rather than all of them. This means allowing for a possible
abe9ff32 23 hole between the first bloc and the end of malloc storage. */
dcfdbac7 24
2c46d29f 25#ifdef emacs
aef4d570 26
18160b98 27#include <config.h>
0328b6de 28
956ace37 29#include "lisp.h" /* Needed for VALBITS. */
a4766fd5 30#include "blockinput.h"
0a58f946 31
642a1733 32#include <unistd.h>
a8c0e5ea 33
b0119c68 34#ifdef DOUG_LEA_MALLOC
177c0ea7 35#define M_TOP_PAD -2
971de7fb 36extern int mallopt (int, int);
0a58f946 37#else /* not DOUG_LEA_MALLOC */
a2c23c92 38#ifndef SYSTEM_MALLOC
b1685c5f 39extern size_t __malloc_extra_blocks;
a2c23c92 40#endif /* SYSTEM_MALLOC */
0a58f946 41#endif /* not DOUG_LEA_MALLOC */
49081834 42
d5179acc 43#else /* not emacs */
aef4d570 44
2c46d29f 45#include <stddef.h>
aef4d570 46#include <malloc.h>
aef4d570 47
d5179acc 48#endif /* not emacs */
2c46d29f 49
0a58f946 50
d5179acc 51#include "getpagesize.h"
dcfdbac7 52
2c46d29f
RS
53/* A flag to indicate whether we have initialized ralloc yet. For
54 Emacs's sake, please do not make this local to malloc_init; on some
55 machines, the dumping procedure makes all static variables
56 read-only. On these machines, the word static is #defined to be
57 the empty string, meaning that r_alloc_initialized becomes an
0a58f946
GM
58 automatic variable, and loses its value each time Emacs is started
59 up. */
60
2c46d29f
RS
61static int r_alloc_initialized = 0;
62
971de7fb 63static void r_alloc_init (void);
0a58f946 64
dcfdbac7 65\f
956ace37
JB
66/* Declarations for working with the malloc, ralloc, and system breaks. */
67
abe9ff32 68/* Function to set the real break value. */
fcee5028 69void *(*real_morecore) (ptrdiff_t);
dcfdbac7 70
abe9ff32 71/* The break value, as seen by malloc. */
fcee5028 72static void *virtual_break_value;
dcfdbac7 73
abe9ff32
RS
74/* The address of the end of the last data in use by ralloc,
75 including relocatable blocs as well as malloc data. */
fcee5028 76static void *break_value;
dcfdbac7 77
7516b7d5
RS
78/* This is the size of a page. We round memory requests to this boundary. */
79static int page_size;
80
177c0ea7 81/* Whenever we get memory from the system, get this many extra bytes. This
ad3bb3d2 82 must be a multiple of page_size. */
7516b7d5
RS
83static int extra_bytes;
84
dcfdbac7 85/* Macros for rounding. Note that rounding to any value is possible
abe9ff32 86 by changing the definition of PAGE. */
dcfdbac7 87#define PAGE (getpagesize ())
3e0b94e7 88#define PAGE_ROUNDUP(size) (((size_t) (size) + page_size - 1) \
fcee5028 89 & ~((size_t) (page_size - 1)))
e429caa2 90
5e617bc2 91#define MEM_ALIGN sizeof (double)
fcee5028 92#define MEM_ROUNDUP(addr) (((size_t) (addr) + MEM_ALIGN - 1) \
2d7d1608 93 & ~(MEM_ALIGN - 1))
0a58f946 94
aeac019e
GM
95/* The hook `malloc' uses for the function which gets more space
96 from the system. */
97
98#ifndef SYSTEM_MALLOC
fcee5028 99extern void *(*__morecore) (ptrdiff_t);
aeac019e
GM
100#endif
101
102
e429caa2 103\f
0a58f946
GM
104/***********************************************************************
105 Implementation using sbrk
106 ***********************************************************************/
107
abe9ff32
RS
108/* Data structures of heaps and blocs. */
109
110/* The relocatable objects, or blocs, and the malloc data
111 both reside within one or more heaps.
112 Each heap contains malloc data, running from `start' to `bloc_start',
113 and relocatable objects, running from `bloc_start' to `free'.
114
115 Relocatable objects may relocate within the same heap
116 or may move into another heap; the heaps themselves may grow
117 but they never move.
118
119 We try to make just one heap and make it larger as necessary.
8e6208c5 120 But sometimes we can't do that, because we can't get contiguous
abe9ff32 121 space to add onto the heap. When that happens, we start a new heap. */
177c0ea7 122
e429caa2
KH
123typedef struct heap
124{
125 struct heap *next;
126 struct heap *prev;
abe9ff32 127 /* Start of memory range of this heap. */
fcee5028 128 void *start;
abe9ff32 129 /* End of memory range of this heap. */
fcee5028 130 void *end;
abe9ff32 131 /* Start of relocatable data in this heap. */
fcee5028 132 void *bloc_start;
abe9ff32 133 /* Start of unused space in this heap. */
fcee5028 134 void *free;
47f13333
RS
135 /* First bloc in this heap. */
136 struct bp *first_bloc;
137 /* Last bloc in this heap. */
138 struct bp *last_bloc;
e429caa2
KH
139} *heap_ptr;
140
141#define NIL_HEAP ((heap_ptr) 0)
e429caa2 142
abe9ff32
RS
143/* This is the first heap object.
144 If we need additional heap objects, each one resides at the beginning of
145 the space it covers. */
146static struct heap heap_base;
147
148/* Head and tail of the list of heaps. */
e429caa2
KH
149static heap_ptr first_heap, last_heap;
150
151/* These structures are allocated in the malloc arena.
152 The linked list is kept in order of increasing '.data' members.
153 The data blocks abut each other; if b->next is non-nil, then
177c0ea7 154 b->data + b->size == b->next->data.
49f82b3d 155
fcee5028 156 An element with variable==NULL denotes a freed block, which has not yet
f96f2c5b
JB
157 been collected. They may only appear while r_alloc_freeze_level > 0,
158 and will be freed when the arena is thawed. Currently, these blocs are
159 not reusable, while the arena is frozen. Very inefficient. */
49f82b3d 160
e429caa2
KH
161typedef struct bp
162{
163 struct bp *next;
164 struct bp *prev;
fcee5028
PE
165 void **variable;
166 void *data;
167 size_t size;
168 void *new_data; /* temporarily used for relocation */
49f82b3d 169 struct heap *heap; /* Heap this bloc is in. */
e429caa2
KH
170} *bloc_ptr;
171
172#define NIL_BLOC ((bloc_ptr) 0)
173#define BLOC_PTR_SIZE (sizeof (struct bp))
174
abe9ff32 175/* Head and tail of the list of relocatable blocs. */
e429caa2
KH
176static bloc_ptr first_bloc, last_bloc;
177
49f82b3d
RS
178static int use_relocatable_buffers;
179
180/* If >0, no relocation whatsoever takes place. */
181static int r_alloc_freeze_level;
182
dcfdbac7 183\f
956ace37
JB
184/* Functions to get and return memory from the system. */
185
abe9ff32
RS
186/* Find the heap that ADDRESS falls within. */
187
188static heap_ptr
fcee5028 189find_heap (void *address)
abe9ff32
RS
190{
191 heap_ptr heap;
192
193 for (heap = last_heap; heap; heap = heap->prev)
194 {
195 if (heap->start <= address && address <= heap->end)
196 return heap;
197 }
198
199 return NIL_HEAP;
200}
201
202/* Find SIZE bytes of space in a heap.
203 Try to get them at ADDRESS (which must fall within some heap's range)
204 if we can get that many within one heap.
205
e429caa2 206 If enough space is not presently available in our reserve, this means
8e6208c5
KH
207 getting more page-aligned space from the system. If the returned space
208 is not contiguous to the last heap, allocate a new heap, and append it
0d26e0b6 209 to the heap list.
abe9ff32 210
0d26e0b6
JB
211 obtain does not try to keep track of whether space is in use or not
212 in use. It just returns the address of SIZE bytes that fall within a
213 single heap. If you call obtain twice in a row with the same arguments,
214 you typically get the same value. It's the caller's responsibility to
215 keep track of what space is in use.
dcfdbac7 216
e429caa2
KH
217 Return the address of the space if all went well, or zero if we couldn't
218 allocate the memory. */
abe9ff32 219
fcee5028
PE
220static void *
221obtain (void *address, size_t size)
dcfdbac7 222{
e429caa2 223 heap_ptr heap;
fcee5028 224 size_t already_available;
dcfdbac7 225
abe9ff32 226 /* Find the heap that ADDRESS falls within. */
e429caa2 227 for (heap = last_heap; heap; heap = heap->prev)
dcfdbac7 228 {
e429caa2
KH
229 if (heap->start <= address && address <= heap->end)
230 break;
231 }
dcfdbac7 232
e429caa2 233 if (! heap)
1088b922 234 emacs_abort ();
dcfdbac7 235
abe9ff32
RS
236 /* If we can't fit SIZE bytes in that heap,
237 try successive later heaps. */
91a211b5 238 while (heap && (char *) address + size > (char *) heap->end)
e429caa2
KH
239 {
240 heap = heap->next;
241 if (heap == NIL_HEAP)
242 break;
243 address = heap->bloc_start;
dcfdbac7
JB
244 }
245
abe9ff32
RS
246 /* If we can't fit them within any existing heap,
247 get more space. */
e429caa2
KH
248 if (heap == NIL_HEAP)
249 {
fcee5028
PE
250 void *new = real_morecore (0);
251 size_t get;
98b7fe02 252
fcee5028 253 already_available = (char *) last_heap->end - (char *) address;
dcfdbac7 254
e429caa2
KH
255 if (new != last_heap->end)
256 {
abe9ff32
RS
257 /* Someone else called sbrk. Make a new heap. */
258
259 heap_ptr new_heap = (heap_ptr) MEM_ROUNDUP (new);
fcee5028 260 void *bloc_start = (void *) MEM_ROUNDUP ((void *) (new_heap + 1));
e429caa2 261
fcee5028 262 if (real_morecore ((char *) bloc_start - (char *) new) != new)
e429caa2
KH
263 return 0;
264
265 new_heap->start = new;
266 new_heap->end = bloc_start;
267 new_heap->bloc_start = bloc_start;
abe9ff32 268 new_heap->free = bloc_start;
e429caa2
KH
269 new_heap->next = NIL_HEAP;
270 new_heap->prev = last_heap;
47f13333
RS
271 new_heap->first_bloc = NIL_BLOC;
272 new_heap->last_bloc = NIL_BLOC;
e429caa2
KH
273 last_heap->next = new_heap;
274 last_heap = new_heap;
275
276 address = bloc_start;
277 already_available = 0;
278 }
dcfdbac7 279
abe9ff32
RS
280 /* Add space to the last heap (which we may have just created).
281 Get some extra, so we can come here less often. */
282
e429caa2 283 get = size + extra_bytes - already_available;
3e0b94e7 284 get = (char *) PAGE_ROUNDUP ((char *) last_heap->end + get)
e429caa2 285 - (char *) last_heap->end;
dcfdbac7 286
fcee5028 287 if (real_morecore (get) != last_heap->end)
e429caa2
KH
288 return 0;
289
91a211b5 290 last_heap->end = (char *) last_heap->end + get;
e429caa2
KH
291 }
292
293 return address;
294}
dcfdbac7 295
abe9ff32
RS
296/* Return unused heap space to the system
297 if there is a lot of unused space now.
298 This can make the last heap smaller;
299 it can also eliminate the last heap entirely. */
300
dcfdbac7 301static void
971de7fb 302relinquish (void)
dcfdbac7 303{
e429caa2 304 register heap_ptr h;
62aba0d4 305 ptrdiff_t excess = 0;
e429caa2 306
abe9ff32
RS
307 /* Add the amount of space beyond break_value
308 in all heaps which have extend beyond break_value at all. */
309
e429caa2
KH
310 for (h = last_heap; h && break_value < h->end; h = h->prev)
311 {
312 excess += (char *) h->end - (char *) ((break_value < h->bloc_start)
313 ? h->bloc_start : break_value);
314 }
315
fcee5028 316 if (excess > extra_bytes * 2 && real_morecore (0) == last_heap->end)
dcfdbac7 317 {
7516b7d5
RS
318 /* Keep extra_bytes worth of empty space.
319 And don't free anything unless we can free at least extra_bytes. */
e429caa2 320 excess -= extra_bytes;
dcfdbac7 321
fcee5028 322 if ((char *) last_heap->end - (char *) last_heap->bloc_start <= excess)
e429caa2 323 {
508f51f5
EZ
324 heap_ptr lh_prev;
325
98daa893
EZ
326 /* This heap should have no blocs in it. If it does, we
327 cannot return it to the system. */
47f13333
RS
328 if (last_heap->first_bloc != NIL_BLOC
329 || last_heap->last_bloc != NIL_BLOC)
98daa893 330 return;
47f13333 331
abe9ff32 332 /* Return the last heap, with its header, to the system. */
fcee5028 333 excess = (char *) last_heap->end - (char *) last_heap->start;
508f51f5
EZ
334 lh_prev = last_heap->prev;
335 /* If the system doesn't want that much memory back, leave
336 last_heap unaltered to reflect that. This can occur if
337 break_value is still within the original data segment. */
fcee5028 338 if (real_morecore (- excess) != 0)
508f51f5
EZ
339 {
340 last_heap = lh_prev;
341 last_heap->next = NIL_HEAP;
342 }
e429caa2
KH
343 }
344 else
345 {
fcee5028 346 excess = ((char *) last_heap->end
3e0b94e7 347 - (char *) PAGE_ROUNDUP ((char *) last_heap->end - excess));
508f51f5
EZ
348 /* If the system doesn't want that much memory back, leave
349 the end of the last heap unchanged to reflect that. This
350 can occur if break_value is still within the original
351 data segment. */
fcee5028 352 if (real_morecore (- excess) != 0)
508f51f5 353 last_heap->end = (char *) last_heap->end - excess;
21532667 354 }
e429caa2 355 }
dcfdbac7
JB
356}
357\f
956ace37
JB
358/* The meat - allocating, freeing, and relocating blocs. */
359
956ace37 360/* Find the bloc referenced by the address in PTR. Returns a pointer
abe9ff32 361 to that block. */
dcfdbac7
JB
362
363static bloc_ptr
fcee5028 364find_bloc (void **ptr)
dcfdbac7 365{
fcee5028 366 bloc_ptr p = first_bloc;
dcfdbac7
JB
367
368 while (p != NIL_BLOC)
369 {
747d9d14 370 /* Consistency check. Don't return inconsistent blocs.
0d26e0b6 371 Don't abort here, as callers might be expecting this, but
747d9d14
JR
372 callers that always expect a bloc to be returned should abort
373 if one isn't to avoid a memory corruption bug that is
374 difficult to track down. */
dcfdbac7
JB
375 if (p->variable == ptr && p->data == *ptr)
376 return p;
377
378 p = p->next;
379 }
380
381 return p;
382}
383
384/* Allocate a bloc of SIZE bytes and append it to the chain of blocs.
98b7fe02
JB
385 Returns a pointer to the new bloc, or zero if we couldn't allocate
386 memory for the new block. */
dcfdbac7
JB
387
388static bloc_ptr
fcee5028 389get_bloc (size_t size)
dcfdbac7 390{
fcee5028
PE
391 bloc_ptr new_bloc;
392 heap_ptr heap;
98b7fe02 393
38182d90 394 if (! (new_bloc = malloc (BLOC_PTR_SIZE))
e429caa2 395 || ! (new_bloc->data = obtain (break_value, size)))
98b7fe02 396 {
c2cd06e6 397 free (new_bloc);
98b7fe02
JB
398
399 return 0;
400 }
dcfdbac7 401
91a211b5 402 break_value = (char *) new_bloc->data + size;
e429caa2 403
dcfdbac7
JB
404 new_bloc->size = size;
405 new_bloc->next = NIL_BLOC;
fcee5028 406 new_bloc->variable = NULL;
e429caa2 407 new_bloc->new_data = 0;
dcfdbac7 408
abe9ff32
RS
409 /* Record in the heap that this space is in use. */
410 heap = find_heap (new_bloc->data);
411 heap->free = break_value;
412
47f13333
RS
413 /* Maintain the correspondence between heaps and blocs. */
414 new_bloc->heap = heap;
415 heap->last_bloc = new_bloc;
416 if (heap->first_bloc == NIL_BLOC)
417 heap->first_bloc = new_bloc;
418
abe9ff32 419 /* Put this bloc on the doubly-linked list of blocs. */
dcfdbac7
JB
420 if (first_bloc)
421 {
422 new_bloc->prev = last_bloc;
423 last_bloc->next = new_bloc;
424 last_bloc = new_bloc;
425 }
426 else
427 {
428 first_bloc = last_bloc = new_bloc;
429 new_bloc->prev = NIL_BLOC;
430 }
431
432 return new_bloc;
433}
47f13333 434\f
abe9ff32
RS
435/* Calculate new locations of blocs in the list beginning with BLOC,
436 relocating it to start at ADDRESS, in heap HEAP. If enough space is
437 not presently available in our reserve, call obtain for
177c0ea7
JB
438 more space.
439
abe9ff32
RS
440 Store the new location of each bloc in its new_data field.
441 Do not touch the contents of blocs or break_value. */
dcfdbac7 442
e429caa2 443static int
fcee5028 444relocate_blocs (bloc_ptr bloc, heap_ptr heap, void *address)
e429caa2 445{
fcee5028 446 bloc_ptr b = bloc;
ad3bb3d2 447
49f82b3d 448 /* No need to ever call this if arena is frozen, bug somewhere! */
177c0ea7 449 if (r_alloc_freeze_level)
1088b922 450 emacs_abort ();
49f82b3d 451
e429caa2
KH
452 while (b)
453 {
abe9ff32
RS
454 /* If bloc B won't fit within HEAP,
455 move to the next heap and try again. */
91a211b5 456 while (heap && (char *) address + b->size > (char *) heap->end)
e429caa2
KH
457 {
458 heap = heap->next;
459 if (heap == NIL_HEAP)
460 break;
461 address = heap->bloc_start;
462 }
dcfdbac7 463
abe9ff32
RS
464 /* If BLOC won't fit in any heap,
465 get enough new space to hold BLOC and all following blocs. */
e429caa2
KH
466 if (heap == NIL_HEAP)
467 {
fcee5028
PE
468 bloc_ptr tb = b;
469 size_t s = 0;
e429caa2 470
abe9ff32 471 /* Add up the size of all the following blocs. */
e429caa2
KH
472 while (tb != NIL_BLOC)
473 {
177c0ea7 474 if (tb->variable)
49f82b3d
RS
475 s += tb->size;
476
e429caa2
KH
477 tb = tb->next;
478 }
479
abe9ff32
RS
480 /* Get that space. */
481 address = obtain (address, s);
482 if (address == 0)
e429caa2
KH
483 return 0;
484
485 heap = last_heap;
486 }
487
abe9ff32
RS
488 /* Record the new address of this bloc
489 and update where the next bloc can start. */
e429caa2 490 b->new_data = address;
177c0ea7 491 if (b->variable)
91a211b5 492 address = (char *) address + b->size;
e429caa2
KH
493 b = b->next;
494 }
495
496 return 1;
497}
47f13333
RS
498\f
499/* Update the records of which heaps contain which blocs, starting
500 with heap HEAP and bloc BLOC. */
501
502static void
971de7fb 503update_heap_bloc_correspondence (bloc_ptr bloc, heap_ptr heap)
abe9ff32
RS
504{
505 register bloc_ptr b;
506
47f13333
RS
507 /* Initialize HEAP's status to reflect blocs before BLOC. */
508 if (bloc != NIL_BLOC && bloc->prev != NIL_BLOC && bloc->prev->heap == heap)
509 {
510 /* The previous bloc is in HEAP. */
511 heap->last_bloc = bloc->prev;
91a211b5 512 heap->free = (char *) bloc->prev->data + bloc->prev->size;
47f13333
RS
513 }
514 else
515 {
516 /* HEAP contains no blocs before BLOC. */
517 heap->first_bloc = NIL_BLOC;
518 heap->last_bloc = NIL_BLOC;
519 heap->free = heap->bloc_start;
520 }
521
abe9ff32
RS
522 /* Advance through blocs one by one. */
523 for (b = bloc; b != NIL_BLOC; b = b->next)
524 {
47f13333
RS
525 /* Advance through heaps, marking them empty,
526 till we get to the one that B is in. */
abe9ff32
RS
527 while (heap)
528 {
529 if (heap->bloc_start <= b->data && b->data <= heap->end)
530 break;
531 heap = heap->next;
47f13333
RS
532 /* We know HEAP is not null now,
533 because there has to be space for bloc B. */
534 heap->first_bloc = NIL_BLOC;
535 heap->last_bloc = NIL_BLOC;
abe9ff32
RS
536 heap->free = heap->bloc_start;
537 }
47f13333
RS
538
539 /* Update HEAP's status for bloc B. */
91a211b5 540 heap->free = (char *) b->data + b->size;
47f13333
RS
541 heap->last_bloc = b;
542 if (heap->first_bloc == NIL_BLOC)
543 heap->first_bloc = b;
544
545 /* Record that B is in HEAP. */
546 b->heap = heap;
abe9ff32
RS
547 }
548
549 /* If there are any remaining heaps and no blocs left,
47f13333 550 mark those heaps as empty. */
abe9ff32
RS
551 heap = heap->next;
552 while (heap)
553 {
47f13333
RS
554 heap->first_bloc = NIL_BLOC;
555 heap->last_bloc = NIL_BLOC;
abe9ff32
RS
556 heap->free = heap->bloc_start;
557 heap = heap->next;
558 }
559}
47f13333 560\f
abe9ff32
RS
561/* Resize BLOC to SIZE bytes. This relocates the blocs
562 that come after BLOC in memory. */
563
e429caa2 564static int
fcee5028 565resize_bloc (bloc_ptr bloc, size_t size)
dcfdbac7 566{
fcee5028 567 bloc_ptr b;
e429caa2 568 heap_ptr heap;
fcee5028
PE
569 void *address;
570 size_t old_size;
e429caa2 571
49f82b3d 572 /* No need to ever call this if arena is frozen, bug somewhere! */
177c0ea7 573 if (r_alloc_freeze_level)
1088b922 574 emacs_abort ();
49f82b3d 575
e429caa2
KH
576 if (bloc == NIL_BLOC || size == bloc->size)
577 return 1;
578
579 for (heap = first_heap; heap != NIL_HEAP; heap = heap->next)
580 {
581 if (heap->bloc_start <= bloc->data && bloc->data <= heap->end)
582 break;
583 }
584
585 if (heap == NIL_HEAP)
1088b922 586 emacs_abort ();
e429caa2
KH
587
588 old_size = bloc->size;
589 bloc->size = size;
590
abe9ff32 591 /* Note that bloc could be moved into the previous heap. */
91a211b5
GM
592 address = (bloc->prev ? (char *) bloc->prev->data + bloc->prev->size
593 : (char *) first_heap->bloc_start);
e429caa2
KH
594 while (heap)
595 {
596 if (heap->bloc_start <= address && address <= heap->end)
597 break;
598 heap = heap->prev;
599 }
600
601 if (! relocate_blocs (bloc, heap, address))
602 {
603 bloc->size = old_size;
604 return 0;
605 }
606
607 if (size > old_size)
608 {
609 for (b = last_bloc; b != bloc; b = b->prev)
610 {
49f82b3d
RS
611 if (!b->variable)
612 {
613 b->size = 0;
614 b->data = b->new_data;
177c0ea7
JB
615 }
616 else
49f82b3d 617 {
78cef877
EZ
618 if (b->new_data != b->data)
619 memmove (b->new_data, b->data, b->size);
49f82b3d
RS
620 *b->variable = b->data = b->new_data;
621 }
622 }
623 if (!bloc->variable)
624 {
625 bloc->size = 0;
626 bloc->data = bloc->new_data;
627 }
628 else
629 {
78cef877
EZ
630 if (bloc->new_data != bloc->data)
631 memmove (bloc->new_data, bloc->data, old_size);
3ce2f8ac 632 memset ((char *) bloc->new_data + old_size, 0, size - old_size);
49f82b3d 633 *bloc->variable = bloc->data = bloc->new_data;
e429caa2 634 }
e429caa2
KH
635 }
636 else
dcfdbac7 637 {
ad3bb3d2
JB
638 for (b = bloc; b != NIL_BLOC; b = b->next)
639 {
49f82b3d
RS
640 if (!b->variable)
641 {
642 b->size = 0;
643 b->data = b->new_data;
177c0ea7
JB
644 }
645 else
49f82b3d 646 {
78cef877
EZ
647 if (b->new_data != b->data)
648 memmove (b->new_data, b->data, b->size);
49f82b3d
RS
649 *b->variable = b->data = b->new_data;
650 }
ad3bb3d2 651 }
ad3bb3d2 652 }
dcfdbac7 653
47f13333 654 update_heap_bloc_correspondence (bloc, heap);
abe9ff32 655
91a211b5
GM
656 break_value = (last_bloc ? (char *) last_bloc->data + last_bloc->size
657 : (char *) first_heap->bloc_start);
e429caa2
KH
658 return 1;
659}
47f13333 660\f
abe9ff32
RS
661/* Free BLOC from the chain of blocs, relocating any blocs above it.
662 This may return space to the system. */
dcfdbac7
JB
663
664static void
971de7fb 665free_bloc (bloc_ptr bloc)
dcfdbac7 666{
47f13333 667 heap_ptr heap = bloc->heap;
36c46f8e 668 heap_ptr h;
47f13333 669
49f82b3d
RS
670 if (r_alloc_freeze_level)
671 {
fcee5028 672 bloc->variable = NULL;
49f82b3d
RS
673 return;
674 }
177c0ea7 675
e429caa2
KH
676 resize_bloc (bloc, 0);
677
dcfdbac7
JB
678 if (bloc == first_bloc && bloc == last_bloc)
679 {
680 first_bloc = last_bloc = NIL_BLOC;
681 }
682 else if (bloc == last_bloc)
683 {
684 last_bloc = bloc->prev;
685 last_bloc->next = NIL_BLOC;
686 }
687 else if (bloc == first_bloc)
688 {
689 first_bloc = bloc->next;
690 first_bloc->prev = NIL_BLOC;
dcfdbac7
JB
691 }
692 else
693 {
694 bloc->next->prev = bloc->prev;
695 bloc->prev->next = bloc->next;
dcfdbac7
JB
696 }
697
36c46f8e
EZ
698 /* Sometimes, 'heap' obtained from bloc->heap above is not really a
699 'heap' structure. It can even be beyond the current break point,
700 which will cause crashes when we dereference it below (see
701 bug#12242). Evidently, the reason is bloc allocations done while
702 use_relocatable_buffers was non-positive, because additional
703 memory we get then is not recorded in the heaps we manage. If
704 bloc->heap records such a "heap", we cannot (and don't need to)
705 update its records. So we validate the 'heap' value by making
706 sure it is one of the heaps we manage via the heaps linked list,
707 and don't touch a 'heap' that isn't found there. This avoids
708 accessing memory we know nothing about. */
709 for (h = first_heap; h != NIL_HEAP; h = h->next)
710 if (heap == h)
711 break;
712
713 if (h)
47f13333 714 {
36c46f8e
EZ
715 /* Update the records of which blocs are in HEAP. */
716 if (heap->first_bloc == bloc)
717 {
718 if (bloc->next != 0 && bloc->next->heap == heap)
719 heap->first_bloc = bloc->next;
720 else
721 heap->first_bloc = heap->last_bloc = NIL_BLOC;
722 }
723 if (heap->last_bloc == bloc)
724 {
725 if (bloc->prev != 0 && bloc->prev->heap == heap)
726 heap->last_bloc = bloc->prev;
727 else
728 heap->first_bloc = heap->last_bloc = NIL_BLOC;
729 }
47f13333
RS
730 }
731
e429caa2 732 relinquish ();
dcfdbac7
JB
733 free (bloc);
734}
735\f
956ace37
JB
736/* Interface routines. */
737
98b7fe02 738/* Obtain SIZE bytes of storage from the free pool, or the system, as
2c46d29f 739 necessary. If relocatable blocs are in use, this means relocating
98b7fe02
JB
740 them. This function gets plugged into the GNU malloc's __morecore
741 hook.
742
7516b7d5
RS
743 We provide hysteresis, never relocating by less than extra_bytes.
744
98b7fe02
JB
745 If we're out of memory, we should return zero, to imitate the other
746 __morecore hook values - in particular, __default_morecore in the
747 GNU malloc package. */
dcfdbac7 748
fcee5028 749static void *
62aba0d4 750r_alloc_sbrk (ptrdiff_t size)
dcfdbac7 751{
fcee5028
PE
752 bloc_ptr b;
753 void *address;
dcfdbac7 754
44d3dec0
RS
755 if (! r_alloc_initialized)
756 r_alloc_init ();
757
e8a02204 758 if (use_relocatable_buffers <= 0)
fcee5028 759 return real_morecore (size);
dcfdbac7 760
e429caa2
KH
761 if (size == 0)
762 return virtual_break_value;
7516b7d5 763
e429caa2 764 if (size > 0)
dcfdbac7 765 {
abe9ff32
RS
766 /* Allocate a page-aligned space. GNU malloc would reclaim an
767 extra space if we passed an unaligned one. But we could
8e6208c5 768 not always find a space which is contiguous to the previous. */
fcee5028 769 void *new_bloc_start;
e429caa2 770 heap_ptr h = first_heap;
3e0b94e7 771 size_t get = PAGE_ROUNDUP (size);
7516b7d5 772
3e0b94e7 773 address = (void *) PAGE_ROUNDUP (virtual_break_value);
e429caa2 774
abe9ff32 775 /* Search the list upward for a heap which is large enough. */
fcee5028 776 while ((char *) h->end < (char *) MEM_ROUNDUP ((char *) address + get))
e429caa2
KH
777 {
778 h = h->next;
779 if (h == NIL_HEAP)
780 break;
3e0b94e7 781 address = (void *) PAGE_ROUNDUP (h->start);
e429caa2
KH
782 }
783
abe9ff32 784 /* If not found, obtain more space. */
e429caa2
KH
785 if (h == NIL_HEAP)
786 {
787 get += extra_bytes + page_size;
788
49f82b3d 789 if (! obtain (address, get))
e429caa2 790 return 0;
98b7fe02 791
e429caa2 792 if (first_heap == last_heap)
3e0b94e7 793 address = (void *) PAGE_ROUNDUP (virtual_break_value);
e429caa2 794 else
3e0b94e7 795 address = (void *) PAGE_ROUNDUP (last_heap->start);
e429caa2
KH
796 h = last_heap;
797 }
798
fcee5028 799 new_bloc_start = (void *) MEM_ROUNDUP ((char *) address + get);
e429caa2
KH
800
801 if (first_heap->bloc_start < new_bloc_start)
802 {
49f82b3d 803 /* This is no clean solution - no idea how to do it better. */
177c0ea7 804 if (r_alloc_freeze_level)
fcee5028 805 return NULL;
49f82b3d
RS
806
807 /* There is a bug here: if the above obtain call succeeded, but the
808 relocate_blocs call below does not succeed, we need to free
809 the memory that we got with obtain. */
810
abe9ff32 811 /* Move all blocs upward. */
49f82b3d 812 if (! relocate_blocs (first_bloc, h, new_bloc_start))
e429caa2
KH
813 return 0;
814
fcee5028 815 /* Note that (char *) (h + 1) <= (char *) new_bloc_start since
e429caa2 816 get >= page_size, so the following does not destroy the heap
abe9ff32 817 header. */
e429caa2
KH
818 for (b = last_bloc; b != NIL_BLOC; b = b->prev)
819 {
78cef877
EZ
820 if (b->new_data != b->data)
821 memmove (b->new_data, b->data, b->size);
e429caa2
KH
822 *b->variable = b->data = b->new_data;
823 }
824
825 h->bloc_start = new_bloc_start;
abe9ff32 826
47f13333 827 update_heap_bloc_correspondence (first_bloc, h);
e429caa2 828 }
e429caa2
KH
829 if (h != first_heap)
830 {
831 /* Give up managing heaps below the one the new
abe9ff32 832 virtual_break_value points to. */
e429caa2
KH
833 first_heap->prev = NIL_HEAP;
834 first_heap->next = h->next;
835 first_heap->start = h->start;
836 first_heap->end = h->end;
abe9ff32 837 first_heap->free = h->free;
47f13333
RS
838 first_heap->first_bloc = h->first_bloc;
839 first_heap->last_bloc = h->last_bloc;
e429caa2
KH
840 first_heap->bloc_start = h->bloc_start;
841
842 if (first_heap->next)
843 first_heap->next->prev = first_heap;
844 else
845 last_heap = first_heap;
846 }
847
72af86bd 848 memset (address, 0, size);
dcfdbac7 849 }
e429caa2 850 else /* size < 0 */
dcfdbac7 851 {
fcee5028
PE
852 size_t excess = ((char *) first_heap->bloc_start
853 - ((char *) virtual_break_value + size));
e429caa2
KH
854
855 address = virtual_break_value;
856
857 if (r_alloc_freeze_level == 0 && excess > 2 * extra_bytes)
858 {
859 excess -= extra_bytes;
860 first_heap->bloc_start
fcee5028 861 = (void *) MEM_ROUNDUP ((char *) first_heap->bloc_start - excess);
e429caa2 862
abe9ff32 863 relocate_blocs (first_bloc, first_heap, first_heap->bloc_start);
7516b7d5 864
e429caa2
KH
865 for (b = first_bloc; b != NIL_BLOC; b = b->next)
866 {
78cef877
EZ
867 if (b->new_data != b->data)
868 memmove (b->new_data, b->data, b->size);
e429caa2
KH
869 *b->variable = b->data = b->new_data;
870 }
871 }
872
fcee5028 873 if ((char *) virtual_break_value + size < (char *) first_heap->start)
e429caa2
KH
874 {
875 /* We found an additional space below the first heap */
fcee5028 876 first_heap->start = (void *) ((char *) virtual_break_value + size);
e429caa2 877 }
dcfdbac7
JB
878 }
879
fcee5028 880 virtual_break_value = (void *) ((char *) address + size);
47f13333 881 break_value = (last_bloc
91a211b5
GM
882 ? (char *) last_bloc->data + last_bloc->size
883 : (char *) first_heap->bloc_start);
e429caa2 884 if (size < 0)
abe9ff32 885 relinquish ();
7516b7d5 886
e429caa2 887 return address;
dcfdbac7
JB
888}
889
0a58f946 890
dcfdbac7
JB
891/* Allocate a relocatable bloc of storage of size SIZE. A pointer to
892 the data is returned in *PTR. PTR is thus the address of some variable
98b7fe02
JB
893 which will use the data area.
894
49f82b3d 895 The allocation of 0 bytes is valid.
f96f2c5b
JB
896 In case r_alloc_freeze_level is set, a best fit of unused blocs could be
897 done before allocating a new area. Not yet done.
49f82b3d 898
98b7fe02
JB
899 If we can't allocate the necessary memory, set *PTR to zero, and
900 return zero. */
dcfdbac7 901
fcee5028
PE
902void *
903r_alloc (void **ptr, size_t size)
dcfdbac7 904{
fcee5028 905 bloc_ptr new_bloc;
dcfdbac7 906
2c46d29f
RS
907 if (! r_alloc_initialized)
908 r_alloc_init ();
909
abe9ff32 910 new_bloc = get_bloc (MEM_ROUNDUP (size));
98b7fe02
JB
911 if (new_bloc)
912 {
913 new_bloc->variable = ptr;
914 *ptr = new_bloc->data;
915 }
916 else
917 *ptr = 0;
dcfdbac7
JB
918
919 return *ptr;
920}
921
2c46d29f
RS
922/* Free a bloc of relocatable storage whose data is pointed to by PTR.
923 Store 0 in *PTR to show there's no block allocated. */
dcfdbac7
JB
924
925void
fcee5028 926r_alloc_free (void **ptr)
dcfdbac7 927{
fcee5028 928 bloc_ptr dead_bloc;
dcfdbac7 929
44d3dec0
RS
930 if (! r_alloc_initialized)
931 r_alloc_init ();
932
dcfdbac7
JB
933 dead_bloc = find_bloc (ptr);
934 if (dead_bloc == NIL_BLOC)
1088b922 935 emacs_abort (); /* Double free? PTR not originally used to allocate? */
dcfdbac7
JB
936
937 free_bloc (dead_bloc);
2c46d29f 938 *ptr = 0;
719b242f 939
d5179acc 940#ifdef emacs
719b242f 941 refill_memory_reserve ();
d5179acc 942#endif
dcfdbac7
JB
943}
944
16a5c729 945/* Given a pointer at address PTR to relocatable data, resize it to SIZE.
98b7fe02
JB
946 Do this by shifting all blocks above this one up in memory, unless
947 SIZE is less than or equal to the current bloc size, in which case
948 do nothing.
dcfdbac7 949
f96f2c5b 950 In case r_alloc_freeze_level is set, a new bloc is allocated, and the
8e6208c5 951 memory copied to it. Not very efficient. We could traverse the
49f82b3d
RS
952 bloc_list for a best fit of free blocs first.
953
98b7fe02
JB
954 Change *PTR to reflect the new bloc, and return this value.
955
956 If more memory cannot be allocated, then leave *PTR unchanged, and
957 return zero. */
dcfdbac7 958
fcee5028
PE
959void *
960r_re_alloc (void **ptr, size_t size)
dcfdbac7 961{
fcee5028 962 bloc_ptr bloc;
dcfdbac7 963
44d3dec0
RS
964 if (! r_alloc_initialized)
965 r_alloc_init ();
966
49f82b3d
RS
967 if (!*ptr)
968 return r_alloc (ptr, size);
177c0ea7 969 if (!size)
49f82b3d
RS
970 {
971 r_alloc_free (ptr);
972 return r_alloc (ptr, 0);
973 }
974
16a5c729
JB
975 bloc = find_bloc (ptr);
976 if (bloc == NIL_BLOC)
1088b922 977 emacs_abort (); /* Already freed? PTR not originally used to allocate? */
dcfdbac7 978
177c0ea7 979 if (size < bloc->size)
49f82b3d
RS
980 {
981 /* Wouldn't it be useful to actually resize the bloc here? */
982 /* I think so too, but not if it's too expensive... */
177c0ea7
JB
983 if ((bloc->size - MEM_ROUNDUP (size) >= page_size)
984 && r_alloc_freeze_level == 0)
49f82b3d
RS
985 {
986 resize_bloc (bloc, MEM_ROUNDUP (size));
987 /* Never mind if this fails, just do nothing... */
988 /* It *should* be infallible! */
989 }
990 }
991 else if (size > bloc->size)
992 {
993 if (r_alloc_freeze_level)
994 {
995 bloc_ptr new_bloc;
996 new_bloc = get_bloc (MEM_ROUNDUP (size));
997 if (new_bloc)
998 {
999 new_bloc->variable = ptr;
1000 *ptr = new_bloc->data;
fcee5028 1001 bloc->variable = NULL;
49f82b3d
RS
1002 }
1003 else
fcee5028 1004 return NULL;
49f82b3d 1005 }
177c0ea7 1006 else
49f82b3d
RS
1007 {
1008 if (! resize_bloc (bloc, MEM_ROUNDUP (size)))
fcee5028 1009 return NULL;
49f82b3d
RS
1010 }
1011 }
dcfdbac7
JB
1012 return *ptr;
1013}
81bd58e8 1014
dec41418
RS
1015
1016#if defined (emacs) && defined (DOUG_LEA_MALLOC)
1017
1018/* Reinitialize the morecore hook variables after restarting a dumped
1019 Emacs. This is needed when using Doug Lea's malloc from GNU libc. */
1020void
971de7fb 1021r_alloc_reinit (void)
dec41418
RS
1022{
1023 /* Only do this if the hook has been reset, so that we don't get an
1024 infinite loop, in case Emacs was linked statically. */
1025 if (__morecore != r_alloc_sbrk)
1026 {
1027 real_morecore = __morecore;
1028 __morecore = r_alloc_sbrk;
1029 }
1030}
0a58f946
GM
1031
1032#endif /* emacs && DOUG_LEA_MALLOC */
dec41418 1033
e429caa2 1034#ifdef DEBUG
0a58f946 1035
e429caa2
KH
1036#include <assert.h>
1037
44d3dec0 1038void
268c2c36 1039r_alloc_check (void)
e429caa2 1040{
6d16dd06
RS
1041 int found = 0;
1042 heap_ptr h, ph = 0;
1043 bloc_ptr b, pb = 0;
1044
1045 if (!r_alloc_initialized)
1046 return;
1047
1048 assert (first_heap);
fcee5028
PE
1049 assert (last_heap->end <= (void *) sbrk (0));
1050 assert ((void *) first_heap < first_heap->start);
6d16dd06
RS
1051 assert (first_heap->start <= virtual_break_value);
1052 assert (virtual_break_value <= first_heap->end);
1053
1054 for (h = first_heap; h; h = h->next)
1055 {
1056 assert (h->prev == ph);
3e0b94e7 1057 assert ((void *) PAGE_ROUNDUP (h->end) == h->end);
40f3f04b
RS
1058#if 0 /* ??? The code in ralloc.c does not really try to ensure
1059 the heap start has any sort of alignment.
1060 Perhaps it should. */
fcee5028 1061 assert ((void *) MEM_ROUNDUP (h->start) == h->start);
40f3f04b 1062#endif
fcee5028 1063 assert ((void *) MEM_ROUNDUP (h->bloc_start) == h->bloc_start);
6d16dd06
RS
1064 assert (h->start <= h->bloc_start && h->bloc_start <= h->end);
1065
1066 if (ph)
1067 {
1068 assert (ph->end < h->start);
fcee5028 1069 assert (h->start <= (void *) h && (void *) (h + 1) <= h->bloc_start);
6d16dd06
RS
1070 }
1071
1072 if (h->bloc_start <= break_value && break_value <= h->end)
1073 found = 1;
1074
1075 ph = h;
1076 }
1077
1078 assert (found);
1079 assert (last_heap == ph);
1080
1081 for (b = first_bloc; b; b = b->next)
1082 {
1083 assert (b->prev == pb);
fcee5028
PE
1084 assert ((void *) MEM_ROUNDUP (b->data) == b->data);
1085 assert ((size_t) MEM_ROUNDUP (b->size) == b->size);
6d16dd06
RS
1086
1087 ph = 0;
1088 for (h = first_heap; h; h = h->next)
1089 {
1090 if (h->bloc_start <= b->data && b->data + b->size <= h->end)
1091 break;
1092 ph = h;
1093 }
1094
1095 assert (h);
1096
1097 if (pb && pb->data + pb->size != b->data)
1098 {
1099 assert (ph && b->data == h->bloc_start);
1100 while (ph)
1101 {
1102 if (ph->bloc_start <= pb->data
1103 && pb->data + pb->size <= ph->end)
1104 {
1105 assert (pb->data + pb->size + b->size > ph->end);
1106 break;
1107 }
1108 else
1109 {
1110 assert (ph->bloc_start + b->size > ph->end);
1111 }
1112 ph = ph->prev;
1113 }
1114 }
1115 pb = b;
1116 }
1117
1118 assert (last_bloc == pb);
1119
1120 if (last_bloc)
1121 assert (last_bloc->data + last_bloc->size == break_value);
1122 else
1123 assert (first_heap->bloc_start == break_value);
e429caa2 1124}
0a58f946 1125
e429caa2 1126#endif /* DEBUG */
0a58f946 1127
baae5c2d
JR
1128/* Update the internal record of which variable points to some data to NEW.
1129 Used by buffer-swap-text in Emacs to restore consistency after it
1130 swaps the buffer text between two buffer objects. The OLD pointer
1131 is checked to ensure that memory corruption does not occur due to
1132 misuse. */
1133void
fcee5028 1134r_alloc_reset_variable (void **old, void **new)
baae5c2d
JR
1135{
1136 bloc_ptr bloc = first_bloc;
1137
1138 /* Find the bloc that corresponds to the data pointed to by pointer.
1139 find_bloc cannot be used, as it has internal consistency checks
0d26e0b6 1140 which fail when the variable needs resetting. */
baae5c2d
JR
1141 while (bloc != NIL_BLOC)
1142 {
1143 if (bloc->data == *new)
1144 break;
1145
1146 bloc = bloc->next;
1147 }
1148
1149 if (bloc == NIL_BLOC || bloc->variable != old)
1088b922 1150 emacs_abort (); /* Already freed? OLD not originally used to allocate? */
baae5c2d
JR
1151
1152 /* Update variable to point to the new location. */
1153 bloc->variable = new;
1154}
0a58f946 1155
52c55cc7
EZ
1156void
1157r_alloc_inhibit_buffer_relocation (int inhibit)
1158{
e8a02204
EZ
1159 if (use_relocatable_buffers > 1)
1160 use_relocatable_buffers = 1;
291d430f 1161 if (inhibit)
291d430f 1162 use_relocatable_buffers--;
e8a02204
EZ
1163 else if (use_relocatable_buffers < 1)
1164 use_relocatable_buffers++;
52c55cc7
EZ
1165}
1166
0a58f946
GM
1167\f
1168/***********************************************************************
1169 Initialization
1170 ***********************************************************************/
1171
0a58f946
GM
1172/* Initialize various things for memory allocation. */
1173
1174static void
971de7fb 1175r_alloc_init (void)
0a58f946
GM
1176{
1177 if (r_alloc_initialized)
1178 return;
0a58f946 1179 r_alloc_initialized = 1;
177c0ea7 1180
a2c23c92
DL
1181 page_size = PAGE;
1182#ifndef SYSTEM_MALLOC
0a58f946
GM
1183 real_morecore = __morecore;
1184 __morecore = r_alloc_sbrk;
1185
1186 first_heap = last_heap = &heap_base;
1187 first_heap->next = first_heap->prev = NIL_HEAP;
1188 first_heap->start = first_heap->bloc_start
fcee5028
PE
1189 = virtual_break_value = break_value = real_morecore (0);
1190 if (break_value == NULL)
1088b922 1191 emacs_abort ();
0a58f946 1192
3e0b94e7 1193 extra_bytes = PAGE_ROUNDUP (50000);
a2c23c92 1194#endif
0a58f946
GM
1195
1196#ifdef DOUG_LEA_MALLOC
4d7e6e51 1197 block_input ();
1673df2e 1198 mallopt (M_TOP_PAD, 64 * 4096);
4d7e6e51 1199 unblock_input ();
0a58f946 1200#else
a2c23c92 1201#ifndef SYSTEM_MALLOC
45ba16c7
EZ
1202 /* Give GNU malloc's morecore some hysteresis so that we move all
1203 the relocatable blocks much less often. The number used to be
1204 64, but alloc.c would override that with 32 in code that was
1205 removed when SYNC_INPUT became the only input handling mode.
9b318728 1206 That code was conditioned on !DOUG_LEA_MALLOC, so the call to
45ba16c7
EZ
1207 mallopt above is left unchanged. (Actually, I think there's no
1208 system nowadays that uses DOUG_LEA_MALLOC and also uses
1209 REL_ALLOC.) */
1210 __malloc_extra_blocks = 32;
0a58f946 1211#endif
a2c23c92 1212#endif
0a58f946 1213
5ad25b24 1214#ifndef SYSTEM_MALLOC
3e0b94e7 1215 first_heap->end = (void *) PAGE_ROUNDUP (first_heap->start);
0a58f946
GM
1216
1217 /* The extra call to real_morecore guarantees that the end of the
1218 address space is a multiple of page_size, even if page_size is
1219 not really the page size of the system running the binary in
1220 which page_size is stored. This allows a binary to be built on a
1221 system with one page size and run on a system with a smaller page
1222 size. */
fcee5028 1223 real_morecore ((char *) first_heap->end - (char *) first_heap->start);
0a58f946
GM
1224
1225 /* Clear the rest of the last page; this memory is in our address space
1226 even though it is after the sbrk value. */
1227 /* Doubly true, with the additional call that explicitly adds the
1228 rest of that page to the address space. */
72af86bd
AS
1229 memset (first_heap->start, 0,
1230 (char *) first_heap->end - (char *) first_heap->start);
0a58f946 1231 virtual_break_value = break_value = first_heap->bloc_start = first_heap->end;
a2c23c92 1232#endif
177c0ea7 1233
0a58f946
GM
1234 use_relocatable_buffers = 1;
1235}