11 #include "mono-codeman.h"
12 #include "mono-mmap.h"
13 #include <mono/metadata/class-internals.h>
14 #ifdef HAVE_VALGRIND_MEMCHECK_H
15 #include <valgrind/memcheck.h>
20 #if defined(__ia64__) || defined(__x86_64__)
22 * We require 16 byte alignment on amd64 so the fp literals embedded in the code are
23 * properly aligned for SSE2.
30 /* if a chunk has less than this amount of free space it's considered full */
31 #define MAX_WASTAGE 32
35 #define ARCH_MAP_FLAGS MONO_MMAP_32BIT
37 #define ARCH_MAP_FLAGS 0
40 #define MONO_PROT_RWX (MONO_MMAP_READ|MONO_MMAP_WRITE|MONO_MMAP_EXEC)
42 typedef struct _CodeChunck CodeChunk;
54 unsigned int flags: 8;
55 /* this number of bytes is available to resolve addresses far in memory */
56 unsigned int bsize: 24;
59 struct _MonoCodeManager {
65 #define ALIGN_INT(val,alignment) (((val) + (alignment - 1)) & ~(alignment - 1))
68 * mono_code_manager_new:
70 * Creates a new code manager. A code manager can be used to allocate memory
71 * suitable for storing native code that can be later executed.
72 * A code manager allocates memory from the operating system in large chunks
73 * (typically 64KB in size) so that many methods can be allocated inside them
74 * close together, improving cache locality.
76 * Returns: the new code manager
79 mono_code_manager_new (void)
81 MonoCodeManager *cman = malloc (sizeof (MonoCodeManager));
91 * mono_code_manager_new_dynamic:
93 * Creates a new code manager suitable for holding native code that can be
94 * used for single or small methods that need to be deallocated independently
95 * of other native code.
97 * Returns: the new code manager
100 mono_code_manager_new_dynamic (void)
102 MonoCodeManager *cman = mono_code_manager_new ();
109 free_chunklist (CodeChunk *chunk)
113 #if defined(HAVE_VALGRIND_MEMCHECK_H) && defined (VALGRIND_JIT_UNREGISTER_MAP)
114 int valgrind_unregister = 0;
115 if (RUNNING_ON_VALGRIND)
116 valgrind_unregister = 1;
117 #define valgrind_unregister(x) do { if (valgrind_unregister) { VALGRIND_JIT_UNREGISTER_MAP(NULL,x); } } while (0)
119 #define valgrind_unregister(x)
125 if (dead->flags == CODE_FLAG_MMAP) {
126 mono_vfree (dead->data, dead->size);
127 /* valgrind_unregister(dead->data); */
128 } else if (dead->flags == CODE_FLAG_MALLOC) {
136 * mono_code_manager_destroy:
137 * @cman: a code manager
139 * Free all the memory associated with the code manager @cman.
142 mono_code_manager_destroy (MonoCodeManager *cman)
144 free_chunklist (cman->full);
145 free_chunklist (cman->current);
150 * mono_code_manager_invalidate:
151 * @cman: a code manager
153 * Fill all the memory with an invalid native code value
154 * so that any attempt to execute code allocated in the code
155 * manager @cman will fail. This is used for debugging purposes.
158 mono_code_manager_invalidate (MonoCodeManager *cman)
162 #if defined(__i386__) || defined(__x86_64__)
163 int fill_value = 0xcc; /* x86 break */
165 int fill_value = 0x2a;
168 for (chunk = cman->current; chunk; chunk = chunk->next)
169 memset (chunk->data, fill_value, chunk->size);
170 for (chunk = cman->full; chunk; chunk = chunk->next)
171 memset (chunk->data, fill_value, chunk->size);
175 * mono_code_manager_foreach:
176 * @cman: a code manager
177 * @func: a callback function pointer
178 * @user_data: additional data to pass to @func
180 * Invokes the callback @func for each different chunk of memory allocated
181 * in the code manager @cman.
184 mono_code_manager_foreach (MonoCodeManager *cman, MonoCodeManagerFunc func, void *user_data)
187 for (chunk = cman->current; chunk; chunk = chunk->next) {
188 if (func (chunk->data, chunk->size, chunk->bsize, user_data))
191 for (chunk = cman->full; chunk; chunk = chunk->next) {
192 if (func (chunk->data, chunk->size, chunk->bsize, user_data))
197 /* BIND_ROOM is the divisor for the chunck of code size dedicated
198 * to binding branches (branches not reachable with the immediate displacement)
199 * bind_size = size/BIND_ROOM;
200 * we should reduce it and make MIN_PAGES bigger for such systems
202 #if defined(__ppc__) || defined(__powerpc__)
210 new_codechunk (int dynamic, int size)
212 int minsize, flags = CODE_FLAG_MMAP;
213 int chunk_size, bsize = 0;
219 flags = CODE_FLAG_MALLOC;
222 pagesize = mono_pagesize ();
226 flags = CODE_FLAG_MALLOC;
228 minsize = pagesize * MIN_PAGES;
230 chunk_size = minsize;
233 chunk_size += pagesize - 1;
234 chunk_size &= ~ (pagesize - 1);
238 bsize = chunk_size / BIND_ROOM;
239 if (bsize < MIN_BSIZE)
241 bsize += MIN_ALIGN -1;
242 bsize &= ~ (MIN_ALIGN - 1);
243 if (chunk_size - size < bsize) {
244 chunk_size = size + bsize;
245 chunk_size += pagesize - 1;
246 chunk_size &= ~ (pagesize - 1);
250 /* does it make sense to use the mmap-like API? */
251 if (flags == CODE_FLAG_MALLOC) {
252 ptr = malloc (chunk_size + MIN_ALIGN - 1);
256 ptr = mono_valloc (NULL, chunk_size, MONO_PROT_RWX | ARCH_MAP_FLAGS);
261 if (flags == CODE_FLAG_MALLOC) {
263 * AMD64 processors maintain icache coherency only for pages which are
266 #ifndef PLATFORM_WIN32
268 char *page_start = (char *) (((gssize) (ptr)) & ~ (pagesize - 1));
269 int pages = ((char*)ptr + chunk_size - page_start + pagesize - 1) / pagesize;
270 int err = mono_mprotect (page_start, pages * pagesize, MONO_PROT_RWX);
276 /* Make sure the thunks area is zeroed */
277 memset (ptr, 0, bsize);
281 chunk = malloc (sizeof (CodeChunk));
283 if (flags == CODE_FLAG_MALLOC)
286 mono_vfree (ptr, chunk_size);
290 chunk->size = chunk_size;
292 chunk->flags = flags;
294 chunk->bsize = bsize;
296 /*printf ("code chunk at: %p\n", ptr);*/
301 * mono_code_manager_reserve:
302 * @cman: a code manager
303 * @size: size of memory to allocate
304 * @alignment: power of two alignment value
306 * Allocates at least @size bytes of memory inside the code manager @cman.
308 * Returns: the pointer to the allocated memory or #NULL on failure
311 mono_code_manager_reserve_align (MonoCodeManager *cman, int size, int alignment)
313 CodeChunk *chunk, *prev;
316 /* eventually allow bigger alignments, but we need to fix the dynamic alloc code to
319 g_assert (alignment <= MIN_ALIGN);
322 ++mono_stats.dynamic_code_alloc_count;
323 mono_stats.dynamic_code_bytes_count += size;
326 if (!cman->current) {
327 cman->current = new_codechunk (cman->dynamic, size);
332 for (chunk = cman->current; chunk; chunk = chunk->next) {
333 if (ALIGN_INT (chunk->pos, alignment) + size <= chunk->size) {
334 chunk->pos = ALIGN_INT (chunk->pos, alignment);
335 ptr = chunk->data + chunk->pos;
341 * no room found, move one filled chunk to cman->full
342 * to keep cman->current from growing too much
345 for (chunk = cman->current; chunk; prev = chunk, chunk = chunk->next) {
346 if (chunk->pos + MIN_ALIGN * 4 <= chunk->size)
349 prev->next = chunk->next;
351 cman->current = chunk->next;
353 chunk->next = cman->full;
357 chunk = new_codechunk (cman->dynamic, size);
360 chunk->next = cman->current;
361 cman->current = chunk;
362 chunk->pos = ALIGN_INT (chunk->pos, alignment);
363 ptr = chunk->data + chunk->pos;
369 * mono_code_manager_reserve:
370 * @cman: a code manager
371 * @size: size of memory to allocate
373 * Allocates at least @size bytes of memory inside the code manager @cman.
375 * Returns: the pointer to the allocated memory or #NULL on failure
378 mono_code_manager_reserve (MonoCodeManager *cman, int size)
380 return mono_code_manager_reserve_align (cman, size, MIN_ALIGN);
384 * mono_code_manager_commit:
385 * @cman: a code manager
386 * @data: the pointer returned by mono_code_manager_reserve ()
387 * @size: the size requested in the call to mono_code_manager_reserve ()
388 * @newsize: the new size to reserve
390 * If we reserved too much room for a method and we didn't allocate
391 * already from the code manager, we can get back the excess allocation
392 * for later use in the code manager.
395 mono_code_manager_commit (MonoCodeManager *cman, void *data, int size, int newsize)
397 g_assert (newsize <= size);
399 if (cman->current && (size != newsize) && (data == cman->current->data + cman->current->pos - size)) {
400 cman->current->pos -= size - newsize;
405 * mono_code_manager_size:
406 * @cman: a code manager
407 * @used_size: pointer to an integer for the result
409 * This function can be used to get statistics about a code manager:
410 * the integer pointed to by @used_size will contain how much
411 * memory is actually used inside the code managed @cman.
413 * Returns: the amount of memory allocated in @cman
416 mono_code_manager_size (MonoCodeManager *cman, int *used_size)
421 for (chunk = cman->current; chunk; chunk = chunk->next) {
425 for (chunk = cman->full; chunk; chunk = chunk->next) {