realloc.c revision 1.1.1.1 1 1.1 christos /* $NetBSD: realloc.c,v 1.1.1.1 2016/01/13 21:42:18 christos Exp $ */
2 1.1 christos
3 1.1 christos /* Change the size of a block allocated by `malloc'.
4 1.1 christos Copyright 1990, 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
5 1.1 christos Written May 1989 by Mike Haertel.
6 1.1 christos
7 1.1 christos This library is free software; you can redistribute it and/or
8 1.1 christos modify it under the terms of the GNU Library General Public License as
9 1.1 christos published by the Free Software Foundation; either version 2 of the
10 1.1 christos License, or (at your option) any later version.
11 1.1 christos
12 1.1 christos This library is distributed in the hope that it will be useful,
13 1.1 christos but WITHOUT ANY WARRANTY; without even the implied warranty of
14 1.1 christos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 1.1 christos Library General Public License for more details.
16 1.1 christos
17 1.1 christos You should have received a copy of the GNU Library General Public
18 1.1 christos License along with this library; see the file COPYING.LIB. If
19 1.1 christos not, write to the Free Software Foundation, Inc., 675 Mass Ave,
20 1.1 christos Cambridge, MA 02139, USA.
21 1.1 christos
22 1.1 christos The author may be reached (Email) at the address mike (at) ai.mit.edu,
23 1.1 christos or (US mail) as Mike Haertel c/o Free Software Foundation. */
24 1.1 christos
25 1.1 christos #ifndef _MALLOC_INTERNAL
26 1.1 christos #define _MALLOC_INTERNAL
27 1.1 christos #include <malloc.h>
28 1.1 christos #endif
29 1.1 christos
30 1.1 christos #if (defined (MEMMOVE_MISSING) || \
31 1.1 christos !defined(_LIBC) && !defined(STDC_HEADERS) && !defined(USG))
32 1.1 christos
33 1.1 christos /* Snarfed directly from Emacs src/dispnew.c:
34 1.1 christos XXX Should use system bcopy if it handles overlap. */
35 1.1 christos #ifndef emacs
36 1.1 christos
37 1.1 christos /* Like bcopy except never gets confused by overlap. */
38 1.1 christos
39 1.1 christos static void
40 1.1 christos safe_bcopy (from, to, size)
41 1.1 christos char *from, *to;
42 1.1 christos int size;
43 1.1 christos {
44 1.1 christos if (size <= 0 || from == to)
45 1.1 christos return;
46 1.1 christos
47 1.1 christos /* If the source and destination don't overlap, then bcopy can
48 1.1 christos handle it. If they do overlap, but the destination is lower in
49 1.1 christos memory than the source, we'll assume bcopy can handle that. */
50 1.1 christos if (to < from || from + size <= to)
51 1.1 christos bcopy (from, to, size);
52 1.1 christos
53 1.1 christos /* Otherwise, we'll copy from the end. */
54 1.1 christos else
55 1.1 christos {
56 1.1 christos register char *endf = from + size;
57 1.1 christos register char *endt = to + size;
58 1.1 christos
59 1.1 christos /* If TO - FROM is large, then we should break the copy into
60 1.1 christos nonoverlapping chunks of TO - FROM bytes each. However, if
61 1.1 christos TO - FROM is small, then the bcopy function call overhead
62 1.1 christos makes this not worth it. The crossover point could be about
63 1.1 christos anywhere. Since I don't think the obvious copy loop is too
64 1.1 christos bad, I'm trying to err in its favor. */
65 1.1 christos if (to - from < 64)
66 1.1 christos {
67 1.1 christos do
68 1.1 christos *--endt = *--endf;
69 1.1 christos while (endf != from);
70 1.1 christos }
71 1.1 christos else
72 1.1 christos {
73 1.1 christos for (;;)
74 1.1 christos {
75 1.1 christos endt -= (to - from);
76 1.1 christos endf -= (to - from);
77 1.1 christos
78 1.1 christos if (endt < to)
79 1.1 christos break;
80 1.1 christos
81 1.1 christos bcopy (endf, endt, to - from);
82 1.1 christos }
83 1.1 christos
84 1.1 christos /* If SIZE wasn't a multiple of TO - FROM, there will be a
85 1.1 christos little left over. The amount left over is
86 1.1 christos (endt + (to - from)) - to, which is endt - from. */
87 1.1 christos bcopy (from, to, endt - from);
88 1.1 christos }
89 1.1 christos }
90 1.1 christos }
91 1.1 christos #endif /* Not emacs. */
92 1.1 christos
93 1.1 christos #define memmove(to, from, size) safe_bcopy ((from), (to), (size))
94 1.1 christos
95 1.1 christos #endif
96 1.1 christos
97 1.1 christos
98 1.1 christos #define min(A, B) ((A) < (B) ? (A) : (B))
99 1.1 christos
100 1.1 christos /* Debugging hook for realloc. */
101 1.1 christos __ptr_t (*__realloc_hook) __P ((__ptr_t __ptr, __malloc_size_t __size));
102 1.1 christos
103 1.1 christos /* Resize the given region to the new size, returning a pointer
104 1.1 christos to the (possibly moved) region. This is optimized for speed;
105 1.1 christos some benchmarks seem to indicate that greater compactness is
106 1.1 christos achieved by unconditionally allocating and copying to a
107 1.1 christos new region. This module has incestuous knowledge of the
108 1.1 christos internals of both free and malloc. */
109 1.1 christos __ptr_t
110 1.1 christos realloc (ptr, size)
111 1.1 christos __ptr_t ptr;
112 1.1 christos __malloc_size_t size;
113 1.1 christos {
114 1.1 christos __ptr_t result;
115 1.1 christos int type;
116 1.1 christos __malloc_size_t block, blocks, oldlimit;
117 1.1 christos
118 1.1 christos if (size == 0)
119 1.1 christos {
120 1.1 christos free (ptr);
121 1.1 christos return malloc (0);
122 1.1 christos }
123 1.1 christos else if (ptr == NULL)
124 1.1 christos return malloc (size);
125 1.1 christos
126 1.1 christos if (__realloc_hook != NULL)
127 1.1 christos return (*__realloc_hook) (ptr, size);
128 1.1 christos
129 1.1 christos block = BLOCK (ptr);
130 1.1 christos
131 1.1 christos type = _heapinfo[block].busy.type;
132 1.1 christos switch (type)
133 1.1 christos {
134 1.1 christos case 0:
135 1.1 christos /* Maybe reallocate a large block to a small fragment. */
136 1.1 christos if (size <= BLOCKSIZE / 2)
137 1.1 christos {
138 1.1 christos result = malloc (size);
139 1.1 christos if (result != NULL)
140 1.1 christos {
141 1.1 christos memcpy (result, ptr, size);
142 1.1 christos _free_internal (ptr);
143 1.1 christos return result;
144 1.1 christos }
145 1.1 christos }
146 1.1 christos
147 1.1 christos /* The new size is a large allocation as well;
148 1.1 christos see if we can hold it in place. */
149 1.1 christos blocks = BLOCKIFY (size);
150 1.1 christos if (blocks < _heapinfo[block].busy.info.size)
151 1.1 christos {
152 1.1 christos /* The new size is smaller; return
153 1.1 christos excess memory to the free list. */
154 1.1 christos _heapinfo[block + blocks].busy.type = 0;
155 1.1 christos _heapinfo[block + blocks].busy.info.size
156 1.1 christos = _heapinfo[block].busy.info.size - blocks;
157 1.1 christos _heapinfo[block].busy.info.size = blocks;
158 1.1 christos /* We have just created a new chunk by splitting a chunk in two.
159 1.1 christos Now we will free this chunk; increment the statistics counter
160 1.1 christos so it doesn't become wrong when _free_internal decrements it. */
161 1.1 christos ++_chunks_used;
162 1.1 christos _free_internal (ADDRESS (block + blocks));
163 1.1 christos result = ptr;
164 1.1 christos }
165 1.1 christos else if (blocks == _heapinfo[block].busy.info.size)
166 1.1 christos /* No size change necessary. */
167 1.1 christos result = ptr;
168 1.1 christos else
169 1.1 christos {
170 1.1 christos /* Won't fit, so allocate a new region that will.
171 1.1 christos Free the old region first in case there is sufficient
172 1.1 christos adjacent free space to grow without moving. */
173 1.1 christos blocks = _heapinfo[block].busy.info.size;
174 1.1 christos /* Prevent free from actually returning memory to the system. */
175 1.1 christos oldlimit = _heaplimit;
176 1.1 christos _heaplimit = 0;
177 1.1 christos _free_internal (ptr);
178 1.1 christos _heaplimit = oldlimit;
179 1.1 christos result = malloc (size);
180 1.1 christos if (result == NULL)
181 1.1 christos {
182 1.1 christos /* Now we're really in trouble. We have to unfree
183 1.1 christos the thing we just freed. Unfortunately it might
184 1.1 christos have been coalesced with its neighbors. */
185 1.1 christos if (_heapindex == block)
186 1.1 christos (void) malloc (blocks * BLOCKSIZE);
187 1.1 christos else
188 1.1 christos {
189 1.1 christos __ptr_t previous = malloc ((block - _heapindex) * BLOCKSIZE);
190 1.1 christos (void) malloc (blocks * BLOCKSIZE);
191 1.1 christos _free_internal (previous);
192 1.1 christos }
193 1.1 christos return NULL;
194 1.1 christos }
195 1.1 christos if (ptr != result)
196 1.1 christos memmove (result, ptr, blocks * BLOCKSIZE);
197 1.1 christos }
198 1.1 christos break;
199 1.1 christos
200 1.1 christos default:
201 1.1 christos /* Old size is a fragment; type is logarithm
202 1.1 christos to base two of the fragment size. */
203 1.1 christos if (size > (__malloc_size_t) (1 << (type - 1)) &&
204 1.1 christos size <= (__malloc_size_t) (1 << type))
205 1.1 christos /* The new size is the same kind of fragment. */
206 1.1 christos result = ptr;
207 1.1 christos else
208 1.1 christos {
209 1.1 christos /* The new size is different; allocate a new space,
210 1.1 christos and copy the lesser of the new size and the old. */
211 1.1 christos result = malloc (size);
212 1.1 christos if (result == NULL)
213 1.1 christos return NULL;
214 1.1 christos memcpy (result, ptr, min (size, (__malloc_size_t) 1 << type));
215 1.1 christos free (ptr);
216 1.1 christos }
217 1.1 christos break;
218 1.1 christos }
219 1.1 christos
220 1.1 christos return result;
221 1.1 christos }
222