Instead of crashing or asserting.
while (capacity > da->capacity)
da->capacity *= 2;
- new_data = sgen_alloc_internal_dynamic (da->elem_size * da->capacity, INTERNAL_MEM_BRIDGE_DATA);
+ new_data = sgen_alloc_internal_dynamic (da->elem_size * da->capacity, INTERNAL_MEM_BRIDGE_DATA, TRUE);
memcpy (new_data, da->data, da->elem_size * da->size);
sgen_free_internal_dynamic (da->data, da->elem_size * old_capacity, INTERNAL_MEM_BRIDGE_DATA);
da->data = new_data;
/* alloc and fill array of all entries */
- all_entries = sgen_alloc_internal_dynamic (sizeof (HashEntry*) * hash_table.num_entries, INTERNAL_MEM_BRIDGE_DATA);
+ all_entries = sgen_alloc_internal_dynamic (sizeof (HashEntry*) * hash_table.num_entries, INTERNAL_MEM_BRIDGE_DATA, TRUE);
j = 0;
SGEN_HASH_TABLE_FOREACH (&hash_table, obj, entry) {
max_sccs_links = MAX (max_sccs_links, scc->xrefs.size);
}
- api_sccs = sgen_alloc_internal_dynamic (sizeof (MonoGCBridgeSCC*) * num_sccs, INTERNAL_MEM_BRIDGE_DATA);
+ api_sccs = sgen_alloc_internal_dynamic (sizeof (MonoGCBridgeSCC*) * num_sccs, INTERNAL_MEM_BRIDGE_DATA, TRUE);
num_xrefs = 0;
j = 0;
for (i = 0; i < sccs.size; ++i) {
if (!scc->num_bridge_entries)
continue;
- api_sccs [j] = sgen_alloc_internal_dynamic (sizeof (MonoGCBridgeSCC) + sizeof (MonoObject*) * scc->num_bridge_entries, INTERNAL_MEM_BRIDGE_DATA);
+ api_sccs [j] = sgen_alloc_internal_dynamic (sizeof (MonoGCBridgeSCC) + sizeof (MonoObject*) * scc->num_bridge_entries, INTERNAL_MEM_BRIDGE_DATA, TRUE);
api_sccs [j]->num_objs = scc->num_bridge_entries;
scc->num_bridge_entries = 0;
scc->api_index = j++;
}
} SGEN_HASH_TABLE_FOREACH_END;
- api_xrefs = sgen_alloc_internal_dynamic (sizeof (MonoGCBridgeXRef) * num_xrefs, INTERNAL_MEM_BRIDGE_DATA);
+ api_xrefs = sgen_alloc_internal_dynamic (sizeof (MonoGCBridgeXRef) * num_xrefs, INTERNAL_MEM_BRIDGE_DATA, TRUE);
j = 0;
for (i = 0; i < sccs.size; ++i) {
int k;
void
sgen_card_table_init (SgenRemeberedSet *remset)
{
- sgen_cardtable = sgen_alloc_os_memory (CARD_COUNT_IN_BYTES, TRUE);
+ sgen_cardtable = sgen_alloc_os_memory (CARD_COUNT_IN_BYTES, TRUE, "card table");
#ifdef SGEN_HAVE_OVERLAPPING_CARDS
- sgen_shadow_cardtable = sgen_alloc_os_memory (CARD_COUNT_IN_BYTES, TRUE);
+ sgen_shadow_cardtable = sgen_alloc_os_memory (CARD_COUNT_IN_BYTES, TRUE, "shadow card table");
#endif
#ifdef HEAVY_STATISTICS
{
/*setup valid_nursery_objects*/
if (!valid_nursery_objects)
- valid_nursery_objects = sgen_alloc_os_memory (DEFAULT_NURSERY_SIZE, TRUE);
+ valid_nursery_objects = sgen_alloc_os_memory (DEFAULT_NURSERY_SIZE, TRUE, "debugging data");
valid_nursery_object_count = 0;
sgen_scan_area_with_callback (nursery_section->data, nursery_section->end_data, setup_mono_sgen_scan_area_with_callback, NULL, FALSE);
section->size = alloc_size;
section->end_data = data + sgen_nursery_size;
scan_starts = (alloc_size + SCAN_START_SIZE - 1) / SCAN_START_SIZE;
- section->scan_starts = sgen_alloc_internal_dynamic (sizeof (char*) * scan_starts, INTERNAL_MEM_SCAN_STARTS);
+ section->scan_starts = sgen_alloc_internal_dynamic (sizeof (char*) * scan_starts, INTERNAL_MEM_SCAN_STARTS, TRUE);
section->num_scan_start = scan_starts;
section->block.role = MEMORY_ROLE_GEN0;
section->block.next = NULL;
void sgen_scan_area_with_callback (char *start, char *end, IterateObjectCallbackFunc callback, void *data, gboolean allow_flags) MONO_INTERNAL;
void sgen_check_section_scan_starts (GCMemSection *section) MONO_INTERNAL;
-/* Keep in sync with sgen_dump_internal_mem_usage() in dump_heap()! */
+/* Keep in sync with description_for_type() in sgen-internal.c! */
enum {
INTERNAL_MEM_PIN_QUEUE,
INTERNAL_MEM_FRAGMENT,
void* sgen_alloc_internal (int type) MONO_INTERNAL;
void sgen_free_internal (void *addr, int type) MONO_INTERNAL;
-void* sgen_alloc_internal_dynamic (size_t size, int type) MONO_INTERNAL;
+void* sgen_alloc_internal_dynamic (size_t size, int type, gboolean assert_on_failure) MONO_INTERNAL;
void sgen_free_internal_dynamic (void *addr, size_t size, int type) MONO_INTERNAL;
void* sgen_alloc_pinned (SgenPinnedAllocator *allocator, size_t size) MONO_INTERNAL;
new_size = g_spaced_primes_closest (hash_table->num_entries);
}
- new_hash = sgen_alloc_internal_dynamic (new_size * sizeof (SgenHashTableEntry*), hash_table->table_mem_type);
+ new_hash = sgen_alloc_internal_dynamic (new_size * sizeof (SgenHashTableEntry*), hash_table->table_mem_type, TRUE);
for (i = 0; i < old_hash_size; ++i) {
for (entry = old_hash [i]; entry; entry = next) {
hash = hash_table->hash_func (entry->key) % new_size;
g_assert (fixed_type_allocator_indexes [type] == slot);
}
+static const char*
+description_for_type (int type)
+{
+ switch (type) {
+ case INTERNAL_MEM_PIN_QUEUE: return "pin-queue";
+ case INTERNAL_MEM_FRAGMENT: return "fragment";
+ case INTERNAL_MEM_SECTION: return "section";
+ case INTERNAL_MEM_SCAN_STARTS: return "scan-starts";
+ case INTERNAL_MEM_FIN_TABLE: return "fin-table";
+ case INTERNAL_MEM_FINALIZE_ENTRY: return "finalize-entry";
+ case INTERNAL_MEM_FINALIZE_READY_ENTRY: return "finalize-ready-entry";
+ case INTERNAL_MEM_DISLINK_TABLE: return "dislink-table";
+ case INTERNAL_MEM_DISLINK: return "dislink";
+ case INTERNAL_MEM_ROOTS_TABLE: return "roots-table";
+ case INTERNAL_MEM_ROOT_RECORD: return "root-record";
+ case INTERNAL_MEM_STATISTICS: return "statistics";
+ case INTERNAL_MEM_STAT_PINNED_CLASS: return "pinned-class";
+ case INTERNAL_MEM_STAT_REMSET_CLASS: return "remset-class";
+ case INTERNAL_MEM_REMSET: return "remset";
+ case INTERNAL_MEM_GRAY_QUEUE: return "gray-queue";
+ case INTERNAL_MEM_STORE_REMSET: return "store-remset";
+ case INTERNAL_MEM_MS_TABLES: return "marksweep-tables";
+ case INTERNAL_MEM_MS_BLOCK_INFO: return "marksweep-block-info";
+ case INTERNAL_MEM_EPHEMERON_LINK: return "ephemeron-link";
+ case INTERNAL_MEM_WORKER_DATA: return "worker-data";
+ case INTERNAL_MEM_BRIDGE_DATA: return "bridge-data";
+ case INTERNAL_MEM_JOB_QUEUE_ENTRY: return "job-queue-entry";
+ case INTERNAL_MEM_TOGGLEREF_DATA: return "toggleref-data";
+ default:
+ g_assert_not_reached ();
+ }
+}
+
void*
-sgen_alloc_internal_dynamic (size_t size, int type)
+sgen_alloc_internal_dynamic (size_t size, int type, gboolean assert_on_failure)
{
int index;
void *p;
- if (size > allocator_sizes [NUM_ALLOCATORS - 1])
- return sgen_alloc_os_memory (size, TRUE);
+ if (size > allocator_sizes [NUM_ALLOCATORS - 1]) {
+ p = sgen_alloc_os_memory (size, TRUE, NULL);
+ if (!p)
+ sgen_assert_memory_alloc (NULL, description_for_type (type));
+ return p;
+ }
index = index_for_size (size);
p = mono_lock_free_alloc (&allocators [index]);
+ if (!p)
+ sgen_assert_memory_alloc (NULL, description_for_type (type));
memset (p, 0, size);
return p;
}
sgen_dump_internal_mem_usage (FILE *heap_dump_file)
{
/*
- static char const *internal_mem_names [] = { "pin-queue", "fragment", "section", "scan-starts",
- "fin-table", "finalize-entry", "finalize-ready-entry", "dislink-table",
- "dislink", "roots-table", "root-record", "statistics",
- "remset", "gray-queue", "store-remset", "marksweep-tables",
- "marksweep-block-info", "ephemeron-link", "worker-data",
- "bridge-data", "job-queue-entry", "toggleref-data" };
-
int i;
fprintf (heap_dump_file, "<other-mem-usage type=\"large-internal\" size=\"%lld\"/>\n", large_internal_bytes_alloced);
fprintf (heap_dump_file, "<other-mem-usage type=\"pinned-chunks\" size=\"%lld\"/>\n", pinned_chunk_bytes_alloced);
for (i = 0; i < INTERNAL_MEM_MAX; ++i) {
fprintf (heap_dump_file, "<other-mem-usage type=\"%s\" size=\"%ld\"/>\n",
- internal_mem_names [i], unmanaged_allocator.small_internal_mem_bytes [i]);
+ description_for_type (i), unmanaged_allocator.small_internal_mem_bytes [i]);
}
*/
}
if (!sgen_memgov_try_alloc_space (LOS_SECTION_SIZE, SPACE_LOS))
return NULL;
- section = sgen_alloc_os_memory_aligned (LOS_SECTION_SIZE, LOS_SECTION_SIZE, TRUE);
+ section = sgen_alloc_os_memory_aligned (LOS_SECTION_SIZE, LOS_SECTION_SIZE, TRUE, NULL);
if (!section)
return NULL;
#ifdef LOS_DUMMY
if (!los_segment)
- los_segment = sgen_alloc_os_memory (LOS_SEGMENT_SIZE, TRUE);
+ los_segment = sgen_alloc_os_memory (LOS_SEGMENT_SIZE, TRUE, NULL);
los_segment_index = ALIGN_UP (los_segment_index);
obj = (LOSObject*)(los_segment + los_segment_index);
alloc_size += pagesize - 1;
alloc_size &= ~(pagesize - 1);
if (sgen_memgov_try_alloc_space (alloc_size, SPACE_LOS)) {
- obj = sgen_alloc_os_memory (alloc_size, TRUE);
+ obj = sgen_alloc_os_memory (alloc_size, TRUE, NULL);
if (obj)
obj->huge_object = TRUE;
}
major_alloc_heap (mword nursery_size, mword nursery_align, int the_nursery_bits)
{
if (nursery_align)
- nursery_start = sgen_alloc_os_memory_aligned (nursery_size, nursery_align, TRUE);
+ nursery_start = sgen_alloc_os_memory_aligned (nursery_size, nursery_align, TRUE, "nursery");
else
- nursery_start = sgen_alloc_os_memory (nursery_size, TRUE);
+ nursery_start = sgen_alloc_os_memory (nursery_size, TRUE, "nursery");
nursery_end = nursery_start + nursery_size;
nursery_bits = the_nursery_bits;
GCMemSection *section;
int scan_starts;
- section = sgen_alloc_os_memory_aligned (MAJOR_SECTION_SIZE, MAJOR_SECTION_SIZE, TRUE);
+ section = sgen_alloc_os_memory_aligned (MAJOR_SECTION_SIZE, MAJOR_SECTION_SIZE, TRUE, "major heap section");
section->next_data = section->data = (char*)section + SGEN_SIZEOF_GC_MEM_SECTION;
g_assert (!((mword)section->data & 7));
section->size = MAJOR_SECTION_SIZE - SGEN_SIZEOF_GC_MEM_SECTION;
sgen_update_heap_boundaries ((mword)section->data, (mword)section->end_data);
DEBUG (3, fprintf (gc_debug_file, "New major heap section: (%p-%p), total: %lld\n", section->data, section->end_data, (long long int)mono_gc_get_heap_size ()));
scan_starts = (section->size + SGEN_SCAN_START_SIZE - 1) / SGEN_SCAN_START_SIZE;
- section->scan_starts = sgen_alloc_internal_dynamic (sizeof (char*) * scan_starts, INTERNAL_MEM_SCAN_STARTS);
+ section->scan_starts = sgen_alloc_internal_dynamic (sizeof (char*) * scan_starts, INTERNAL_MEM_SCAN_STARTS, TRUE);
section->num_scan_start = scan_starts;
section->block.role = MEMORY_ROLE_GEN1;
section->is_to_space = TRUE;
if (nursery_align)
g_assert (nursery_align % MS_BLOCK_SIZE == 0);
- nursery_start = sgen_alloc_os_memory_aligned (alloc_size, nursery_align ? nursery_align : MS_BLOCK_SIZE, TRUE);
+ nursery_start = sgen_alloc_os_memory_aligned (alloc_size, nursery_align ? nursery_align : MS_BLOCK_SIZE, TRUE, "heap");
ms_heap_start = nursery_start + nursery_size;
ms_heap_end = ms_heap_start + major_heap_size;
- block_infos = sgen_alloc_internal_dynamic (sizeof (MSBlockInfo) * ms_heap_num_blocks, INTERNAL_MEM_MS_BLOCK_INFO);
+ block_infos = sgen_alloc_internal_dynamic (sizeof (MSBlockInfo) * ms_heap_num_blocks, INTERNAL_MEM_MS_BLOCK_INFO, TRUE);
for (i = 0; i < ms_heap_num_blocks; ++i) {
block_infos [i].block = ms_heap_start + i * MS_BLOCK_SIZE;
{
char *start;
if (nursery_align)
- start = sgen_alloc_os_memory_aligned (nursery_size, nursery_align, TRUE);
+ start = sgen_alloc_os_memory_aligned (nursery_size, nursery_align, TRUE, "nursery");
else
- start = sgen_alloc_os_memory (nursery_size, TRUE);
+ start = sgen_alloc_os_memory (nursery_size, TRUE, "nursery");
return start;
}
retry:
if (!empty_blocks) {
- p = sgen_alloc_os_memory_aligned (MS_BLOCK_SIZE * MS_BLOCK_ALLOC_NUM, MS_BLOCK_SIZE, TRUE);
+ p = sgen_alloc_os_memory_aligned (MS_BLOCK_SIZE * MS_BLOCK_ALLOC_NUM, MS_BLOCK_SIZE, TRUE, "major heap section");
for (i = 0; i < MS_BLOCK_ALLOC_NUM; ++i) {
block = p;
{
int i;
for (i = 0; i < MS_BLOCK_TYPE_MAX; ++i)
- lists [i] = sgen_alloc_internal_dynamic (sizeof (MSBlockInfo*) * num_block_obj_sizes, INTERNAL_MEM_MS_TABLES);
+ lists [i] = sgen_alloc_internal_dynamic (sizeof (MSBlockInfo*) * num_block_obj_sizes, INTERNAL_MEM_MS_TABLES, TRUE);
}
#ifdef SGEN_PARALLEL_MARK
#endif
num_block_obj_sizes = ms_calculate_block_obj_sizes (MS_BLOCK_OBJ_SIZE_FACTOR, NULL);
- block_obj_sizes = sgen_alloc_internal_dynamic (sizeof (int) * num_block_obj_sizes, INTERNAL_MEM_MS_TABLES);
+ block_obj_sizes = sgen_alloc_internal_dynamic (sizeof (int) * num_block_obj_sizes, INTERNAL_MEM_MS_TABLES, TRUE);
ms_calculate_block_obj_sizes (MS_BLOCK_OBJ_SIZE_FACTOR, block_obj_sizes);
- evacuate_block_obj_sizes = sgen_alloc_internal_dynamic (sizeof (gboolean) * num_block_obj_sizes, INTERNAL_MEM_MS_TABLES);
+ evacuate_block_obj_sizes = sgen_alloc_internal_dynamic (sizeof (gboolean) * num_block_obj_sizes, INTERNAL_MEM_MS_TABLES, TRUE);
for (i = 0; i < num_block_obj_sizes; ++i)
evacuate_block_obj_sizes [i] = FALSE;
return prot_flags | MONO_MMAP_PRIVATE | MONO_MMAP_ANON;
}
+void
+sgen_assert_memory_alloc (void *ptr, const char *assert_description)
+{
+ if (ptr || !assert_description)
+ return;
+ fprintf (stderr, "Error: Garbage collector could not allocate memory for %s.\n", assert_description);
+ exit (1);
+}
+
/*
* Allocate a big chunk of memory from the OS (usually 64KB to several megabytes).
* This must not require any lock.
*/
void*
-sgen_alloc_os_memory (size_t size, int activate)
+sgen_alloc_os_memory (size_t size, int activate, const char *assert_description)
{
void *ptr = mono_valloc (0, size, prot_flags_for_activate (activate));
+ sgen_assert_memory_alloc (ptr, assert_description);
if (ptr)
SGEN_ATOMIC_ADD_P (total_alloc, size);
return ptr;
/* size must be a power of 2 */
void*
-sgen_alloc_os_memory_aligned (size_t size, mword alignment, gboolean activate)
+sgen_alloc_os_memory_aligned (size_t size, mword alignment, gboolean activate, const char *assert_description)
{
void *ptr = mono_valloc_aligned (size, alignment, prot_flags_for_activate (activate));
+ sgen_assert_memory_alloc (ptr, assert_description);
if (ptr)
SGEN_ATOMIC_ADD_P (total_alloc, size);
return ptr;
/* OS memory allocation */
-void* sgen_alloc_os_memory (size_t size, int activate) MONO_INTERNAL;
-void* sgen_alloc_os_memory_aligned (size_t size, mword alignment, gboolean activate) MONO_INTERNAL;
+void* sgen_alloc_os_memory (size_t size, int activate, const char *assert_description) MONO_INTERNAL;
+void* sgen_alloc_os_memory_aligned (size_t size, mword alignment, gboolean activate, const char *assert_description) MONO_INTERNAL;
void sgen_free_os_memory (void *addr, size_t size) MONO_INTERNAL;
+/* Error handling */
+void sgen_assert_memory_alloc (void *ptr, const char *assert_description) MONO_INTERNAL;
+
#endif
{
sgen_register_fixed_internal_mem_type (INTERNAL_MEM_FRAGMENT, sizeof (SgenFragment));
#ifdef NALLOC_DEBUG
- alloc_records = sgen_alloc_os_memory (sizeof (AllocRecord) * ALLOC_RECORD_COUNT, TRUE);
+ alloc_records = sgen_alloc_os_memory (sizeof (AllocRecord) * ALLOC_RECORD_COUNT, TRUE, "debugging memory");
#endif
}
int offset;
int size = SGEN_PINNED_CHUNK_SIZE;
- chunk = sgen_alloc_os_memory_aligned (size, size, TRUE);
+ chunk = sgen_alloc_os_memory_aligned (size, size, TRUE, "pinned chunk");
chunk->block.role = MEMORY_ROLE_PINNED;
sgen_update_heap_boundaries ((mword)chunk, ((mword)chunk + size));
LargePinnedMemHeader *mh;
size += sizeof (LargePinnedMemHeader);
- mh = sgen_alloc_os_memory (size, TRUE);
+ mh = sgen_alloc_os_memory (size, TRUE, "large pinned object");
mh->magic = LARGE_PINNED_MEM_HEADER_MAGIC;
mh->size = size;
/* FIXME: do a CAS here */
node_ptr = &node->right;
}
- node = sgen_alloc_internal_dynamic (sizeof (PinStatAddress), INTERNAL_MEM_STATISTICS);
+ node = sgen_alloc_internal_dynamic (sizeof (PinStatAddress), INTERNAL_MEM_STATISTICS, TRUE);
node->addr = addr;
node->pin_types = pin_type_bit;
node->left = node->right = NULL;
int pin_types = 0;
ObjectList *list;
- list = sgen_alloc_internal_dynamic (sizeof (ObjectList), INTERNAL_MEM_STATISTICS);
+ list = sgen_alloc_internal_dynamic (sizeof (ObjectList), INTERNAL_MEM_STATISTICS, TRUE);
pin_stats_count_object_from_tree (obj, size, pin_stat_addresses, &pin_types);
list->obj = (MonoObject*)obj;
list->next = pinned_objects;
realloc_pin_queue (void)
{
int new_size = pin_queue_size? pin_queue_size + pin_queue_size/2: 1024;
- void **new_pin = sgen_alloc_internal_dynamic (sizeof (void*) * new_size, INTERNAL_MEM_PIN_QUEUE);
+ void **new_pin = sgen_alloc_internal_dynamic (sizeof (void*) * new_size, INTERNAL_MEM_PIN_QUEUE, TRUE);
memcpy (new_pin, pin_queue, sizeof (void*) * next_pin_slot);
sgen_free_internal_dynamic (pin_queue, sizeof (void*) * pin_queue_size, INTERNAL_MEM_PIN_QUEUE);
pin_queue = new_pin;
if (buffer && buffer->index + length <= BINARY_PROTOCOL_BUFFER_SIZE)
return buffer;
- new_buffer = sgen_alloc_os_memory (sizeof (BinaryProtocolBuffer), TRUE);
+ new_buffer = sgen_alloc_os_memory (sizeof (BinaryProtocolBuffer), TRUE, "debugging memory");
new_buffer->next = buffer;
new_buffer->index = 0;
static RememberedSet*
sgen_alloc_remset (int size, gpointer id, gboolean global)
{
- RememberedSet* res = sgen_alloc_internal_dynamic (sizeof (RememberedSet) + (size * sizeof (gpointer)), INTERNAL_MEM_REMSET);
+ RememberedSet* res = sgen_alloc_internal_dynamic (sizeof (RememberedSet) + (size * sizeof (gpointer)), INTERNAL_MEM_REMSET, TRUE);
res->store_next = res->data;
res->end_set = res->data + size;
res->next = NULL;
for (remset = global_remset; remset; remset = remset->next)
size += remset->store_next - remset->data;
- bumper = addresses = sgen_alloc_internal_dynamic (sizeof (mword) * size, INTERNAL_MEM_STATISTICS);
+ bumper = addresses = sgen_alloc_internal_dynamic (sizeof (mword) * size, INTERNAL_MEM_STATISTICS, TRUE);
FOREACH_THREAD (info) {
for (remset = info->remset; remset; remset = remset->next)
toggleref_array_capacity = 32;
toggleref_array = sgen_alloc_internal_dynamic (
toggleref_array_capacity * sizeof (MonoGCToggleRef),
- INTERNAL_MEM_TOGGLEREF_DATA);
+ INTERNAL_MEM_TOGGLEREF_DATA,
+ TRUE);
}
if (toggleref_array_size + capacity >= toggleref_array_capacity) {
MonoGCToggleRef *tmp;
tmp = sgen_alloc_internal_dynamic (
toggleref_array_capacity * sizeof (MonoGCToggleRef),
- INTERNAL_MEM_TOGGLEREF_DATA);
+ INTERNAL_MEM_TOGGLEREF_DATA,
+ TRUE);
memcpy (tmp, toggleref_array, toggleref_array_size * sizeof (MonoGCToggleRef));
workers_num = num_workers;
- workers_data = sgen_alloc_internal_dynamic (sizeof (WorkerData) * num_workers, INTERNAL_MEM_WORKER_DATA);
+ workers_data = sgen_alloc_internal_dynamic (sizeof (WorkerData) * num_workers, INTERNAL_MEM_WORKER_DATA, TRUE);
memset (workers_data, 0, sizeof (WorkerData) * num_workers);
MONO_SEM_INIT (&workers_waiting_sem, 0);