From b66f5972f9ca126bdd2a204b8df253720fc750a9 Mon Sep 17 00:00:00 2001 From: gbeauche <> Date: Fri, 3 Oct 2003 18:18:15 +0000 Subject: [PATCH] Make sure a 32-bit B2/JIT works reasonnably well on AMD64 too. This implies to force RAMBaseHost < 0x80000000. This is empirically determined to work on Linux/x86 and Linux/amd64. --- BasiliskII/src/Unix/vm_alloc.cpp | 26 ++++++-- .../src/uae_cpu/compiler/compemu_support.cpp | 59 ++++++++++++++++++- 2 files changed, 80 insertions(+), 5 deletions(-) diff --git a/BasiliskII/src/Unix/vm_alloc.cpp b/BasiliskII/src/Unix/vm_alloc.cpp index ba97f238..5a68d0f3 100644 --- a/BasiliskII/src/Unix/vm_alloc.cpp +++ b/BasiliskII/src/Unix/vm_alloc.cpp @@ -38,20 +38,38 @@ #endif #endif +/* We want MAP_32BIT, if available, for SheepShaver and BasiliskII + because the emulated target is 32-bit and this helps to allocate + memory so that branches could be resolved more easily (32-bit + displacement to code in .text), on AMD64 for example. */ +#ifndef MAP_32BIT +#define MAP_32BIT 0 +#endif + +#define MAP_EXTRA_FLAGS (MAP_32BIT) + #ifdef HAVE_MMAP_VM -static char * next_address = 0; +#if defined(__linux__) && defined(__i386__) +/* Force a reasonnable address below 0x80000000 on x86 so that we + don't get addresses above when the program is run on AMD64. + NOTE: this is empirically determined on Linux/x86. */ +#define MAP_BASE 0x10000000 +#else +#define MAP_BASE 0x00000000 +#endif +static char * next_address = (char *)MAP_BASE; #ifdef HAVE_MMAP_ANON -#define map_flags (MAP_PRIVATE | MAP_ANON) +#define map_flags (MAP_PRIVATE | MAP_ANON | MAP_EXTRA_FLAGS) #define zero_fd -1 #else #ifdef HAVE_MMAP_ANONYMOUS -#define map_flags (MAP_PRIVATE | MAP_ANONYMOUS) +#define map_flags (MAP_PRIVATE | MAP_ANONYMOUS | MAP_EXTRA_FLAGS) #define zero_fd -1 #else #ifdef HAVE_FCNTL_H #include #endif -#define map_flags (MAP_PRIVATE) +#define map_flags (MAP_PRIVATE | MAP_EXTRA_FLAGS) static int zero_fd = -1; #endif #endif diff --git a/BasiliskII/src/uae_cpu/compiler/compemu_support.cpp b/BasiliskII/src/uae_cpu/compiler/compemu_support.cpp index 17b8c458..385f96eb 100644 --- a/BasiliskII/src/uae_cpu/compiler/compemu_support.cpp +++ b/BasiliskII/src/uae_cpu/compiler/compemu_support.cpp @@ -37,6 +37,7 @@ #define USE_NORMAL_CALLING_CONVENTION 0 #ifndef WIN32 +#include #include #include #endif @@ -5530,6 +5531,62 @@ uae_u32 get_jitted_size(void) return 0; } +const int CODE_ALLOC_MAX_ATTEMPTS = 10; +const int CODE_ALLOC_BOUNDARIES = 128 * 1024; // 128 KB + +static uint8 *do_alloc_code(uint32 size, int depth) +{ +#if defined(__linux__) && 0 + /* + This is a really awful hack that is known to work on Linux at + least. + + The trick here is to make sure the allocated cache is nearby + code segment, and more precisely in the positive half of a + 32-bit address space. i.e. addr < 0x80000000. Actually, it + turned out that a 32-bit binary run on AMD64 yields a cache + allocated around 0xa0000000, thus causing some troubles when + translating addresses from m68k to x86. + */ + static uint8 * code_base = NULL; + if (code_base == NULL) { + uintptr page_size = getpagesize(); + uintptr boundaries = CODE_ALLOC_BOUNDARIES; + if (boundaries < page_size) + boundaries = page_size; + code_base = (uint8 *)sbrk(0); + for (int attempts = 0; attempts < CODE_ALLOC_MAX_ATTEMPTS; attempts++) { + if (vm_acquire_fixed(code_base, size) == 0) { + uint8 *code = code_base; + code_base += size; + return code; + } + code_base += boundaries; + } + return NULL; + } + + if (vm_acquire_fixed(code_base, size) == 0) { + uint8 *code = code_base; + code_base += size; + return code; + } + + if (depth >= CODE_ALLOC_MAX_ATTEMPTS) + return NULL; + + return do_alloc_code(size, depth + 1); +#else + uint8 *code = (uint8 *)vm_acquire(size); + return code == VM_MAP_FAILED ? NULL : code; +#endif +} + +static inline uint8 *alloc_code(uint32 size) +{ + return do_alloc_code(size, 0); +} + void alloc_cache(void) { if (compiled_code) { @@ -5542,7 +5599,7 @@ void alloc_cache(void) return; while (!compiled_code && cache_size) { - if ((compiled_code = (uae_u8 *)vm_acquire(cache_size * 1024)) == VM_MAP_FAILED) { + if ((compiled_code = alloc_code(cache_size * 1024)) == NULL) { compiled_code = 0; cache_size /= 2; }