11 #include <sys/types.h>
17 #include "mono-codeman.h"
25 /* if a chunk has less than this amount of free space it's considered full */
26 #define MAX_WASTAGE 32
30 #define MAP_ANONYMOUS MAP_ANON
36 typedef struct _CodeChunck CodeChunk;
48 unsigned int flags: 8;
49 /* this number of bytes is available to resolve addresses far in memory */
50 unsigned int bsize: 24;
53 struct _MonoCodeManager {
60 mono_code_manager_new (void)
62 MonoCodeManager *cman = malloc (sizeof (MonoCodeManager));
72 mono_code_manager_new_dynamic (void)
74 MonoCodeManager *cman = mono_code_manager_new ();
81 free_chunklist (CodeChunk *chunk)
87 if (dead->flags == CODE_FLAG_MMAP) {
89 munmap (dead->data, dead->size);
91 } else if (dead->flags == CODE_FLAG_MALLOC) {
99 mono_code_manager_destroy (MonoCodeManager *cman)
101 free_chunklist (cman->full);
102 free_chunklist (cman->current);
106 /* fill all the memory with the 0x2a (42) value */
108 mono_code_manager_invalidate (MonoCodeManager *cman)
112 #if defined(__i386__) || defined(__x86_64__)
113 int fill_value = 0xcc; /* x86 break */
115 int fill_value = 0x2a;
118 for (chunk = cman->current; chunk; chunk = chunk->next)
119 memset (chunk->data, fill_value, chunk->size);
120 for (chunk = cman->full; chunk; chunk = chunk->next)
121 memset (chunk->data, fill_value, chunk->size);
125 mono_code_manager_foreach (MonoCodeManager *cman, MonoCodeManagerFunc func, void *user_data)
128 for (chunk = cman->current; chunk; chunk = chunk->next) {
129 if (func (chunk->data, chunk->size, chunk->bsize, user_data))
132 for (chunk = cman->full; chunk; chunk = chunk->next) {
133 if (func (chunk->data, chunk->size, chunk->bsize, user_data))
139 query_pagesize (void)
141 #ifdef PLATFORM_WIN32
143 GetSystemInfo (&info);
144 return info.dwAllocationGranularity;
146 return getpagesize ();
150 /* BIND_ROOM is the divisor for the chunck of code size dedicated
151 * to binding branches (branches not reachable with the immediate displacement)
152 * bind_size = size/BIND_ROOM;
153 * we should reduce it and make MIN_PAGES bigger for such systems
155 #if defined(__ppc__) || defined(__powerpc__)
160 new_codechunk (int dynamic, int size)
162 static int pagesize = 0;
163 int minsize, flags = CODE_FLAG_MMAP;
164 int chunk_size, bsize = 0;
169 flags = CODE_FLAG_MALLOC;
174 flags = CODE_FLAG_MALLOC;
178 pagesize = query_pagesize ();
180 minsize = pagesize * MIN_PAGES;
182 chunk_size = minsize;
185 chunk_size += pagesize - 1;
186 chunk_size &= ~ (pagesize - 1);
190 bsize = chunk_size / BIND_ROOM;
191 if (chunk_size - size < bsize) {
193 chunk_size = size + bsize;
195 chunk_size += pagesize;
199 /* does it make sense to use the mmap-like API? */
200 if (flags == CODE_FLAG_MALLOC) {
201 ptr = malloc (chunk_size);
208 ptr = mmap (0, chunk_size, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
209 if (ptr == (void*)-1) {
210 int fd = open ("/dev/zero", O_RDONLY);
212 ptr = mmap (0, chunk_size, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE, fd, 0);
215 if (ptr == (void*)-1) {
216 ptr = malloc (chunk_size);
219 flags = CODE_FLAG_MALLOC;
227 if (flags == CODE_FLAG_MALLOC) {
229 * AMD64 processors maintain icache coherency only for pages which are
232 #ifndef PLATFORM_WIN32
234 char *page_start = (char *) (((unsigned long long) (ptr)) & ~ (pagesize - 1));
235 int pages = ((char*)ptr + chunk_size - page_start + pagesize - 1) / pagesize;
236 int err = mprotect (page_start, pages * pagesize, PROT_READ | PROT_WRITE | PROT_EXEC);
242 int err = VirtualProtect (ptr, chunk_size, PAGE_EXECUTE_READWRITE, &oldp);
247 /* Make sure the thunks area is zeroed */
248 memset (ptr, 0, bsize);
251 chunk = malloc (sizeof (CodeChunk));
253 if (flags == CODE_FLAG_MALLOC)
257 munmap (ptr, chunk_size);
262 chunk->size = chunk_size;
264 chunk->flags = flags;
266 chunk->bsize = bsize;
268 /*printf ("code chunk at: %p\n", ptr);*/
273 mono_code_manager_reserve (MonoCodeManager *cman, int size)
275 CodeChunk *chunk, *prev;
279 size &= ~ (MIN_ALIGN - 1);
281 if (!cman->current) {
282 cman->current = new_codechunk (cman->dynamic, size);
287 for (chunk = cman->current; chunk; chunk = chunk->next) {
288 if (chunk->pos + size <= chunk->size) {
289 ptr = chunk->data + chunk->pos;
295 * no room found, move one filled chunk to cman->full
296 * to keep cman->current from growing too much
299 for (chunk = cman->current; chunk; prev = chunk, chunk = chunk->next) {
300 if (chunk->pos + MIN_ALIGN * 4 <= chunk->size)
303 prev->next = chunk->next;
305 cman->current = chunk->next;
307 chunk->next = cman->full;
311 chunk = new_codechunk (cman->dynamic, size);
314 chunk->next = cman->current;
315 cman->current = chunk;
321 * if we reserved too much room for a method and we didn't allocate
322 * already from the code manager, we can get back the excess allocation.
325 mono_code_manager_commit (MonoCodeManager *cman, void *data, int size, int newsize)
327 newsize += MIN_ALIGN;
328 newsize &= ~ (MIN_ALIGN - 1);
330 size &= ~ (MIN_ALIGN - 1);
332 if (cman->current && (size != newsize) && (data == cman->current->data + cman->current->pos - size)) {
333 cman->current->pos -= size - newsize;