12 #define USE_DL_PREFIX 1
14 #include "mono-codeman.h"
15 #include "mono-mmap.h"
17 #include <mono/metadata/class-internals.h>
18 #include <mono/metadata/profiler-private.h>
19 #ifdef HAVE_VALGRIND_MEMCHECK_H
20 #include <valgrind/memcheck.h>
24 * AMD64 processors maintain icache coherency only for pages which are
25 * marked executable. Also, windows DEP requires us to obtain executable memory from
26 * malloc when using dynamic code managers. The system malloc can't do this so we use a
27 * slighly modified version of Doug Lea's Malloc package for this purpose:
28 * http://g.oswego.edu/dl/html/malloc.html
33 #if defined(__ia64__) || defined(__x86_64__)
35 * We require 16 byte alignment on amd64 so the fp literals embedded in the code are
36 * properly aligned for SSE2.
43 /* if a chunk has less than this amount of free space it's considered full */
44 #define MAX_WASTAGE 32
48 #define ARCH_MAP_FLAGS MONO_MMAP_32BIT
50 #define ARCH_MAP_FLAGS 0
53 #define MONO_PROT_RWX (MONO_MMAP_READ|MONO_MMAP_WRITE|MONO_MMAP_EXEC)
55 typedef struct _CodeChunck CodeChunk
;
67 unsigned int flags
: 8;
68 /* this number of bytes is available to resolve addresses far in memory */
69 unsigned int bsize
: 24;
72 struct _MonoCodeManager
{
79 #define ALIGN_INT(val,alignment) (((val) + (alignment - 1)) & ~(alignment - 1))
82 * mono_code_manager_new:
84 * Creates a new code manager. A code manager can be used to allocate memory
85 * suitable for storing native code that can be later executed.
86 * A code manager allocates memory from the operating system in large chunks
87 * (typically 64KB in size) so that many methods can be allocated inside them
88 * close together, improving cache locality.
90 * Returns: the new code manager
93 mono_code_manager_new (void)
95 MonoCodeManager
*cman
= malloc (sizeof (MonoCodeManager
));
106 * mono_code_manager_new_dynamic:
108 * Creates a new code manager suitable for holding native code that can be
109 * used for single or small methods that need to be deallocated independently
110 * of other native code.
112 * Returns: the new code manager
115 mono_code_manager_new_dynamic (void)
117 MonoCodeManager
*cman
= mono_code_manager_new ();
124 free_chunklist (CodeChunk
*chunk
)
128 #if defined(HAVE_VALGRIND_MEMCHECK_H) && defined (VALGRIND_JIT_UNREGISTER_MAP)
129 int valgrind_unregister
= 0;
130 if (RUNNING_ON_VALGRIND
)
131 valgrind_unregister
= 1;
132 #define valgrind_unregister(x) do { if (valgrind_unregister) { VALGRIND_JIT_UNREGISTER_MAP(NULL,x); } } while (0)
134 #define valgrind_unregister(x)
139 mono_profiler_code_chunk_destroy ((gpointer
) dead
->data
);
141 if (dead
->flags
== CODE_FLAG_MMAP
) {
142 mono_vfree (dead
->data
, dead
->size
);
143 /* valgrind_unregister(dead->data); */
144 } else if (dead
->flags
== CODE_FLAG_MALLOC
) {
152 * mono_code_manager_destroy:
153 * @cman: a code manager
155 * Free all the memory associated with the code manager @cman.
158 mono_code_manager_destroy (MonoCodeManager
*cman
)
160 free_chunklist (cman
->full
);
161 free_chunklist (cman
->current
);
166 * mono_code_manager_invalidate:
167 * @cman: a code manager
169 * Fill all the memory with an invalid native code value
170 * so that any attempt to execute code allocated in the code
171 * manager @cman will fail. This is used for debugging purposes.
174 mono_code_manager_invalidate (MonoCodeManager
*cman
)
178 #if defined(__i386__) || defined(__x86_64__)
179 int fill_value
= 0xcc; /* x86 break */
181 int fill_value
= 0x2a;
184 for (chunk
= cman
->current
; chunk
; chunk
= chunk
->next
)
185 memset (chunk
->data
, fill_value
, chunk
->size
);
186 for (chunk
= cman
->full
; chunk
; chunk
= chunk
->next
)
187 memset (chunk
->data
, fill_value
, chunk
->size
);
191 * mono_code_manager_set_read_only:
192 * @cman: a code manager
194 * Make the code manager read only, so further allocation requests cause an assert.
197 mono_code_manager_set_read_only (MonoCodeManager
*cman
)
199 cman
->read_only
= TRUE
;
203 * mono_code_manager_foreach:
204 * @cman: a code manager
205 * @func: a callback function pointer
206 * @user_data: additional data to pass to @func
208 * Invokes the callback @func for each different chunk of memory allocated
209 * in the code manager @cman.
212 mono_code_manager_foreach (MonoCodeManager
*cman
, MonoCodeManagerFunc func
, void *user_data
)
215 for (chunk
= cman
->current
; chunk
; chunk
= chunk
->next
) {
216 if (func (chunk
->data
, chunk
->size
, chunk
->bsize
, user_data
))
219 for (chunk
= cman
->full
; chunk
; chunk
= chunk
->next
) {
220 if (func (chunk
->data
, chunk
->size
, chunk
->bsize
, user_data
))
225 /* BIND_ROOM is the divisor for the chunck of code size dedicated
226 * to binding branches (branches not reachable with the immediate displacement)
227 * bind_size = size/BIND_ROOM;
228 * we should reduce it and make MIN_PAGES bigger for such systems
230 #if defined(__ppc__) || defined(__powerpc__)
238 new_codechunk (int dynamic
, int size
)
240 int minsize
, flags
= CODE_FLAG_MMAP
;
241 int chunk_size
, bsize
= 0;
247 flags
= CODE_FLAG_MALLOC
;
250 pagesize
= mono_pagesize ();
254 flags
= CODE_FLAG_MALLOC
;
256 minsize
= pagesize
* MIN_PAGES
;
258 chunk_size
= minsize
;
261 chunk_size
+= pagesize
- 1;
262 chunk_size
&= ~ (pagesize
- 1);
266 bsize
= chunk_size
/ BIND_ROOM
;
267 if (bsize
< MIN_BSIZE
)
269 bsize
+= MIN_ALIGN
-1;
270 bsize
&= ~ (MIN_ALIGN
- 1);
271 if (chunk_size
- size
< bsize
) {
272 chunk_size
= size
+ bsize
;
273 chunk_size
+= pagesize
- 1;
274 chunk_size
&= ~ (pagesize
- 1);
278 if (flags
== CODE_FLAG_MALLOC
) {
279 ptr
= dlmemalign (MIN_ALIGN
, chunk_size
+ MIN_ALIGN
- 1);
283 ptr
= mono_valloc (NULL
, chunk_size
, MONO_PROT_RWX
| ARCH_MAP_FLAGS
);
288 if (flags
== CODE_FLAG_MALLOC
) {
290 /* Make sure the thunks area is zeroed */
291 memset (ptr
, 0, bsize
);
295 chunk
= malloc (sizeof (CodeChunk
));
297 if (flags
== CODE_FLAG_MALLOC
)
300 mono_vfree (ptr
, chunk_size
);
304 chunk
->size
= chunk_size
;
306 chunk
->flags
= flags
;
308 chunk
->bsize
= bsize
;
309 mono_profiler_code_chunk_new((gpointer
) chunk
->data
, chunk
->size
);
311 /*printf ("code chunk at: %p\n", ptr);*/
316 * mono_code_manager_reserve:
317 * @cman: a code manager
318 * @size: size of memory to allocate
319 * @alignment: power of two alignment value
321 * Allocates at least @size bytes of memory inside the code manager @cman.
323 * Returns: the pointer to the allocated memory or #NULL on failure
326 mono_code_manager_reserve_align (MonoCodeManager
*cman
, int size
, int alignment
)
328 CodeChunk
*chunk
, *prev
;
331 g_assert (!cman
->read_only
);
333 /* eventually allow bigger alignments, but we need to fix the dynamic alloc code to
336 g_assert (alignment
<= MIN_ALIGN
);
339 ++mono_stats
.dynamic_code_alloc_count
;
340 mono_stats
.dynamic_code_bytes_count
+= size
;
343 if (!cman
->current
) {
344 cman
->current
= new_codechunk (cman
->dynamic
, size
);
349 for (chunk
= cman
->current
; chunk
; chunk
= chunk
->next
) {
350 if (ALIGN_INT (chunk
->pos
, alignment
) + size
<= chunk
->size
) {
351 chunk
->pos
= ALIGN_INT (chunk
->pos
, alignment
);
352 ptr
= chunk
->data
+ chunk
->pos
;
358 * no room found, move one filled chunk to cman->full
359 * to keep cman->current from growing too much
362 for (chunk
= cman
->current
; chunk
; prev
= chunk
, chunk
= chunk
->next
) {
363 if (chunk
->pos
+ MIN_ALIGN
* 4 <= chunk
->size
)
366 prev
->next
= chunk
->next
;
368 cman
->current
= chunk
->next
;
370 chunk
->next
= cman
->full
;
374 chunk
= new_codechunk (cman
->dynamic
, size
);
377 chunk
->next
= cman
->current
;
378 cman
->current
= chunk
;
379 chunk
->pos
= ALIGN_INT (chunk
->pos
, alignment
);
380 ptr
= chunk
->data
+ chunk
->pos
;
386 * mono_code_manager_reserve:
387 * @cman: a code manager
388 * @size: size of memory to allocate
390 * Allocates at least @size bytes of memory inside the code manager @cman.
392 * Returns: the pointer to the allocated memory or #NULL on failure
395 mono_code_manager_reserve (MonoCodeManager
*cman
, int size
)
397 return mono_code_manager_reserve_align (cman
, size
, MIN_ALIGN
);
401 * mono_code_manager_commit:
402 * @cman: a code manager
403 * @data: the pointer returned by mono_code_manager_reserve ()
404 * @size: the size requested in the call to mono_code_manager_reserve ()
405 * @newsize: the new size to reserve
407 * If we reserved too much room for a method and we didn't allocate
408 * already from the code manager, we can get back the excess allocation
409 * for later use in the code manager.
412 mono_code_manager_commit (MonoCodeManager
*cman
, void *data
, int size
, int newsize
)
414 g_assert (newsize
<= size
);
416 if (cman
->current
&& (size
!= newsize
) && (data
== cman
->current
->data
+ cman
->current
->pos
- size
)) {
417 cman
->current
->pos
-= size
- newsize
;
422 * mono_code_manager_size:
423 * @cman: a code manager
424 * @used_size: pointer to an integer for the result
426 * This function can be used to get statistics about a code manager:
427 * the integer pointed to by @used_size will contain how much
428 * memory is actually used inside the code managed @cman.
430 * Returns: the amount of memory allocated in @cman
433 mono_code_manager_size (MonoCodeManager
*cman
, int *used_size
)
438 for (chunk
= cman
->current
; chunk
; chunk
= chunk
->next
) {
442 for (chunk
= cman
->full
; chunk
; chunk
= chunk
->next
) {