12 #define USE_DL_PREFIX 1
14 #include "mono-codeman.h"
15 #include "mono-mmap.h"
17 #include <mono/metadata/class-internals.h>
18 #ifdef HAVE_VALGRIND_MEMCHECK_H
19 #include <valgrind/memcheck.h>
23 * AMD64 processors maintain icache coherency only for pages which are
24 * marked executable. Also, windows DEP requires us to obtain executable memory from
25 * malloc when using dynamic code managers. The system malloc can't do this so we use a
26 * slighly modified version of Doug Lea's Malloc package for this purpose:
27 * http://g.oswego.edu/dl/html/malloc.html
32 #if defined(__ia64__) || defined(__x86_64__)
34 * We require 16 byte alignment on amd64 so the fp literals embedded in the code are
35 * properly aligned for SSE2.
42 /* if a chunk has less than this amount of free space it's considered full */
43 #define MAX_WASTAGE 32
47 #define ARCH_MAP_FLAGS MONO_MMAP_32BIT
49 #define ARCH_MAP_FLAGS 0
52 #define MONO_PROT_RWX (MONO_MMAP_READ|MONO_MMAP_WRITE|MONO_MMAP_EXEC)
54 typedef struct _CodeChunck CodeChunk;
66 unsigned int flags: 8;
67 /* this number of bytes is available to resolve addresses far in memory */
68 unsigned int bsize: 24;
71 struct _MonoCodeManager {
78 #define ALIGN_INT(val,alignment) (((val) + (alignment - 1)) & ~(alignment - 1))
81 * mono_code_manager_new:
83 * Creates a new code manager. A code manager can be used to allocate memory
84 * suitable for storing native code that can be later executed.
85 * A code manager allocates memory from the operating system in large chunks
86 * (typically 64KB in size) so that many methods can be allocated inside them
87 * close together, improving cache locality.
89 * Returns: the new code manager
92 mono_code_manager_new (void)
94 MonoCodeManager *cman = malloc (sizeof (MonoCodeManager));
105 * mono_code_manager_new_dynamic:
107 * Creates a new code manager suitable for holding native code that can be
108 * used for single or small methods that need to be deallocated independently
109 * of other native code.
111 * Returns: the new code manager
114 mono_code_manager_new_dynamic (void)
116 MonoCodeManager *cman = mono_code_manager_new ();
123 free_chunklist (CodeChunk *chunk)
127 #if defined(HAVE_VALGRIND_MEMCHECK_H) && defined (VALGRIND_JIT_UNREGISTER_MAP)
128 int valgrind_unregister = 0;
129 if (RUNNING_ON_VALGRIND)
130 valgrind_unregister = 1;
131 #define valgrind_unregister(x) do { if (valgrind_unregister) { VALGRIND_JIT_UNREGISTER_MAP(NULL,x); } } while (0)
133 #define valgrind_unregister(x)
139 if (dead->flags == CODE_FLAG_MMAP) {
140 mono_vfree (dead->data, dead->size);
141 /* valgrind_unregister(dead->data); */
142 } else if (dead->flags == CODE_FLAG_MALLOC) {
150 * mono_code_manager_destroy:
151 * @cman: a code manager
153 * Free all the memory associated with the code manager @cman.
156 mono_code_manager_destroy (MonoCodeManager *cman)
158 free_chunklist (cman->full);
159 free_chunklist (cman->current);
164 * mono_code_manager_invalidate:
165 * @cman: a code manager
167 * Fill all the memory with an invalid native code value
168 * so that any attempt to execute code allocated in the code
169 * manager @cman will fail. This is used for debugging purposes.
172 mono_code_manager_invalidate (MonoCodeManager *cman)
176 #if defined(__i386__) || defined(__x86_64__)
177 int fill_value = 0xcc; /* x86 break */
179 int fill_value = 0x2a;
182 for (chunk = cman->current; chunk; chunk = chunk->next)
183 memset (chunk->data, fill_value, chunk->size);
184 for (chunk = cman->full; chunk; chunk = chunk->next)
185 memset (chunk->data, fill_value, chunk->size);
189 * mono_code_manager_set_read_only:
190 * @cman: a code manager
192 * Make the code manager read only, so further allocation requests cause an assert.
195 mono_code_manager_set_read_only (MonoCodeManager *cman)
197 cman->read_only = TRUE;
201 * mono_code_manager_foreach:
202 * @cman: a code manager
203 * @func: a callback function pointer
204 * @user_data: additional data to pass to @func
206 * Invokes the callback @func for each different chunk of memory allocated
207 * in the code manager @cman.
210 mono_code_manager_foreach (MonoCodeManager *cman, MonoCodeManagerFunc func, void *user_data)
213 for (chunk = cman->current; chunk; chunk = chunk->next) {
214 if (func (chunk->data, chunk->size, chunk->bsize, user_data))
217 for (chunk = cman->full; chunk; chunk = chunk->next) {
218 if (func (chunk->data, chunk->size, chunk->bsize, user_data))
223 /* BIND_ROOM is the divisor for the chunck of code size dedicated
224 * to binding branches (branches not reachable with the immediate displacement)
225 * bind_size = size/BIND_ROOM;
226 * we should reduce it and make MIN_PAGES bigger for such systems
228 #if defined(__ppc__) || defined(__powerpc__)
236 new_codechunk (int dynamic, int size)
238 int minsize, flags = CODE_FLAG_MMAP;
239 int chunk_size, bsize = 0;
245 flags = CODE_FLAG_MALLOC;
248 pagesize = mono_pagesize ();
252 flags = CODE_FLAG_MALLOC;
254 minsize = pagesize * MIN_PAGES;
256 chunk_size = minsize;
259 chunk_size += pagesize - 1;
260 chunk_size &= ~ (pagesize - 1);
264 bsize = chunk_size / BIND_ROOM;
265 if (bsize < MIN_BSIZE)
267 bsize += MIN_ALIGN -1;
268 bsize &= ~ (MIN_ALIGN - 1);
269 if (chunk_size - size < bsize) {
270 chunk_size = size + bsize;
271 chunk_size += pagesize - 1;
272 chunk_size &= ~ (pagesize - 1);
276 if (flags == CODE_FLAG_MALLOC) {
277 ptr = dlmemalign (MIN_ALIGN, chunk_size + MIN_ALIGN - 1);
281 ptr = mono_valloc (NULL, chunk_size, MONO_PROT_RWX | ARCH_MAP_FLAGS);
286 if (flags == CODE_FLAG_MALLOC) {
288 /* Make sure the thunks area is zeroed */
289 memset (ptr, 0, bsize);
293 chunk = malloc (sizeof (CodeChunk));
295 if (flags == CODE_FLAG_MALLOC)
298 mono_vfree (ptr, chunk_size);
302 chunk->size = chunk_size;
304 chunk->flags = flags;
306 chunk->bsize = bsize;
308 /*printf ("code chunk at: %p\n", ptr);*/
313 * mono_code_manager_reserve:
314 * @cman: a code manager
315 * @size: size of memory to allocate
316 * @alignment: power of two alignment value
318 * Allocates at least @size bytes of memory inside the code manager @cman.
320 * Returns: the pointer to the allocated memory or #NULL on failure
323 mono_code_manager_reserve_align (MonoCodeManager *cman, int size, int alignment)
325 CodeChunk *chunk, *prev;
328 g_assert (!cman->read_only);
330 /* eventually allow bigger alignments, but we need to fix the dynamic alloc code to
333 g_assert (alignment <= MIN_ALIGN);
336 ++mono_stats.dynamic_code_alloc_count;
337 mono_stats.dynamic_code_bytes_count += size;
340 if (!cman->current) {
341 cman->current = new_codechunk (cman->dynamic, size);
346 for (chunk = cman->current; chunk; chunk = chunk->next) {
347 if (ALIGN_INT (chunk->pos, alignment) + size <= chunk->size) {
348 chunk->pos = ALIGN_INT (chunk->pos, alignment);
349 ptr = chunk->data + chunk->pos;
355 * no room found, move one filled chunk to cman->full
356 * to keep cman->current from growing too much
359 for (chunk = cman->current; chunk; prev = chunk, chunk = chunk->next) {
360 if (chunk->pos + MIN_ALIGN * 4 <= chunk->size)
363 prev->next = chunk->next;
365 cman->current = chunk->next;
367 chunk->next = cman->full;
371 chunk = new_codechunk (cman->dynamic, size);
374 chunk->next = cman->current;
375 cman->current = chunk;
376 chunk->pos = ALIGN_INT (chunk->pos, alignment);
377 ptr = chunk->data + chunk->pos;
383 * mono_code_manager_reserve:
384 * @cman: a code manager
385 * @size: size of memory to allocate
387 * Allocates at least @size bytes of memory inside the code manager @cman.
389 * Returns: the pointer to the allocated memory or #NULL on failure
392 mono_code_manager_reserve (MonoCodeManager *cman, int size)
394 return mono_code_manager_reserve_align (cman, size, MIN_ALIGN);
398 * mono_code_manager_commit:
399 * @cman: a code manager
400 * @data: the pointer returned by mono_code_manager_reserve ()
401 * @size: the size requested in the call to mono_code_manager_reserve ()
402 * @newsize: the new size to reserve
404 * If we reserved too much room for a method and we didn't allocate
405 * already from the code manager, we can get back the excess allocation
406 * for later use in the code manager.
409 mono_code_manager_commit (MonoCodeManager *cman, void *data, int size, int newsize)
411 g_assert (newsize <= size);
413 if (cman->current && (size != newsize) && (data == cman->current->data + cman->current->pos - size)) {
414 cman->current->pos -= size - newsize;
419 * mono_code_manager_size:
420 * @cman: a code manager
421 * @used_size: pointer to an integer for the result
423 * This function can be used to get statistics about a code manager:
424 * the integer pointed to by @used_size will contain how much
425 * memory is actually used inside the code managed @cman.
427 * Returns: the amount of memory allocated in @cman
430 mono_code_manager_size (MonoCodeManager *cman, int *used_size)
435 for (chunk = cman->current; chunk; chunk = chunk->next) {
439 for (chunk = cman->full; chunk; chunk = chunk->next) {