/* * alloc.c * * Copyright (c) 1991 Symantec Corporation. All rights reserved. * */ #include #include "stdlib.h" #include "string.h" static void *alloc(short); static void *zoneList, *lastZone, *curZone, *startPtr; /* requests above this size just use _NewPtr */ #define CROSSOVER 15000 /* ---------- ANSI routines ---------- */ void * malloc(size_t size) { if (size < CROSSOVER) return(alloc(size)); if (size > maxSize) return(NULL); asm { move.l size,d0 addq.l #2,d0 _NewPtr bmi.s @1 move.w #-1,(a0)+ @1 move.l a0,d0 } } void * calloc(size_t count, size_t size) { void *p; if (size > maxSize) return(NULL); if (size & 1) ++size; size *= count; if (size > maxSize) return(NULL); if (size < CROSSOVER) { if (p = alloc(size)) memset(p, 0, size); return(p); } asm { move.l size,d0 addq.l #2,d0 _NewPtr CLEAR bmi.s @1 move.w #-1,(a0)+ @1 move.l a0,d0 } } void * realloc(register void *oldptr, register size_t newsize) { register size_t oldsize, min; register void *newptr; /* handle special cases */ if (newsize > maxSize) return(NULL); if (oldptr == NULL) return(malloc(newsize)); if (newsize == 0) { free(oldptr); return(NULL); } /* compute sizes */ if (newsize & 1) ++newsize; asm { movea.l oldptr,a0 moveq #0,d0 move.w -(a0),d0 not.w d0 bne.s @1 _GetPtrSize @1 subq.l #2,d0 move.l d0,oldsize } /* decide how to resize block */ if (newsize < oldsize) { min = newsize; if (oldsize < CROSSOVER) goto shrink; if (newsize < CROSSOVER) goto reallocate; goto resize; } else if (newsize > oldsize) { min = oldsize; if (oldsize >= CROSSOVER) goto resize; if (newsize >= CROSSOVER) goto reallocate; goto grow; } resized: return(oldptr); /* "shrink" - make a block (in a zone) smaller */ shrink: asm { movea.l oldptr,a0 move.w -(a0),d1 ; A0 ==> this block move.l oldsize,d0 sub.l newsize,d0 ; D0.W = # bytes to free add.w d0,d1 move.w d1,(a0) not.w d1 ; D1.W = newsize+2 adda.w d1,a0 ; A0 ==> new next block move.w d0,(a0) } goto resized; /* "grow" - make a block (in a zone) larger */ grow: asm { movea.l oldptr,a1 move.w -(a1),d0 ; A1 ==> this block not.w d0 lea 0(a1,d0.w),a0 ; A0 ==> next block move.w (a0),d0 bmi.s @reallocate move.l curZone,startPtr moveq #0,d1 @2 add.w d1,d0 ; coalesce following free blocks move.w 0(a0,d0.w),d1 bpl.s @2 move.w d0,(a0) ; D0.W = # bytes available move.l newsize,d1 sub.l oldsize,d1 ; D1.W = # bytes needed adda.w d1,a0 ; A0 ==> new next block sub.w d1,d0 blo.s @reallocate beq.s @3 move.w d0,(a0) @3 sub.w d1,(a1) } goto resized; /* "resize" - make a block (not in a zone) larger or smaller */ resize: asm { movea.l oldptr,a0 subq.l #2,a0 move.l newsize,d0 addq.l #2,d0 _SetPtrSize bpl.s @resized } goto reallocate; /* "reallocate" - allocate new block, copy and free old block */ reallocate: if (newptr = malloc(newsize)) { BlockMove(oldptr, newptr, min); free(oldptr); } return(newptr); } void free(p) void *p; { asm { move.l p,d0 beq.s @1 movea.l d0,a0 not.w -(a0) bne.s @1 _DisposPtr @1 } } /* ---------- storage allocator ---------- */ static void * alloc(register short size) { void *startZone, *nextZone; asm { addq.w #3,size bclr #0,size move.l curZone,startZone move.l startPtr,d0 bne.s @try_alloc } /* add a new zone to the list */ add_zone: asm { move.l #CROSSOVER+8,d0 _NewPtr bmi @99 ; allocation failed move.w #-1,CROSSOVER+2(a0) move.l zoneList,CROSSOVER+4(a0) move.l a0,zoneList move.l a0,curZone } /* link last zone back to new first zone */ asm { move.l lastZone,d0 bne.s @11 move.l a0,d0 move.l d0,lastZone @11 movea.l d0,a1 move.l a0,CROSSOVER+4(a1) move.w #CROSSOVER+2,d0 move.w d0,(a0) bra.s @90 } /* advance to next zone */ next_zone: asm { move.l nextZone,d0 cmp.l startZone,d0 beq.s @add_zone move.l d0,curZone move.l d0,startPtr } /* attempt allocation in current zone */ try_alloc: asm { movea.l d0,a0 moveq #-1,d2 ; a very large address bra.s @32 } /* find next free block */ asm { @30 not.w d0 bne.s @31 move.l 2(a0),nextZone movea.l curZone,a0 ; wrap to start of zone move.l startPtr,d2 @31 adda.w d0,a0 cmpa.l d2,a0 bhs.s @next_zone ; searched entire zone @32 move.w (a0),d0 bmi.s @30 } /* coalesce free blocks */ asm { moveq #0,d1 @41 add.w d1,d0 move.w 0(a0,d0.w),d1 bpl.s @41 move.w d0,(a0) cmp.w size,d0 blo.s @31 ; block too small } /* success - carve out block */ asm { @90 movea.l a0,a1 adda.w size,a1 move.l a1,startPtr sub.w size,d0 beq.s @91 move.w d0,(a1) @91 not.w size move.w size,(a0)+ @99 move.l a0,d0 } }