* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
+#include "config.h"
+
+#ifdef HAVE_SGEN_GC
+
+#include "metadata/sgen-gc.h"
+#include "metadata/sgen-protocol.h"
+#include "metadata/sgen-cardtable.h"
+#include "metadata/sgen-memory-governor.h"
+#include "utils/mono-mmap.h"
+
#define LOS_SECTION_SIZE (1024 * 1024)
/*
#define LOS_NUM_FAST_SIZES 32
-typedef struct _LOSObject LOSObject;
-struct _LOSObject {
- LOSObject *next;
- mword size; /* this is the object size */
- guint16 huge_object;
- int dummy; /* to have a sizeof (LOSObject) a multiple of ALLOC_ALIGN and data starting at same alignment */
- char data [MONO_ZERO_LEN_ARRAY];
-};
-
typedef struct _LOSFreeChunks LOSFreeChunks;
struct _LOSFreeChunks {
LOSFreeChunks *next_size;
unsigned char *free_chunk_map;
};
+LOSObject *los_object_list = NULL;
+mword los_memory_usage = 0;
+
static LOSSection *los_sections = NULL;
-static LOSObject *los_object_list = NULL;
static LOSFreeChunks *los_fast_free_lists [LOS_NUM_FAST_SIZES]; /* 0 is for larger sizes */
-static mword los_memory_usage = 0;
-static mword last_los_memory_usage = 0;
static mword los_num_objects = 0;
static int los_num_sections = 0;
-static mword next_los_collection = 2*1024*1024; /* 2 MB, need to tune */
//#define USE_MALLOC
//#define LOS_CONSISTENCY_CHECK
if (free_chunks)
return (LOSObject*)free_chunks;
- section = mono_sgen_alloc_os_memory_aligned (LOS_SECTION_SIZE, LOS_SECTION_SIZE, TRUE);
+ 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, NULL);
+
+ if (!section)
+ return NULL;
free_chunks = (LOSFreeChunks*)((char*)section + LOS_CHUNK_SIZE);
free_chunks->size = LOS_SECTION_SIZE - LOS_CHUNK_SIZE;
add_free_chunk ((LOSFreeChunks*)obj, size);
}
-static void
-free_large_object (LOSObject *obj)
+static int pagesize;
+
+void
+sgen_los_free_object (LOSObject *obj)
{
#ifndef LOS_DUMMY
size_t size = obj->size;
free (obj);
#else
if (size > LOS_SECTION_OBJECT_LIMIT) {
+ if (!pagesize)
+ pagesize = mono_pagesize ();
size += sizeof (LOSObject);
size += pagesize - 1;
size &= ~(pagesize - 1);
- mono_sgen_free_os_memory (obj, size);
+ sgen_free_os_memory (obj, size);
+ sgen_memgov_release_space (size, SPACE_LOS);
} else {
free_los_section_memory (obj, size + sizeof (LOSObject));
#ifdef LOS_CONSISTENCY_CHECKS
* They don't move, so there is no need to pin them during collection
* and we avoid the memcpy overhead.
*/
-static void* __attribute__((noinline))
-alloc_large_inner (MonoVTable *vtable, size_t size)
+void*
+sgen_los_alloc_large_inner (MonoVTable *vtable, size_t size)
{
- LOSObject *obj;
+ LOSObject *obj = NULL;
void **vtslot;
- g_assert (size > MAX_SMALL_OBJ_SIZE);
+ g_assert (size > SGEN_MAX_SMALL_OBJ_SIZE);
#ifdef LOS_DUMMY
if (!los_segment)
- los_segment = mono_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);
los_segment_index += size + sizeof (LOSObject);
g_assert (los_segment_index <= LOS_SEGMENT_SIZE);
#else
- if (need_major_collection ()) {
- DEBUG (4, fprintf (gc_debug_file, "Should trigger major collection: req size %zd (los already: %lu, limit: %lu)\n", size, (unsigned long)los_memory_usage, (unsigned long)next_los_collection));
- stop_world ();
- major_collection ("LOS overflow");
- restart_world ();
- }
+ sgen_ensure_free_space (size);
#ifdef USE_MALLOC
obj = malloc (size + sizeof (LOSObject));
#else
if (size > LOS_SECTION_OBJECT_LIMIT) {
size_t alloc_size = size;
+ if (!pagesize)
+ pagesize = mono_pagesize ();
alloc_size += sizeof (LOSObject);
alloc_size += pagesize - 1;
alloc_size &= ~(pagesize - 1);
- /* FIXME: handle OOM */
- obj = mono_sgen_alloc_os_memory (alloc_size, TRUE);
- obj->huge_object = TRUE;
+ if (sgen_memgov_try_alloc_space (alloc_size, SPACE_LOS)) {
+ obj = sgen_alloc_os_memory (alloc_size, TRUE, NULL);
+ if (obj)
+ obj->huge_object = TRUE;
+ }
} else {
obj = get_los_section_memory (size + sizeof (LOSObject));
- memset (obj, 0, size + sizeof (LOSObject));
+ if (obj)
+ memset (obj, 0, size + sizeof (LOSObject));
}
#endif
#endif
-
- g_assert (!((mword)obj->data & (ALLOC_ALIGN - 1)));
+ if (!obj)
+ return NULL;
+ g_assert (!((mword)obj->data & (SGEN_ALLOC_ALIGN - 1)));
obj->size = size;
vtslot = (void**)obj->data;
*vtslot = vtable;
- mono_sgen_update_heap_boundaries ((mword)obj->data, (mword)obj->data + size);
+ sgen_update_heap_boundaries ((mword)obj->data, (mword)obj->data + size);
obj->next = los_object_list;
los_object_list = obj;
los_memory_usage += size;
return obj->data;
}
-static void
-los_sweep (void)
+void
+sgen_los_sweep (void)
{
LOSSection *section, *prev;
int i;
prev->next = next;
else
los_sections = next;
- mono_sgen_free_os_memory (section, LOS_SECTION_SIZE);
+ sgen_free_os_memory (section, LOS_SECTION_SIZE);
+ sgen_memgov_release_space (LOS_SECTION_SIZE, SPACE_LOS);
section = next;
--los_num_sections;
continue;
g_assert (los_num_sections == num_sections);
}
-#ifdef SGEN_HAVE_CARDTABLE
+gboolean
+sgen_ptr_is_in_los (char *ptr, char **start)
+{
+ LOSObject *obj;
-static void
-los_iterate_live_block_ranges (sgen_cardtable_block_callback callback)
+ *start = NULL;
+ for (obj = los_object_list; obj; obj = obj->next) {
+ char *end = obj->data + obj->size;
+
+ if (ptr >= obj->data && ptr < end) {
+ *start = obj->data;
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+void
+sgen_los_iterate_objects (IterateObjectCallbackFunc cb, void *user_data)
{
LOSObject *obj;
+
+ for (obj = los_object_list; obj; obj = obj->next)
+ cb (obj->data, obj->size, user_data);
+}
+
+gboolean
+sgen_los_is_valid_object (char *object)
+{
+ LOSObject *obj;
+
for (obj = los_object_list; obj; obj = obj->next) {
- MonoVTable *vt = (MonoVTable*)LOAD_VTABLE (obj->data);
- if (vt->klass->has_references)
- callback ((mword)obj->data, (mword)obj->size);
+ if (obj->data == object)
+ return TRUE;
}
+ return FALSE;
}
-#define ARRAY_OBJ_INDEX(ptr,array,elem_size) (((char*)(ptr) - ((char*)(array) + G_STRUCT_OFFSET (MonoArray, vector))) / (elem_size))
+gboolean
+mono_sgen_los_describe_pointer (char *ptr)
+{
+ LOSObject *obj;
+
+ for (obj = los_object_list; obj; obj = obj->next) {
+ MonoVTable *vtable;
+ if (obj->data > ptr || obj->data + obj->size <= ptr)
+ continue;
+
+ if (obj->size > LOS_SECTION_OBJECT_LIMIT)
+ fprintf (gc_debug_file, "huge-los-ptr ");
+ else
+ fprintf (gc_debug_file, "los-ptr ");
+
+ vtable = (MonoVTable*)SGEN_LOAD_VTABLE (obj->data);
-static void __attribute__((noinline))
-los_scan_card_table (GrayQueue *queue)
+ if (obj->data == ptr)
+ fprintf (gc_debug_file, "(object %s.%s size %d)",
+ vtable->klass->name_space, vtable->klass->name, (int)obj->size);
+ else
+ fprintf (gc_debug_file, "(interior-ptr offset %td of %p (%s.%s) size %d)",
+ ptr - obj->data, obj->data,
+ vtable->klass->name_space, vtable->klass->name, (int)obj->size);
+
+ return TRUE;
+ }
+ return FALSE;
+}
+
+void
+sgen_los_iterate_live_block_ranges (sgen_cardtable_block_callback callback)
+{
+ LOSObject *obj;
+ for (obj = los_object_list; obj; obj = obj->next) {
+ MonoVTable *vt = (MonoVTable*)SGEN_LOAD_VTABLE (obj->data);
+ if (SGEN_VTABLE_HAS_REFERENCES (vt))
+ callback ((mword)obj->data, (mword)obj->size);
+ }
+}
+
+#ifdef SGEN_HAVE_CARDTABLE
+void
+sgen_los_scan_card_table (SgenGrayQueue *queue)
{
LOSObject *obj;
sgen_cardtable_scan_object (obj->data, obj->size, NULL, queue);
}
}
-
#endif
+
+#endif /* HAVE_SGEN_GC */