OSDN Git Service

* config/mips/mips.c (TARGET_SMALL_REGISTER_CLASSES_FOR_MODE_P): Undef.
[pf3gnuchains/gcc-fork.git] / boehm-gc / mallocx.c
index ae8bfff..5ad593d 100644 (file)
@@ -2,6 +2,7 @@
  * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
  * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.
  * Copyright (c) 1996 by Silicon Graphics.  All rights reserved.
+ * Copyright (c) 2000 by Hewlett-Packard Company.  All rights reserved.
  *
  * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
  * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
@@ -21,7 +22,7 @@
  */
 
 #include <stdio.h>
-#include "gc_priv.h"
+#include "private/gc_priv.h"
 
 extern ptr_t GC_clear_stack();  /* in misc.c, behaves like identity */
 void GC_extend_size_map();      /* in misc.c. */
@@ -30,61 +31,193 @@ GC_bool GC_alloc_reclaim_list();   /* in malloc.c */
 /* Some externally visible but unadvertised variables to allow access to */
 /* free lists from inlined allocators without including gc_priv.h       */
 /* or introducing dependencies on internal data structure layouts.      */
-ptr_t * CONST GC_objfreelist_ptr = GC_objfreelist;
-ptr_t * CONST GC_aobjfreelist_ptr = GC_aobjfreelist;
-ptr_t * CONST GC_uobjfreelist_ptr = GC_uobjfreelist;
+ptr_t * GC_CONST GC_objfreelist_ptr = GC_objfreelist;
+ptr_t * GC_CONST GC_aobjfreelist_ptr = GC_aobjfreelist;
+ptr_t * GC_CONST GC_uobjfreelist_ptr = GC_uobjfreelist;
 # ifdef ATOMIC_UNCOLLECTABLE
-    ptr_t * CONST GC_auobjfreelist_ptr = GC_auobjfreelist;
+    ptr_t * GC_CONST GC_auobjfreelist_ptr = GC_auobjfreelist;
 # endif
 
-/* Allocate a composite object of size n bytes.  The caller guarantees  */
-/* that pointers past the first page are not relevant.  Caller holds    */
-/* allocation lock.                                                     */
-ptr_t GC_generic_malloc_inner_ignore_off_page(lb, k)
-register size_t lb;
-register int k;
+
+GC_PTR GC_generic_or_special_malloc(lb,knd)
+word lb;
+int knd;
 {
-    register struct hblk * h;
-    register word n_blocks;
-    register word lw;
-    register ptr_t op;
-
-    if (lb <= HBLKSIZE)
-        return(GC_generic_malloc_inner((word)lb, k));
-    n_blocks = divHBLKSZ(ADD_SLOP(lb) + HDR_BYTES + HBLKSIZE-1);
-    if (!GC_is_initialized) GC_init_inner();
-    /* Do our share of marking work */
-    if(GC_incremental && !GC_dont_gc)
-        GC_collect_a_little_inner((int)n_blocks);
-    lw = ROUNDED_UP_WORDS(lb);
-    while ((h = GC_allochblk(lw, k, IGNORE_OFF_PAGE)) == 0
-           && GC_collect_or_expand(n_blocks, TRUE));
-    if (h == 0) {
-        op = 0;
+    switch(knd) {
+#     ifdef STUBBORN_ALLOC
+       case STUBBORN:
+           return(GC_malloc_stubborn((size_t)lb));
+#     endif
+       case PTRFREE:
+           return(GC_malloc_atomic((size_t)lb));
+       case NORMAL:
+           return(GC_malloc((size_t)lb));
+       case UNCOLLECTABLE:
+           return(GC_malloc_uncollectable((size_t)lb));
+#       ifdef ATOMIC_UNCOLLECTABLE
+         case AUNCOLLECTABLE:
+           return(GC_malloc_atomic_uncollectable((size_t)lb));
+#      endif /* ATOMIC_UNCOLLECTABLE */
+       default:
+           return(GC_generic_malloc(lb,knd));
+    }
+}
+
+
+/* Change the size of the block pointed to by p to contain at least   */
+/* lb bytes.  The object may be (and quite likely will be) moved.     */
+/* The kind (e.g. atomic) is the same as that of the old.            */
+/* Shrinking of large blocks is not implemented well.                 */
+# ifdef __STDC__
+    GC_PTR GC_realloc(GC_PTR p, size_t lb)
+# else
+    GC_PTR GC_realloc(p,lb)
+    GC_PTR p;
+    size_t lb;
+# endif
+{
+register struct hblk * h;
+register hdr * hhdr;
+register word sz;       /* Current size in bytes       */
+register word orig_sz;  /* Original sz in bytes        */
+int obj_kind;
+
+    if (p == 0) return(GC_malloc(lb)); /* Required by ANSI */
+    h = HBLKPTR(p);
+    hhdr = HDR(h);
+    sz = hhdr -> hb_sz;
+    obj_kind = hhdr -> hb_obj_kind;
+    sz = WORDS_TO_BYTES(sz);
+    orig_sz = sz;
+
+    if (sz > MAXOBJBYTES) {
+       /* Round it up to the next whole heap block */
+         register word descr;
+         
+         sz = (sz+HBLKSIZE-1) & (~HBLKMASK);
+         hhdr -> hb_sz = BYTES_TO_WORDS(sz);
+         descr = GC_obj_kinds[obj_kind].ok_descriptor;
+          if (GC_obj_kinds[obj_kind].ok_relocate_descr) descr += sz;
+          hhdr -> hb_descr = descr;
+         if (IS_UNCOLLECTABLE(obj_kind)) GC_non_gc_bytes += (sz - orig_sz);
+         /* Extra area is already cleared by GC_alloc_large_and_clear. */
+    }
+    if (ADD_SLOP(lb) <= sz) {
+       if (lb >= (sz >> 1)) {
+#          ifdef STUBBORN_ALLOC
+               if (obj_kind == STUBBORN) GC_change_stubborn(p);
+#          endif
+           if (orig_sz > lb) {
+             /* Clear unneeded part of object to avoid bogus pointer */
+             /* tracing.                                             */
+             /* Safe for stubborn objects.                           */
+               BZERO(((ptr_t)p) + lb, orig_sz - lb);
+           }
+           return(p);
+       } else {
+           /* shrink */
+             GC_PTR result =
+                       GC_generic_or_special_malloc((word)lb, obj_kind);
+
+             if (result == 0) return(0);
+                 /* Could also return original object.  But this       */
+                 /* gives the client warning of imminent disaster.     */
+             BCOPY(p, result, lb);
+#            ifndef IGNORE_FREE
+               GC_free(p);
+#            endif
+             return(result);
+       }
     } else {
-        op = (ptr_t) (h -> hb_body);
-        GC_words_wasted += BYTES_TO_WORDS(n_blocks * HBLKSIZE) - lw;
+       /* grow */
+         GC_PTR result =
+               GC_generic_or_special_malloc((word)lb, obj_kind);
+
+         if (result == 0) return(0);
+         BCOPY(p, result, sz);
+#        ifndef IGNORE_FREE
+           GC_free(p);
+#        endif
+         return(result);
     }
-    GC_words_allocd += lw;
-    return((ptr_t)op);
 }
 
+# if defined(REDIRECT_MALLOC) && !defined(REDIRECT_REALLOC)
+#   define REDIRECT_REALLOC GC_realloc
+# endif
+
+# ifdef REDIRECT_REALLOC
+
+/* As with malloc, avoid two levels of extra calls here.       */
+# ifdef GC_ADD_CALLER
+#   define RA GC_RETURN_ADDR,
+# else
+#   define RA
+# endif
+# define GC_debug_realloc_replacement(p, lb) \
+       GC_debug_realloc(p, lb, RA "unknown", 0)
+
+# ifdef __STDC__
+    GC_PTR realloc(GC_PTR p, size_t lb)
+# else
+    GC_PTR realloc(p,lb)
+    GC_PTR p;
+    size_t lb;
+# endif
+  {
+    return(REDIRECT_REALLOC(p, lb));
+  }
+
+# undef GC_debug_realloc_replacement
+# endif /* REDIRECT_REALLOC */
+
+
+/* Allocate memory such that only pointers to near the                 */
+/* beginning of the object are considered.                     */
+/* We avoid holding allocation lock while we clear memory.     */
 ptr_t GC_generic_malloc_ignore_off_page(lb, k)
 register size_t lb;
 register int k;
 {
     register ptr_t result;
+    word lw;
+    word n_blocks;
+    GC_bool init;
     DCL_LOCK_STATE;
     
+    if (SMALL_OBJ(lb))
+        return(GC_generic_malloc((word)lb, k));
+    lw = ROUNDED_UP_WORDS(lb);
+    n_blocks = OBJ_SZ_TO_BLOCKS(lw);
+    init = GC_obj_kinds[k].ok_init;
+    if (GC_have_errors) GC_print_all_errors();
     GC_INVOKE_FINALIZERS();
     DISABLE_SIGNALS();
     LOCK();
-    result = GC_generic_malloc_inner_ignore_off_page(lb,k);
+    result = (ptr_t)GC_alloc_large(lw, k, IGNORE_OFF_PAGE);
+    if (0 != result) {
+        if (GC_debugging_started) {
+           BZERO(result, n_blocks * HBLKSIZE);
+        } else {
+#           ifdef THREADS
+             /* Clear any memory that might be used for GC descriptors */
+             /* before we release the lock.                          */
+               ((word *)result)[0] = 0;
+               ((word *)result)[1] = 0;
+               ((word *)result)[lw-1] = 0;
+               ((word *)result)[lw-2] = 0;
+#          endif
+        }
+    }
+    GC_words_allocd += lw;
     UNLOCK();
     ENABLE_SIGNALS();
     if (0 == result) {
         return((*GC_oom_fn)(lb));
     } else {
+       if (init && !GC_debugging_started) {
+           BZERO(result, n_blocks * HBLKSIZE);
+        }
         return(result);
     }
 }
@@ -126,29 +259,21 @@ void GC_incr_mem_freed(size_t n)
 
 /* Analogous to the above, but assumes a small object size, and        */
 /* bypasses MERGE_SIZES mechanism.  Used by gc_inline.h.               */
-#ifdef __STDC__
-     ptr_t GC_generic_malloc_words_small(size_t lw, int k)
-#else 
-     ptr_t GC_generic_malloc_words_small(lw, k)
-     register size_t lw;
-     register int k;
-#endif
+ptr_t GC_generic_malloc_words_small_inner(lw, k)
+register word lw;
+register int k;
 {
 register ptr_t op;
 register ptr_t *opp;
 register struct obj_kind * kind = GC_obj_kinds + k;
-DCL_LOCK_STATE;
 
-    GC_INVOKE_FINALIZERS();
-    DISABLE_SIGNALS();
-    LOCK();
     opp = &(kind -> ok_freelist[lw]);
     if( (op = *opp) == 0 ) {
         if (!GC_is_initialized) {
             GC_init_inner();
         }
        if (kind -> ok_reclaim_list != 0 || GC_alloc_reclaim_list(kind)) {
-           op = GC_clear_stack(GC_allocobj(lw, k));
+           op = GC_clear_stack(GC_allocobj((word)lw, k));
        }
        if (op == 0) {
            UNLOCK();
@@ -159,12 +284,51 @@ DCL_LOCK_STATE;
     *opp = obj_link(op);
     obj_link(op) = 0;
     GC_words_allocd += lw;
+    return((ptr_t)op);
+}
+
+/* Analogous to the above, but assumes a small object size, and        */
+/* bypasses MERGE_SIZES mechanism.  Used by gc_inline.h.               */
+#ifdef __STDC__
+     ptr_t GC_generic_malloc_words_small(size_t lw, int k)
+#else 
+     ptr_t GC_generic_malloc_words_small(lw, k)
+     register word lw;
+     register int k;
+#endif
+{
+register ptr_t op;
+DCL_LOCK_STATE;
+
+    if (GC_have_errors) GC_print_all_errors();
+    GC_INVOKE_FINALIZERS();
+    DISABLE_SIGNALS();
+    LOCK();
+    op = GC_generic_malloc_words_small_inner(lw, k);
     UNLOCK();
     ENABLE_SIGNALS();
     return((ptr_t)op);
 }
 
 #if defined(THREADS) && !defined(SRC_M3)
+
+extern signed_word GC_mem_found;   /* Protected by GC lock.  */
+
+#ifdef PARALLEL_MARK
+volatile signed_word GC_words_allocd_tmp = 0;
+                        /* Number of words of memory allocated since    */
+                        /* we released the GC lock.  Instead of         */
+                        /* reacquiring the GC lock just to add this in, */
+                        /* we add it in the next time we reacquire      */
+                        /* the lock.  (Atomically adding it doesn't     */
+                        /* work, since we would have to atomically      */
+                        /* update it in GC_malloc, which is too         */
+                        /* expensive.                                   */
+#endif /* PARALLEL_MARK */
+
+/* See reclaim.c: */
+extern ptr_t GC_reclaim_generic();
+
 /* Return a list of 1 or more objects of the indicated size, linked    */
 /* through the first word in the object.  This has the advantage that  */
 /* it acquires the allocation lock only once, and may greatly reduce   */
@@ -174,63 +338,193 @@ DCL_LOCK_STATE;
 /* GC_malloc_many or friends to replenish it.  (We do not round up     */
 /* object sizes, since a call indicates the intention to consume many  */
 /* objects of exactly this size.)                                      */
+/* We return the free-list by assigning it to *result, since it is     */
+/* not safe to return, e.g. a linked list of pointer-free objects,     */
+/* since the collector would not retain the entire list if it were     */
+/* invoked just as we were returning.                                  */
 /* Note that the client should usually clear the link field.           */
-ptr_t GC_generic_malloc_many(lb, k)
+void GC_generic_malloc_many(lb, k, result)
 register word lb;
 register int k;
+ptr_t *result;
 {
 ptr_t op;
-register ptr_t p;
+ptr_t p;
 ptr_t *opp;
 word lw;
-register word my_words_allocd;
+word my_words_allocd = 0;
+struct obj_kind * ok = &(GC_obj_kinds[k]);
 DCL_LOCK_STATE;
 
+#   if defined(GATHERSTATS) || defined(PARALLEL_MARK)
+#     define COUNT_ARG , &my_words_allocd
+#   else
+#     define COUNT_ARG
+#     define NEED_TO_COUNT
+#   endif
     if (!SMALL_OBJ(lb)) {
         op = GC_generic_malloc(lb, k);
         if(0 != op) obj_link(op) = 0;
-        return(op);
+       *result = op;
+        return;
     }
     lw = ALIGNED_WORDS(lb);
+    if (GC_have_errors) GC_print_all_errors();
     GC_INVOKE_FINALIZERS();
     DISABLE_SIGNALS();
     LOCK();
-    opp = &(GC_obj_kinds[k].ok_freelist[lw]);
-    if( (op = *opp) == 0 ) {
-        if (!GC_is_initialized) {
-            GC_init_inner();
-        }
-       op = GC_clear_stack(GC_allocobj(lw, k));
-       if (op == 0) {
-           UNLOCK();
-           ENABLE_SIGNALS();
-           op = (*GC_oom_fn)(lb);
-           if(0 != op) obj_link(op) = 0;
-            return(op);
-       }
+    if (!GC_is_initialized) GC_init_inner();
+    /* Do our share of marking work */
+      if (GC_incremental && !GC_dont_gc) {
+        ENTER_GC();
+       GC_collect_a_little_inner(1);
+        EXIT_GC();
+      }
+    /* First see if we can reclaim a page of objects waiting to be */
+    /* reclaimed.                                                 */
+    {
+       struct hblk ** rlh = ok -> ok_reclaim_list;
+       struct hblk * hbp;
+       hdr * hhdr;
+
+       rlh += lw;
+       while ((hbp = *rlh) != 0) {
+            hhdr = HDR(hbp);
+            *rlh = hhdr -> hb_next;
+           hhdr -> hb_last_reclaimed = (unsigned short) GC_gc_no;
+#          ifdef PARALLEL_MARK
+               {
+                 signed_word my_words_allocd_tmp = GC_words_allocd_tmp;
+
+                 GC_ASSERT(my_words_allocd_tmp >= 0);
+                 /* We only decrement it while holding the GC lock.    */
+                 /* Thus we can't accidentally adjust it down in more  */
+                 /* than one thread simultaneously.                    */
+                 if (my_words_allocd_tmp != 0) {
+                   (void)GC_atomic_add(
+                               (volatile GC_word *)(&GC_words_allocd_tmp),
+                               (GC_word)(-my_words_allocd_tmp));
+                   GC_words_allocd += my_words_allocd_tmp;
+                 }
+               }
+               GC_acquire_mark_lock();
+               ++ GC_fl_builder_count;
+               UNLOCK();
+               ENABLE_SIGNALS();
+               GC_release_mark_lock();
+#          endif
+           op = GC_reclaim_generic(hbp, hhdr, lw,
+                                   ok -> ok_init, 0 COUNT_ARG);
+            if (op != 0) {
+#            ifdef NEED_TO_COUNT
+               /* We are neither gathering statistics, nor marking in  */
+               /* parallel.  Thus GC_reclaim_generic doesn't count     */
+               /* for us.                                              */
+               for (p = op; p != 0; p = obj_link(p)) {
+                 my_words_allocd += lw;
+               }
+#            endif
+#            if defined(GATHERSTATS)
+               /* We also reclaimed memory, so we need to adjust       */
+               /* that count.                                          */
+               /* This should be atomic, so the results may be         */
+               /* inaccurate.                                          */
+               GC_mem_found += my_words_allocd;
+#            endif
+#            ifdef PARALLEL_MARK
+               *result = op;
+               (void)GC_atomic_add(
+                               (volatile GC_word *)(&GC_words_allocd_tmp),
+                               (GC_word)(my_words_allocd));
+               GC_acquire_mark_lock();
+               -- GC_fl_builder_count;
+               if (GC_fl_builder_count == 0) GC_notify_all_builder();
+               GC_release_mark_lock();
+               (void) GC_clear_stack(0);
+               return;
+#            else
+               GC_words_allocd += my_words_allocd;
+               goto out;
+#            endif
+           }
+#          ifdef PARALLEL_MARK
+             GC_acquire_mark_lock();
+             -- GC_fl_builder_count;
+             if (GC_fl_builder_count == 0) GC_notify_all_builder();
+             GC_release_mark_lock();
+             DISABLE_SIGNALS();
+             LOCK();
+             /* GC lock is needed for reclaim list access.     We      */
+             /* must decrement fl_builder_count before reaquiring GC   */
+             /* lock.  Hopefully this path is rare.                    */
+#          endif
+       }
     }
-    *opp = 0;
-    my_words_allocd = 0;
-    for (p = op; p != 0; p = obj_link(p)) {
-        my_words_allocd += lw;
-        if (my_words_allocd >= BODY_SZ) {
+    /* Next try to use prefix of global free list if there is one.     */
+    /* We don't refill it, but we need to use it up before allocating  */
+    /* a new block ourselves.                                          */
+      opp = &(GC_obj_kinds[k].ok_freelist[lw]);
+      if ( (op = *opp) != 0 ) {
+       *opp = 0;
+        my_words_allocd = 0;
+        for (p = op; p != 0; p = obj_link(p)) {
+          my_words_allocd += lw;
+          if (my_words_allocd >= BODY_SZ) {
             *opp = obj_link(p);
             obj_link(p) = 0;
             break;
+         }
         }
+       GC_words_allocd += my_words_allocd;
+       goto out;
+      }
+    /* Next try to allocate a new block worth of objects of this size. */
+    {
+       struct hblk *h = GC_allochblk(lw, k, 0);
+       if (h != 0) {
+         if (IS_UNCOLLECTABLE(k)) GC_set_hdr_marks(HDR(h));
+         GC_words_allocd += BYTES_TO_WORDS(HBLKSIZE)
+                              - BYTES_TO_WORDS(HBLKSIZE) % lw;
+#        ifdef PARALLEL_MARK
+           GC_acquire_mark_lock();
+           ++ GC_fl_builder_count;
+           UNLOCK();
+           ENABLE_SIGNALS();
+           GC_release_mark_lock();
+#        endif
+
+         op = GC_build_fl(h, lw, ok -> ok_init, 0);
+#        ifdef PARALLEL_MARK
+           *result = op;
+           GC_acquire_mark_lock();
+           -- GC_fl_builder_count;
+           if (GC_fl_builder_count == 0) GC_notify_all_builder();
+           GC_release_mark_lock();
+           (void) GC_clear_stack(0);
+           return;
+#        else
+           goto out;
+#        endif
+       }
     }
-    GC_words_allocd += my_words_allocd;
     
-out:
+    /* As a last attempt, try allocating a single object.  Note that   */
+    /* this may trigger a collection or expand the heap.               */
+      op = GC_generic_malloc_inner(lb, k);
+      if (0 != op) obj_link(op) = 0;
+    
+  out:
+    *result = op;
     UNLOCK();
     ENABLE_SIGNALS();
-    return(op);
-
+    (void) GC_clear_stack(0);
 }
 
-void * GC_malloc_many(size_t lb)
+GC_PTR GC_malloc_many(size_t lb)
 {
-    return(GC_generic_malloc_many(lb, NORMAL));
+    ptr_t result;
+    GC_generic_malloc_many(lb, NORMAL, &result);
+    return result;
 }
 
 /* Note that the "atomic" version of this would be unsafe, since the   */
@@ -252,11 +546,9 @@ DCL_LOCK_STATE;
 
     if( SMALL_OBJ(lb) ) {
 #       ifdef MERGE_SIZES
-#        ifdef ADD_BYTE_AT_END
-           if (lb != 0) lb--;
+         if (EXTRA_BYTES != 0 && lb != 0) lb--;
                  /* We don't need the extra byte, since this won't be  */
                  /* collected anyway.                                  */
-#        endif
          lw = GC_size_map[lb];
 #      else
          lw = ALIGNED_WORDS(lb);
@@ -300,6 +592,44 @@ DCL_LOCK_STATE;
     }
 }
 
+#ifdef __STDC__
+/* Not well tested nor integrated.     */
+/* Debug version is tricky and currently missing.      */
+#include <limits.h>
+
+GC_PTR GC_memalign(size_t align, size_t lb) 
+{ 
+    size_t new_lb;
+    size_t offset;
+    ptr_t result;
+
+#   ifdef ALIGN_DOUBLE
+       if (align <= WORDS_TO_BYTES(2) && lb > align) return GC_malloc(lb);
+#   endif
+    if (align <= WORDS_TO_BYTES(1)) return GC_malloc(lb);
+    if (align >= HBLKSIZE/2 || lb >= HBLKSIZE/2) {
+        if (align > HBLKSIZE) return GC_oom_fn(LONG_MAX-1024) /* Fail */;
+       return GC_malloc(lb <= HBLKSIZE? HBLKSIZE : lb);
+           /* Will be HBLKSIZE aligned.        */
+    }
+    /* We could also try to make sure that the real rounded-up object size */
+    /* is a multiple of align.  That would be correct up to HBLKSIZE.     */
+    new_lb = lb + align - 1;
+    result = GC_malloc(new_lb);
+    offset = (word)result % align;
+    if (offset != 0) {
+       offset = align - offset;
+        if (!GC_all_interior_pointers) {
+           if (offset >= VALID_OFFSET_SZ) return GC_malloc(HBLKSIZE);
+           GC_register_displacement(offset);
+       }
+    }
+    result = (GC_PTR) ((ptr_t)result + offset);
+    GC_ASSERT((word)result % align == 0);
+    return result;
+}
+#endif 
+
 # ifdef ATOMIC_UNCOLLECTABLE
 /* Allocate lb bytes of pointerfree, untraced, uncollectable data      */
 /* This is normally roughly equivalent to the system malloc.           */
@@ -318,11 +648,9 @@ DCL_LOCK_STATE;
 
     if( SMALL_OBJ(lb) ) {
 #       ifdef MERGE_SIZES
-#        ifdef ADD_BYTE_AT_END
-           if (lb != 0) lb--;
+         if (EXTRA_BYTES != 0 && lb != 0) lb--;
                  /* We don't need the extra byte, since this won't be  */
                  /* collected anyway.                                  */
-#        endif
          lw = GC_size_map[lb];
 #      else
          lw = ALIGNED_WORDS(lb);