2010-03-03 Gonzalo Paniagua Javier <gonzalo@novell.com>
[mono.git] / mono / utils / mono-codeman.c
index 92cb35a4cd540d1f68009d690b897a7cc7f2d45c..fcef18e0f7dcddf886182188ce19566072cb2976 100644 (file)
@@ -8,12 +8,25 @@
 #include <assert.h>
 #include <glib.h>
 
+/* For dlmalloc.h */
+#define USE_DL_PREFIX 1
+
 #include "mono-codeman.h"
 #include "mono-mmap.h"
+#include "dlmalloc.h"
 #include <mono/metadata/class-internals.h>
+#include <mono/metadata/profiler-private.h>
 #ifdef HAVE_VALGRIND_MEMCHECK_H
 #include <valgrind/memcheck.h>
 #endif
+/*
+ * AMD64 processors maintain icache coherency only for pages which are 
+ * marked executable. Also, windows DEP requires us to obtain executable memory from
+ * malloc when using dynamic code managers. The system malloc can't do this so we use a 
+ * slighly modified version of Doug Lea's Malloc package for this purpose:
+ * http://g.oswego.edu/dl/html/malloc.html
+ */
 
 #define MIN_PAGES 16
 
@@ -58,6 +71,7 @@ struct _CodeChunck {
 
 struct _MonoCodeManager {
        int dynamic;
+       int read_only;
        CodeChunk *current;
        CodeChunk *full;
 };
@@ -84,6 +98,7 @@ mono_code_manager_new (void)
        cman->current = NULL;
        cman->full = NULL;
        cman->dynamic = 0;
+       cman->read_only = 0;
        return cman;
 }
 
@@ -121,12 +136,13 @@ free_chunklist (CodeChunk *chunk)
 
        for (; chunk; ) {
                dead = chunk;
+               mono_profiler_code_chunk_destroy ((gpointer) dead->data);
                chunk = chunk->next;
                if (dead->flags == CODE_FLAG_MMAP) {
                        mono_vfree (dead->data, dead->size);
                        /* valgrind_unregister(dead->data); */
                } else if (dead->flags == CODE_FLAG_MALLOC) {
-                       free (dead->data);
+                       dlfree (dead->data);
                }
                free (dead);
        }
@@ -171,6 +187,18 @@ mono_code_manager_invalidate (MonoCodeManager *cman)
                memset (chunk->data, fill_value, chunk->size);
 }
 
+/**
+ * mono_code_manager_set_read_only:
+ * @cman: a code manager
+ *
+ * Make the code manager read only, so further allocation requests cause an assert.
+ */
+void             
+mono_code_manager_set_read_only (MonoCodeManager *cman)
+{
+       cman->read_only = TRUE;
+}
+
 /**
  * mono_code_manager_foreach:
  * @cman: a code manager
@@ -247,9 +275,8 @@ new_codechunk (int dynamic, int size)
        }
 #endif
 
-       /* does it make sense to use the mmap-like API? */
        if (flags == CODE_FLAG_MALLOC) {
-               ptr = malloc (chunk_size + MIN_ALIGN - 1);
+               ptr = dlmemalign (MIN_ALIGN, chunk_size + MIN_ALIGN - 1);
                if (!ptr)
                        return NULL;
        } else {
@@ -259,29 +286,16 @@ new_codechunk (int dynamic, int size)
        }
 
        if (flags == CODE_FLAG_MALLOC) {
-               /*
-                * AMD64 processors maintain icache coherency only for pages which are 
-                * marked executable.
-                */
-#ifndef PLATFORM_WIN32
-               {
-                       char *page_start = (char *) (((gssize) (ptr)) & ~ (pagesize - 1));
-                       int pages = ((char*)ptr + chunk_size - page_start + pagesize - 1) / pagesize;
-                       int err = mono_mprotect (page_start, pages * pagesize, MONO_PROT_RWX);
-                       assert (!err);
-               }
-#endif
-
 #ifdef BIND_ROOM
-                       /* Make sure the thunks area is zeroed */
-                       memset (ptr, 0, bsize);
+               /* Make sure the thunks area is zeroed */
+               memset (ptr, 0, bsize);
 #endif
        }
 
        chunk = malloc (sizeof (CodeChunk));
        if (!chunk) {
                if (flags == CODE_FLAG_MALLOC)
-                       free (ptr);
+                       dlfree (ptr);
                else
                        mono_vfree (ptr, chunk_size);
                return NULL;
@@ -292,6 +306,7 @@ new_codechunk (int dynamic, int size)
        chunk->flags = flags;
        chunk->pos = bsize;
        chunk->bsize = bsize;
+       mono_profiler_code_chunk_new((gpointer) chunk->data, chunk->size);
 
        /*printf ("code chunk at: %p\n", ptr);*/
        return chunk;
@@ -313,6 +328,8 @@ mono_code_manager_reserve_align (MonoCodeManager *cman, int size, int alignment)
        CodeChunk *chunk, *prev;
        void *ptr;
 
+       g_assert (!cman->read_only);
+
        /* eventually allow bigger alignments, but we need to fix the dynamic alloc code to
         * handle this before
         */