diff options
| author | ptitSeb <sebastien.chev@gmail.com> | 2021-11-18 14:21:16 +0100 |
|---|---|---|
| committer | ptitSeb <sebastien.chev@gmail.com> | 2021-11-18 14:21:16 +0100 |
| commit | e7290d78d5047662c49a8558d1709ed912346ff7 (patch) | |
| tree | 10ecdc9b7b9a994087980cf5e65cfefdb48602db /src/libtools | |
| parent | 4f0e98ade5d37b8647cb5d39b6e5a3aded55fa2f (diff) | |
| download | box64-e7290d78d5047662c49a8558d1709ed912346ff7.tar.gz box64-e7290d78d5047662c49a8558d1709ed912346ff7.zip | |
[DYNAREC] Improved JIT handling, and added a HotPage detection to temporarily disable Dynarec when write occurs on the same page of some Dynablocks (help speedup some C#/Unity3D programs)
Diffstat (limited to 'src/libtools')
| -rwxr-xr-x | src/libtools/signals.c | 42 |
1 files changed, 38 insertions, 4 deletions
diff --git a/src/libtools/signals.c b/src/libtools/signals.c index 3cb84d7d..5ac76342 100755 --- a/src/libtools/signals.c +++ b/src/libtools/signals.c @@ -706,6 +706,9 @@ void my_sigactionhandler_oldcode(int32_t sig, int simple, siginfo_t* info, void } extern __thread void* current_helper; +#ifdef DYNAREC +static pthread_mutex_t mutex_dynarec_prot; +#endif void my_box64signalhandler(int32_t sig, siginfo_t* info, void * ucntx) { @@ -745,12 +748,23 @@ void my_box64signalhandler(int32_t sig, siginfo_t* info, void * ucntx) dynablock_t* db = NULL; int db_searched = 0; if ((sig==SIGSEGV) && (addr) && (info->si_code == SEGV_ACCERR) && (prot&PROT_DYNAREC)) { - // access error, unprotect the block (and mark them dirty) - unprotectDB((uintptr_t)addr, 1); // unprotect 1 byte... But then, the whole page will be unprotected + pthread_mutex_lock(&mutex_dynarec_prot); // check if SMC inside block db = FindDynablockFromNativeAddress(pc); db_searched = 1; - dynarec_log(LOG_DEBUG, "SIGSEGV with Access error on %p for %p , db=%p(%p), prot=0x%x\n", pc, addr, db, db?((void*)db->x64_addr):NULL, prot); + static uintptr_t repeated_page = 0; + dynarec_log(LOG_DEBUG, "SIGSEGV with Access error on %p for %p , db=%p(%p), prot=0x%x (old page=%p)\n", pc, addr, db, db?((void*)db->x64_addr):NULL, prot, (void*)repeated_page); + static int repeated_count = 0; + if(repeated_page == ((uintptr_t)addr&~0xfff)) { + ++repeated_count; // Access eoor multiple time on same page, disable dynarec on this page a few time... + dynarec_log(LOG_DEBUG, "Detecting a Hotpage at %p (%d)\n", (void*)repeated_page, repeated_count); + AddHotPage(repeated_page); + } else { + repeated_page = (uintptr_t)addr&~0xfff; + repeated_count = 0; + } + // access error, unprotect the block (and mark them dirty) + unprotectDB((uintptr_t)addr, 1); // unprotect 1 byte... But then, the whole page will be unprotected if(db && ((addr>=db->x64_addr && addr<(db->x64_addr+db->x64_size)) || db->need_test)) { // dynablock got auto-dirty! need to get out of it!!! emu_jmpbuf_t* ejb = GetJmpBuf(); @@ -785,17 +799,21 @@ void my_box64signalhandler(int32_t sig, siginfo_t* info, void * ucntx) dynarec_log(LOG_INFO, "Dynablock unprotected, getting out!\n"); } relockMutex(Locks); + pthread_mutex_unlock(&mutex_dynarec_prot); siglongjmp(ejb->jmpbuf, 2); } dynarec_log(LOG_INFO, "Warning, Auto-SMC (%p for db %p/%p) detected, but jmpbuffer not ready!\n", (void*)addr, db, (void*)db->x64_addr); } // done - if(prot&PROT_WRITE) { + if((prot&PROT_WRITE) || (prot&PROT_DYNAREC)) { + pthread_mutex_unlock(&mutex_dynarec_prot); // if there is no write permission, don't return and continue to program signal handling relockMutex(Locks); return; } + pthread_mutex_unlock(&mutex_dynarec_prot); } else if ((sig==SIGSEGV) && (addr) && (info->si_code == SEGV_ACCERR) && (prot&(PROT_READ|PROT_WRITE))) { + pthread_mutex_lock(&mutex_dynarec_prot); db = FindDynablockFromNativeAddress(pc); db_searched = 1; if(db && db->x64_addr>= addr && (db->x64_addr+db->x64_size)<addr) { @@ -812,6 +830,7 @@ void my_box64signalhandler(int32_t sig, siginfo_t* info, void * ucntx) glitch_addr = addr; glitch_prot = prot; relockMutex(Locks); + pthread_mutex_unlock(&mutex_dynarec_prot); return; // try again } dynarec_log(/*LOG_DEBUG*/LOG_INFO, "Repeated SIGSEGV with Access error on %p for %p, db=%p, prot=0x%x\n", pc, addr, db, prot); @@ -819,6 +838,7 @@ dynarec_log(/*LOG_DEBUG*/LOG_INFO, "Repeated SIGSEGV with Access error on %p for glitch_addr = NULL; glitch_prot = 0; } + pthread_mutex_unlock(&mutex_dynarec_prot); } #else void* db = NULL; @@ -1281,7 +1301,17 @@ EXPORT int my_swapcontext(x64emu_t* emu, void* ucp1, void* ucp2) my_setcontext(emu, ucp2); return 0; } +#ifdef DYNAREC +static void atfork_child_dynarec_prot(void) +{ + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK); + pthread_mutex_init(&mutex_dynarec_prot, &attr); + pthread_mutexattr_destroy(&attr); +} +#endif void init_signal_helper(box64context_t* context) { // setup signal handling @@ -1300,6 +1330,10 @@ void init_signal_helper(box64context_t* context) sigaction(SIGILL, &action, NULL); pthread_once(&sigstack_key_once, sigstack_key_alloc); +#ifdef DYNAREC + atfork_child_dynarec_prot(); + pthread_atfork(NULL, NULL, atfork_child_dynarec_prot); +#endif } void fini_signal_helper() |