summaryrefslogtreecommitdiff
path: root/allochblk.c
diff options
context:
space:
mode:
Diffstat (limited to 'allochblk.c')
-rw-r--r--allochblk.c155
1 files changed, 51 insertions, 104 deletions
diff --git a/allochblk.c b/allochblk.c
index 1dcf581b..48212b7f 100644
--- a/allochblk.c
+++ b/allochblk.c
@@ -38,61 +38,24 @@ struct hblk *GC_savhbp = (struct hblk *)0; /* heap block preceding next */
/* block to be examined by */
/* GC_allochblk. */
-/*
- * Return TRUE if there is a heap block sufficient for object size sz,
- * FALSE otherwise. Advance GC_savhbp to point to the block prior to the
- * first such block.
- */
-bool GC_sufficient_hb(sz, kind)
-word sz;
+/* Initialize hdr for a block containing the indicated size and */
+/* kind of objects. */
+static setup_header(hhdr, sz, kind)
+register hdr * hhdr;
+word sz; /* object size in words */
int kind;
{
-register struct hblk *hbp;
-register hdr * hhdr;
-struct hblk *prevhbp;
-signed_word size_needed;
-signed_word size_avail;
-bool first_time = TRUE;
-
- size_needed = WORDS_TO_BYTES(sz);
- size_needed = (size_needed+HDR_BYTES+HBLKSIZE-1) & ~HBLKMASK;
-# ifdef DEBUG
- GC_printf("GC_sufficient_hb: sz = %ld, size_needed = 0x%lx\n",
- (long)sz, (unsigned long)size_needed);
-# endif
- /* search for a big enough block in free list */
- hbp = GC_savhbp;
- hhdr = HDR(hbp);
- for(;;) {
- prevhbp = hbp;
- hbp = ((prevhbp == (struct hblk *)0)
- ? GC_hblkfreelist
- : hhdr->hb_next);
- hhdr = HDR(hbp);
-
- if( prevhbp == GC_savhbp && !first_time) {
- /* no sufficiently big blocks on free list */
- return(FALSE);
- }
- first_time = 0;
- if( hbp == (struct hblk *)0 ) continue;
- size_avail = hhdr->hb_sz;
- if ( kind != PTRFREE || size_needed > MAX_BLACK_LIST_ALLOC) {
- struct hblk * thishbp;
- struct hblk * lasthbp = hbp;
-
- while ((ptr_t)lasthbp - (ptr_t)hbp < size_avail
- && (thishbp = GC_is_black_listed(lasthbp,
- (word)size_needed))) {
- lasthbp = thishbp;
- }
- size_avail -= (ptr_t)lasthbp - (ptr_t)hbp;
- }
- if( size_avail >= size_needed ) {
- GC_savhbp = prevhbp;
- return(TRUE);
- }
- }
+ /* Set size, kind and mark proc fields */
+ hhdr -> hb_sz = sz;
+ hhdr -> hb_obj_kind = kind;
+ hhdr -> hb_mark_proc = GC_obj_kinds[kind].ok_mark_proc;
+
+ /* Add description of valid object pointers */
+ GC_add_map_entry(sz);
+ hhdr -> hb_map = GC_obj_map[sz > MAXOBJSZ? 0 : sz];
+
+ /* Clear mark bits */
+ GC_clear_hdr_marks(hhdr);
}
/*
@@ -134,31 +97,10 @@ int kind;
hhdr = HDR(hbp);
if( prevhbp == GC_savhbp && !first_time) {
- /* no sufficiently big blocks on free list, */
- /* let thishbp --> a newly-allocated block, */
- /* free it (to merge into existing block */
- /* list) and start the search again, this */
- /* time with guaranteed success. */
- word size_to_get = size_needed + GC_hincr * HBLKSIZE;
-
- if (! GC_expand_hp_inner(divHBLKSZ(size_to_get))) {
- if (! GC_expand_hp_inner(divHBLKSZ((word)size_needed)))
- {
- /* GC_printf("Out of Memory! Giving up ...\n"); */
- /* There are other things we could try. It */
- /* would probably be reasonable to clear */
- /* black lists at tthis point. */
- return(0);
- } else {
- WARN("Out of Memory! Trying to continue ...\n");
- GC_gcollect_inner(TRUE);
- }
- }
- update_GC_hincr;
- return (GC_allochblk(sz, kind));
+ return(0);
}
- first_time = 0;
+ first_time = FALSE;
if( hbp == 0 ) continue;
@@ -205,7 +147,30 @@ int kind;
phdr = hhdr;
hbp = thishbp;
hhdr = thishdr;
- }
+ } else if (size_avail == 0
+ && size_needed == HBLKSIZE
+ && prevhbp != 0) {
+ static unsigned count = 0;
+
+ /* The block is completely blacklisted. We need */
+ /* to drop some such blocks, since otherwise we spend */
+ /* all our time traversing them if pointerfree */
+ /* blocks are unpopular. */
+ /* A dropped block will be reconsidered at next GC. */
+ if ((++count & 3) == 0) {
+ /* Allocate and drop the block */
+ phdr -> hb_next = hhdr -> hb_next;
+ GC_install_counts(hbp, hhdr->hb_sz);
+ setup_header(hhdr,
+ BYTES_TO_WORDS(hhdr->hb_sz - HDR_BYTES),
+ PTRFREE);
+ if (GC_savhbp == hbp) GC_savhbp = prevhbp;
+ /* Restore hbp to point at free block */
+ hbp = prevhbp;
+ hhdr = phdr;
+ if (hbp == GC_savhbp) first_time = TRUE;
+ }
+ }
}
if( size_avail >= size_needed ) {
/* found a big enough block */
@@ -237,34 +202,16 @@ int kind;
}
}
- /* set size and mask field of *thishbp correctly */
- thishdr->hb_sz = sz;
-
/* Clear block if necessary */
if (sz > MAXOBJSZ && GC_obj_kinds[kind].ok_init) {
bzero((char *)thishbp + HDR_BYTES, (int)(size_needed - HDR_BYTES));
}
-
- /* Clear mark bits */
- {
- register word *p = (word *)(&(thishdr -> hb_marks[0]));
- register word * plim =
- (word *)(&(thishdr -> hb_marks[MARK_BITS_SZ]));
- while (p < plim) {
- *p++ = 0;
- }
- }
-
- /* Add it to data structure describing hblks in use */
- GC_install_counts(thishbp, (word)size_needed);
-
- /* Add description of valid object pointers. */
- GC_add_map_entry(sz);
- thishdr -> hb_map = GC_obj_map[sz > MAXOBJSZ? 0 : sz];
+
+ /* Set up header */
+ setup_header(thishdr, sz, kind);
- /* Set kind related fields */
- thishdr -> hb_obj_kind = kind;
- thishdr -> hb_mark_proc = GC_obj_kinds[kind].ok_mark_proc;
+ /* Add it to map of valid blocks */
+ GC_install_counts(thishbp, (word)size_needed);
return( thishbp );
}
@@ -311,10 +258,10 @@ register signed_word size;
/* Check for duplicate deallocation in the easy case */
if (hbp != 0 && (ptr_t)p + size > (ptr_t)hbp
|| prevhbp != 0 && (ptr_t)prevhbp + prevhdr->hb_sz > (ptr_t)p) {
- GC_printf("Duplicate large block deallocation of 0x%lx\n",
- (unsigned long) p);
- GC_printf("Surrounding free blocks are 0x%lx and 0x%lx\n",
- (unsigned long) prevhbp, (unsigned long) hbp);
+ GC_printf1("Duplicate large block deallocation of 0x%lx\n",
+ (unsigned long) p);
+ GC_printf2("Surrounding free blocks are 0x%lx and 0x%lx\n",
+ (unsigned long) prevhbp, (unsigned long) hbp);
}
/* Coalesce with successor, if possible */