/* Allocate lb bytes of pointerful, traced, but not collectable data */ GC_API void * GC_CALL GC_malloc_uncollectable(size_t lb) { void *op; void **opp; size_t lg; DCL_LOCK_STATE; if( SMALL_OBJ(lb) ) { if (EXTRA_BYTES != 0 && lb != 0) lb--; /* We don't need the extra byte, since this won't be */ /* collected anyway. */ lg = GC_size_map[lb]; opp = &(GC_uobjfreelist[lg]); LOCK(); if( (op = *opp) != 0 ) { *opp = obj_link(op); obj_link(op) = 0; GC_bytes_allocd += GRANULES_TO_BYTES(lg); /* Mark bit ws already set on free list. It will be */ /* cleared only temporarily during a collection, as a */ /* result of the normal free list mark bit clearing. */ GC_non_gc_bytes += GRANULES_TO_BYTES(lg); UNLOCK(); } else { UNLOCK(); op = (ptr_t)GC_generic_malloc((word)lb, UNCOLLECTABLE); /* For small objects, the free lists are completely marked. */ } GC_ASSERT(0 == op || GC_is_marked(op)); return((void *) op); } else { hdr * hhdr; op = (ptr_t)GC_generic_malloc((word)lb, UNCOLLECTABLE); if (0 == op) return(0); GC_ASSERT(((word)op & (HBLKSIZE - 1)) == 0); /* large block */ hhdr = HDR(op); /* We don't need the lock here, since we have an undisguised */ /* pointer. We do need to hold the lock while we adjust */ /* mark bits. */ LOCK(); set_mark_bit_from_hdr(hhdr, 0); /* Only object. */ # ifndef THREADS GC_ASSERT(hhdr -> hb_n_marks == 0); /* This is not guaranteed in the multi-threaded case */ /* because the counter could be updated before locking. */ # endif hhdr -> hb_n_marks = 1; UNLOCK(); return((void *) op); } }
GC_API void * GC_CALL GC_malloc(size_t lb) #endif { void *op; void **opp; size_t lg; DCL_LOCK_STATE; if(SMALL_OBJ(lb)) { lg = GC_size_map[lb]; opp = (void **)&(GC_objfreelist[lg]); LOCK(); if (EXPECT((op = *opp) == 0, FALSE)) { UNLOCK(); return (GENERAL_MALLOC((word)lb, NORMAL)); } GC_ASSERT(0 == obj_link(op) || ((word)obj_link(op) <= (word)GC_greatest_plausible_heap_addr && (word)obj_link(op) >= (word)GC_least_plausible_heap_addr)); *opp = obj_link(op); obj_link(op) = 0; GC_bytes_allocd += GRANULES_TO_BYTES(lg); UNLOCK(); return op; } else { return(GENERAL_MALLOC(lb, NORMAL)); } }
/* hold lock: */ GC_INNER void * GC_generic_malloc_inner(size_t lb, int k) { void *op; if(SMALL_OBJ(lb)) { struct obj_kind * kind = GC_obj_kinds + k; size_t lg = GC_size_map[lb]; void ** opp = &(kind -> ok_freelist[lg]); if( (op = *opp) == 0 ) { if (GC_size_map[lb] == 0) { if (!GC_is_initialized) GC_init(); if (GC_size_map[lb] == 0) GC_extend_size_map(lb); return(GC_generic_malloc_inner(lb, k)); } if (kind -> ok_reclaim_list == 0) { if (!GC_alloc_reclaim_list(kind)) goto out; } op = GC_allocobj(lg, k); if (op == 0) goto out; } *opp = obj_link(op); obj_link(op) = 0; GC_bytes_allocd += GRANULES_TO_BYTES(lg); } else { op = (ptr_t)GC_alloc_large_and_clear(ADD_SLOP(lb), k, 0); GC_bytes_allocd += lb; } out: return op; }
GC_API GC_ATTR_MALLOC void * GC_CALL GC_malloc(size_t lb) #endif { void *op; size_t lg; DCL_LOCK_STATE; if(SMALL_OBJ(lb)) { GC_DBG_COLLECT_AT_MALLOC(lb); lg = GC_size_map[lb]; LOCK(); op = GC_freelists[NORMAL][lg]; if (EXPECT(0 == op, FALSE)) { UNLOCK(); return (GENERAL_MALLOC((word)lb, NORMAL)); } GC_ASSERT(0 == obj_link(op) || ((word)obj_link(op) <= (word)GC_greatest_plausible_heap_addr && (word)obj_link(op) >= (word)GC_least_plausible_heap_addr)); GC_freelists[NORMAL][lg] = obj_link(op); obj_link(op) = 0; GC_bytes_allocd += GRANULES_TO_BYTES(lg); UNLOCK(); return op; } else { return(GENERAL_MALLOC(lb, NORMAL)); } }
/* A size of 0 granules is used for large objects. */ GC_INNER GC_bool GC_add_map_entry(size_t granules) { unsigned displ; unsigned short * new_map; if (granules > BYTES_TO_GRANULES(MAXOBJBYTES)) granules = 0; if (GC_obj_map[granules] != 0) { return(TRUE); } new_map = (unsigned short *)GC_scratch_alloc(MAP_LEN * sizeof(short)); if (new_map == 0) return(FALSE); GC_COND_LOG_PRINTF( "Adding block map for size of %u granules (%u bytes)\n", (unsigned)granules, (unsigned)GRANULES_TO_BYTES(granules)); if (granules == 0) { for (displ = 0; displ < BYTES_TO_GRANULES(HBLKSIZE); displ++) { new_map[displ] = 1; /* Nonzero to get us out of marker fast path. */ } } else { for (displ = 0; displ < BYTES_TO_GRANULES(HBLKSIZE); displ++) { new_map[displ] = (unsigned short)(displ % granules); } } GC_obj_map[granules] = new_map; return(TRUE); }
void * GC_gcj_malloc_ignore_off_page(size_t lb, void * ptr_to_struct_containing_descr) { ptr_t op; ptr_t * opp; word lg; DCL_LOCK_STATE; if(SMALL_OBJ(lb)) { lg = GC_size_map[lb]; opp = &(GC_gcjobjfreelist[lg]); LOCK(); if( (op = *opp) == 0 ) { maybe_finalize(); op = (ptr_t)GENERAL_MALLOC_IOP(lb, GC_gcj_kind); lg = GC_size_map[lb]; /* May have been uninitialized. */ } else { *opp = obj_link(op); GC_bytes_allocd += GRANULES_TO_BYTES(lg); } *(void **)op = ptr_to_struct_containing_descr; UNLOCK(); } else { LOCK(); maybe_finalize(); op = (ptr_t)GENERAL_MALLOC_IOP(lb, GC_gcj_kind); if (0 != op) { *(void **)op = ptr_to_struct_containing_descr; } UNLOCK(); } return((void *) op); }
GC_API GC_ATTR_MALLOC void * GC_CALL GC_generic_malloc(size_t lb, int k) { void * result; DCL_LOCK_STATE; if (EXPECT(GC_have_errors, FALSE)) GC_print_all_errors(); GC_INVOKE_FINALIZERS(); GC_DBG_COLLECT_AT_MALLOC(lb); if (SMALL_OBJ(lb)) { LOCK(); result = GC_generic_malloc_inner(lb, k); UNLOCK(); } else { size_t lg; size_t lb_rounded; word n_blocks; GC_bool init; lg = ROUNDED_UP_GRANULES(lb); lb_rounded = GRANULES_TO_BYTES(lg); if (lb_rounded < lb) return((*GC_get_oom_fn())(lb)); n_blocks = OBJ_SZ_TO_BLOCKS(lb_rounded); init = GC_obj_kinds[k].ok_init; LOCK(); result = (ptr_t)GC_alloc_large(lb_rounded, k, 0); 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)[GRANULES_TO_WORDS(lg)-1] = 0; ((word *)result)[GRANULES_TO_WORDS(lg)-2] = 0; # endif } } GC_bytes_allocd += lb_rounded; UNLOCK(); if (init && !GC_debugging_started && 0 != result) { BZERO(result, n_blocks * HBLKSIZE); } } if (0 == result) { return((*GC_get_oom_fn())(lb)); } else { return(result); } }
/* require special handling on allocation. */ GC_INNER void * GC_generic_malloc_inner(size_t lb, int k) { void *op; GC_ASSERT(I_HOLD_LOCK()); if(SMALL_OBJ(lb)) { struct obj_kind * kind = GC_obj_kinds + k; size_t lg = GC_size_map[lb]; void ** opp = &(kind -> ok_freelist[lg]); op = *opp; if (EXPECT(0 == op, FALSE)) { if (lg == 0) { if (!EXPECT(GC_is_initialized, TRUE)) { DCL_LOCK_STATE; UNLOCK(); /* just to unset GC_lock_holder */ GC_init(); LOCK(); lg = GC_size_map[lb]; } if (0 == lg) { GC_extend_size_map(lb); lg = GC_size_map[lb]; GC_ASSERT(lg != 0); } /* Retry */ opp = &(kind -> ok_freelist[lg]); op = *opp; } if (0 == op) { if (0 == kind -> ok_reclaim_list && !GC_alloc_reclaim_list(kind)) return NULL; op = GC_allocobj(lg, k); if (0 == op) return NULL; } } *opp = obj_link(op); obj_link(op) = 0; GC_bytes_allocd += GRANULES_TO_BYTES(lg); } else { op = (ptr_t)GC_alloc_large_and_clear(ADD_SLOP(lb), k, 0); GC_bytes_allocd += lb; } return op; }
GC_API void * GC_CALL GC_finalized_malloc(size_t lb, const struct GC_finalizer_closure *fclos) #endif { ptr_t op; word lg; DCL_LOCK_STATE; lb += sizeof(void *); GC_ASSERT(done_init); if (SMALL_OBJ(lb)) { GC_DBG_COLLECT_AT_MALLOC(lb); lg = GC_size_map[lb]; LOCK(); op = GC_finalized_objfreelist[lg]; if (EXPECT(0 == op, FALSE)) { UNLOCK(); op = GC_generic_malloc(lb, GC_finalized_kind); if (NULL == op) return NULL; /* GC_generic_malloc has extended the size map for us. */ lg = GC_size_map[lb]; } else { GC_finalized_objfreelist[lg] = obj_link(op); obj_link(op) = 0; GC_bytes_allocd += GRANULES_TO_BYTES(lg); UNLOCK(); } GC_ASSERT(lg > 0); ((const void **)op)[GRANULES_TO_WORDS(lg) - 1] = fclos; } else { size_t op_sz; op = GC_generic_malloc(lb, GC_finalized_kind); if (NULL == op) return NULL; op_sz = GC_size(op); GC_ASSERT(op_sz >= lb); ((const void **)op)[op_sz / sizeof(void *) - 1] = fclos; } return GC_clear_stack(op); }
/* Will fail to do anything if we are out of memory. */ GC_INNER void GC_new_hblk(size_t gran, int kind) { struct hblk *h; /* the new heap block */ GC_bool clear = GC_obj_kinds[kind].ok_init; GC_STATIC_ASSERT((sizeof (struct hblk)) == HBLKSIZE); if (GC_debugging_started) clear = TRUE; /* Allocate a new heap block */ h = GC_allochblk(GRANULES_TO_BYTES(gran), kind, 0); if (h == 0) return; /* Mark all objects if appropriate. */ if (IS_UNCOLLECTABLE(kind)) GC_set_hdr_marks(HDR(h)); /* Build the free list */ GC_obj_kinds[kind].ok_freelist[gran] = GC_build_fl(h, GRANULES_TO_WORDS(gran), clear, GC_obj_kinds[kind].ok_freelist[gran]); }
void * GC_gcj_malloc(size_t lb, void * ptr_to_struct_containing_descr) #endif { ptr_t op; ptr_t * opp; word lg; DCL_LOCK_STATE; if(SMALL_OBJ(lb)) { lg = GC_size_map[lb]; opp = &(GC_gcjobjfreelist[lg]); LOCK(); op = *opp; if(EXPECT(op == 0, 0)) { maybe_finalize(); op = (ptr_t)GENERAL_MALLOC((word)lb, GC_gcj_kind); if (0 == op) { UNLOCK(); return(GC_oom_fn(lb)); } } else { *opp = obj_link(op); GC_bytes_allocd += GRANULES_TO_BYTES(lg); } *(void **)op = ptr_to_struct_containing_descr; GC_ASSERT(((void **)op)[1] == 0); UNLOCK(); } else { LOCK(); maybe_finalize(); op = (ptr_t)GENERAL_MALLOC((word)lb, GC_gcj_kind); if (0 == op) { UNLOCK(); return(GC_oom_fn(lb)); } *(void **)op = ptr_to_struct_containing_descr; UNLOCK(); } return((void *) op); }
GC_API void * GC_CALL GC_malloc_atomic(size_t lb) #endif { void *op; void ** opp; size_t lg; DCL_LOCK_STATE; if(SMALL_OBJ(lb)) { lg = GC_size_map[lb]; opp = &(GC_aobjfreelist[lg]); LOCK(); if (EXPECT((op = *opp) == 0, FALSE)) { UNLOCK(); return(GENERAL_MALLOC((word)lb, PTRFREE)); } *opp = obj_link(op); GC_bytes_allocd += GRANULES_TO_BYTES(lg); UNLOCK(); return((void *) op); } else { return(GENERAL_MALLOC((word)lb, PTRFREE)); } }
GC_API GC_ATTR_MALLOC void * GC_CALL GC_malloc_atomic(size_t lb) #endif { void *op; size_t lg; DCL_LOCK_STATE; if(SMALL_OBJ(lb)) { GC_DBG_COLLECT_AT_MALLOC(lb); lg = GC_size_map[lb]; LOCK(); op = GC_freelists[PTRFREE][lg]; if (EXPECT(0 == op, FALSE)) { UNLOCK(); return(GENERAL_MALLOC((word)lb, PTRFREE)); } GC_freelists[PTRFREE][lg] = obj_link(op); GC_bytes_allocd += GRANULES_TO_BYTES(lg); UNLOCK(); return((void *) op); } else { return(GENERAL_MALLOC((word)lb, PTRFREE)); } }