2007-10-19 Marek Habersack <mhabersack@novell.com>
[mono.git] / mono / utils / mono-codeman.c
index 8baa34907c3c7b7229f45e6098e28cd76c477825..92cb35a4cd540d1f68009d690b897a7cc7f2d45c 100644 (file)
@@ -62,6 +62,19 @@ struct _MonoCodeManager {
        CodeChunk *full;
 };
 
+#define ALIGN_INT(val,alignment) (((val) + (alignment - 1)) & ~(alignment - 1))
+
+/**
+ * mono_code_manager_new:
+ *
+ * Creates a new code manager. A code manager can be used to allocate memory
+ * suitable for storing native code that can be later executed.
+ * A code manager allocates memory from the operating system in large chunks
+ * (typically 64KB in size) so that many methods can be allocated inside them
+ * close together, improving cache locality.
+ *
+ * Returns: the new code manager
+ */
 MonoCodeManager* 
 mono_code_manager_new (void)
 {
@@ -74,6 +87,15 @@ mono_code_manager_new (void)
        return cman;
 }
 
+/**
+ * mono_code_manager_new_dynamic:
+ *
+ * Creates a new code manager suitable for holding native code that can be
+ * used for single or small methods that need to be deallocated independently
+ * of other native code.
+ *
+ * Returns: the new code manager
+ */
 MonoCodeManager* 
 mono_code_manager_new_dynamic (void)
 {
@@ -102,7 +124,7 @@ free_chunklist (CodeChunk *chunk)
                chunk = chunk->next;
                if (dead->flags == CODE_FLAG_MMAP) {
                        mono_vfree (dead->data, dead->size);
-                       valgrind_unregister(dead->data);
+                       /* valgrind_unregister(dead->data); */
                } else if (dead->flags == CODE_FLAG_MALLOC) {
                        free (dead->data);
                }
@@ -110,6 +132,12 @@ free_chunklist (CodeChunk *chunk)
        }
 }
 
+/**
+ * mono_code_manager_destroy:
+ * @cman: a code manager
+ *
+ * Free all the memory associated with the code manager @cman.
+ */
 void
 mono_code_manager_destroy (MonoCodeManager *cman)
 {
@@ -118,7 +146,14 @@ mono_code_manager_destroy (MonoCodeManager *cman)
        free (cman);
 }
 
-/* fill all the memory with the 0x2a (42) value */
+/**
+ * mono_code_manager_invalidate:
+ * @cman: a code manager
+ *
+ * Fill all the memory with an invalid native code value
+ * so that any attempt to execute code allocated in the code
+ * manager @cman will fail. This is used for debugging purposes.
+ */
 void             
 mono_code_manager_invalidate (MonoCodeManager *cman)
 {
@@ -136,6 +171,15 @@ mono_code_manager_invalidate (MonoCodeManager *cman)
                memset (chunk->data, fill_value, chunk->size);
 }
 
+/**
+ * mono_code_manager_foreach:
+ * @cman: a code manager
+ * @func: a callback function pointer
+ * @user_data: additional data to pass to @func
+ *
+ * Invokes the callback @func for each different chunk of memory allocated
+ * in the code manager @cman.
+ */
 void
 mono_code_manager_foreach (MonoCodeManager *cman, MonoCodeManagerFunc func, void *user_data)
 {
@@ -205,7 +249,7 @@ new_codechunk (int dynamic, int size)
 
        /* does it make sense to use the mmap-like API? */
        if (flags == CODE_FLAG_MALLOC) {
-               ptr = malloc (chunk_size);
+               ptr = malloc (chunk_size + MIN_ALIGN - 1);
                if (!ptr)
                        return NULL;
        } else {
@@ -253,14 +297,26 @@ new_codechunk (int dynamic, int size)
        return chunk;
 }
 
+/**
+ * mono_code_manager_reserve:
+ * @cman: a code manager
+ * @size: size of memory to allocate
+ * @alignment: power of two alignment value
+ *
+ * Allocates at least @size bytes of memory inside the code manager @cman.
+ *
+ * Returns: the pointer to the allocated memory or #NULL on failure
+ */
 void*
-mono_code_manager_reserve (MonoCodeManager *cman, int size)
+mono_code_manager_reserve_align (MonoCodeManager *cman, int size, int alignment)
 {
        CodeChunk *chunk, *prev;
        void *ptr;
-       
-       size += MIN_ALIGN;
-       size &= ~ (MIN_ALIGN - 1);
+
+       /* eventually allow bigger alignments, but we need to fix the dynamic alloc code to
+        * handle this before
+        */
+       g_assert (alignment <= MIN_ALIGN);
 
        if (cman->dynamic) {
                ++mono_stats.dynamic_code_alloc_count;
@@ -274,7 +330,8 @@ mono_code_manager_reserve (MonoCodeManager *cman, int size)
        }
 
        for (chunk = cman->current; chunk; chunk = chunk->next) {
-               if (chunk->pos + size <= chunk->size) {
+               if (ALIGN_INT (chunk->pos, alignment) + size <= chunk->size) {
+                       chunk->pos = ALIGN_INT (chunk->pos, alignment);
                        ptr = chunk->data + chunk->pos;
                        chunk->pos += size;
                        return ptr;
@@ -302,25 +359,75 @@ mono_code_manager_reserve (MonoCodeManager *cman, int size)
                return NULL;
        chunk->next = cman->current;
        cman->current = chunk;
+       chunk->pos = ALIGN_INT (chunk->pos, alignment);
        ptr = chunk->data + chunk->pos;
        chunk->pos += size;
        return ptr;
 }
 
-/* 
- * if we reserved too much room for a method and we didn't allocate
- * already from the code manager, we can get back the excess allocation.
+/**
+ * mono_code_manager_reserve:
+ * @cman: a code manager
+ * @size: size of memory to allocate
+ *
+ * Allocates at least @size bytes of memory inside the code manager @cman.
+ *
+ * Returns: the pointer to the allocated memory or #NULL on failure
+ */
+void*
+mono_code_manager_reserve (MonoCodeManager *cman, int size)
+{
+       return mono_code_manager_reserve_align (cman, size, MIN_ALIGN);
+}
+
+/**
+ * mono_code_manager_commit:
+ * @cman: a code manager
+ * @data: the pointer returned by mono_code_manager_reserve ()
+ * @size: the size requested in the call to mono_code_manager_reserve ()
+ * @newsize: the new size to reserve
+ *
+ * If we reserved too much room for a method and we didn't allocate
+ * already from the code manager, we can get back the excess allocation
+ * for later use in the code manager.
  */
 void
 mono_code_manager_commit (MonoCodeManager *cman, void *data, int size, int newsize)
 {
-       newsize += MIN_ALIGN;
-       newsize &= ~ (MIN_ALIGN - 1);
-       size += MIN_ALIGN;
-       size &= ~ (MIN_ALIGN - 1);
+       g_assert (newsize <= size);
 
        if (cman->current && (size != newsize) && (data == cman->current->data + cman->current->pos - size)) {
                cman->current->pos -= size - newsize;
        }
 }
 
+/**
+ * mono_code_manager_size:
+ * @cman: a code manager
+ * @used_size: pointer to an integer for the result
+ *
+ * This function can be used to get statistics about a code manager:
+ * the integer pointed to by @used_size will contain how much
+ * memory is actually used inside the code managed @cman.
+ *
+ * Returns: the amount of memory allocated in @cman
+ */
+int
+mono_code_manager_size (MonoCodeManager *cman, int *used_size)
+{
+       CodeChunk *chunk;
+       guint32 size = 0;
+       guint32 used = 0;
+       for (chunk = cman->current; chunk; chunk = chunk->next) {
+               size += chunk->size;
+               used += chunk->pos;
+       }
+       for (chunk = cman->full; chunk; chunk = chunk->next) {
+               size += chunk->size;
+               used += chunk->pos;
+       }
+       if (used_size)
+               *used_size = used;
+       return size;
+}
+