Headers and library sources from all versions of Lightspeed C and THINK C
1
2/*
3 * alloc.c
4 *
5 * Copyright (c) 1991 Symantec Corporation. All rights reserved.
6 *
7 */
8
9#include <MacHeaders>
10
11#include "stdlib.h"
12#include "string.h"
13
14static void *alloc(short);
15static void *zoneList, *lastZone, *curZone, *startPtr;
16
17/* requests above this size just use _NewPtr */
18#define CROSSOVER 15000
19
20
21/* ---------- ANSI routines ---------- */
22
23
24void *
25malloc(size_t size)
26{
27 if (size < CROSSOVER)
28 return(alloc(size));
29 if (size > maxSize)
30 return(NULL);
31 asm {
32 move.l size,d0
33 addq.l #2,d0
34 _NewPtr
35 bmi.s @1
36 move.w #-1,(a0)+
37@1 move.l a0,d0
38 }
39}
40
41
42void *
43calloc(size_t count, size_t size)
44{
45 void *p;
46
47 if (size > maxSize)
48 return(NULL);
49 if (size & 1)
50 ++size;
51 size *= count;
52 if (size > maxSize)
53 return(NULL);
54 if (size < CROSSOVER) {
55 if (p = alloc(size))
56 memset(p, 0, size);
57 return(p);
58 }
59 asm {
60 move.l size,d0
61 addq.l #2,d0
62 _NewPtr CLEAR
63 bmi.s @1
64 move.w #-1,(a0)+
65@1 move.l a0,d0
66 }
67}
68
69
70void *
71realloc(register void *oldptr, register size_t newsize)
72{
73 register size_t oldsize, min;
74 register void *newptr;
75
76 /* handle special cases */
77
78 if (newsize > maxSize)
79 return(NULL);
80 if (oldptr == NULL)
81 return(malloc(newsize));
82 if (newsize == 0) {
83 free(oldptr);
84 return(NULL);
85 }
86
87 /* compute sizes */
88
89 if (newsize & 1)
90 ++newsize;
91 asm {
92 movea.l oldptr,a0
93 moveq #0,d0
94 move.w -(a0),d0
95 not.w d0
96 bne.s @1
97 _GetPtrSize
98@1 subq.l #2,d0
99 move.l d0,oldsize
100 }
101
102 /* decide how to resize block */
103
104 if (newsize < oldsize) {
105 min = newsize;
106 if (oldsize < CROSSOVER)
107 goto shrink;
108 if (newsize < CROSSOVER)
109 goto reallocate;
110 goto resize;
111 }
112 else if (newsize > oldsize) {
113 min = oldsize;
114 if (oldsize >= CROSSOVER)
115 goto resize;
116 if (newsize >= CROSSOVER)
117 goto reallocate;
118 goto grow;
119 }
120resized:
121 return(oldptr);
122
123 /* "shrink" - make a block (in a zone) smaller */
124
125shrink:
126 asm {
127 movea.l oldptr,a0
128 move.w -(a0),d1 ; A0 ==> this block
129 move.l oldsize,d0
130 sub.l newsize,d0 ; D0.W = # bytes to free
131 add.w d0,d1
132 move.w d1,(a0)
133 not.w d1 ; D1.W = newsize+2
134 adda.w d1,a0 ; A0 ==> new next block
135 move.w d0,(a0)
136 }
137 goto resized;
138
139 /* "grow" - make a block (in a zone) larger */
140
141grow:
142 asm {
143 movea.l oldptr,a1
144 move.w -(a1),d0 ; A1 ==> this block
145 not.w d0
146 lea 0(a1,d0.w),a0 ; A0 ==> next block
147 move.w (a0),d0
148 bmi.s @reallocate
149 move.l curZone,startPtr
150 moveq #0,d1
151@2 add.w d1,d0 ; coalesce following free blocks
152 move.w 0(a0,d0.w),d1
153 bpl.s @2
154 move.w d0,(a0) ; D0.W = # bytes available
155 move.l newsize,d1
156 sub.l oldsize,d1 ; D1.W = # bytes needed
157 adda.w d1,a0 ; A0 ==> new next block
158 sub.w d1,d0
159 blo.s @reallocate
160 beq.s @3
161 move.w d0,(a0)
162@3 sub.w d1,(a1)
163 }
164 goto resized;
165
166 /* "resize" - make a block (not in a zone) larger or smaller */
167
168resize:
169 asm {
170 movea.l oldptr,a0
171 subq.l #2,a0
172 move.l newsize,d0
173 addq.l #2,d0
174 _SetPtrSize
175 bpl.s @resized
176 }
177 goto reallocate;
178
179 /* "reallocate" - allocate new block, copy and free old block */
180
181reallocate:
182 if (newptr = malloc(newsize)) {
183 BlockMove(oldptr, newptr, min);
184 free(oldptr);
185 }
186 return(newptr);
187}
188
189
190void
191free(p)
192void *p;
193{
194 asm {
195 move.l p,d0
196 beq.s @1
197 movea.l d0,a0
198 not.w -(a0)
199 bne.s @1
200 _DisposPtr
201@1 }
202}
203
204
205/* ---------- storage allocator ---------- */
206
207
208static void *
209alloc(register short size)
210{
211 void *startZone, *nextZone;
212
213 asm {
214 addq.w #3,size
215 bclr #0,size
216 move.l curZone,startZone
217 move.l startPtr,d0
218 bne.s @try_alloc
219 }
220
221 /* add a new zone to the list */
222
223add_zone:
224 asm {
225 move.l #CROSSOVER+8,d0
226 _NewPtr
227 bmi @99 ; allocation failed
228 move.w #-1,CROSSOVER+2(a0)
229 move.l zoneList,CROSSOVER+4(a0)
230 move.l a0,zoneList
231 move.l a0,curZone
232 }
233
234 /* link last zone back to new first zone */
235
236 asm {
237 move.l lastZone,d0
238 bne.s @11
239 move.l a0,d0
240 move.l d0,lastZone
241@11 movea.l d0,a1
242 move.l a0,CROSSOVER+4(a1)
243 move.w #CROSSOVER+2,d0
244 move.w d0,(a0)
245 bra.s @90
246 }
247
248 /* advance to next zone */
249
250next_zone:
251 asm {
252 move.l nextZone,d0
253 cmp.l startZone,d0
254 beq.s @add_zone
255 move.l d0,curZone
256 move.l d0,startPtr
257 }
258
259 /* attempt allocation in current zone */
260
261try_alloc:
262 asm {
263 movea.l d0,a0
264 moveq #-1,d2 ; a very large address
265 bra.s @32
266 }
267
268 /* find next free block */
269
270 asm {
271@30 not.w d0
272 bne.s @31
273 move.l 2(a0),nextZone
274 movea.l curZone,a0 ; wrap to start of zone
275 move.l startPtr,d2
276@31 adda.w d0,a0
277 cmpa.l d2,a0
278 bhs.s @next_zone ; searched entire zone
279@32 move.w (a0),d0
280 bmi.s @30
281 }
282
283 /* coalesce free blocks */
284
285 asm {
286 moveq #0,d1
287@41 add.w d1,d0
288 move.w 0(a0,d0.w),d1
289 bpl.s @41
290 move.w d0,(a0)
291 cmp.w size,d0
292 blo.s @31 ; block too small
293 }
294
295 /* success - carve out block */
296
297 asm {
298@90 movea.l a0,a1
299 adda.w size,a1
300 move.l a1,startPtr
301 sub.w size,d0
302 beq.s @91
303 move.w d0,(a1)
304@91 not.w size
305 move.w size,(a0)+
306@99 move.l a0,d0
307 }
308}