about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
authorptitSeb <sebastien.chev@gmail.com>2021-11-11 20:47:10 +0100
committerptitSeb <sebastien.chev@gmail.com>2021-11-11 20:47:10 +0100
commit6a1b9e050a488cb5b2e1217fd3a01e484c3d7bb7 (patch)
treeee38007ce576f32a13b6c8f9ec298002300d74ba /src
parent6675b43dd0d7eb567227bea204ee663b1e7aab4a (diff)
downloadbox64-6a1b9e050a488cb5b2e1217fd3a01e484c3d7bb7.tar.gz
box64-6a1b9e050a488cb5b2e1217fd3a01e484c3d7bb7.zip
[DYNAREC] Changed Dynarec a bit to try stabilise program using many threads and a JIT (help RimWorld Linux, but not enough to be 100% stable)
Diffstat (limited to 'src')
-rw-r--r--src/custommem.c24
-rwxr-xr-xsrc/dynarec/dynablock.c61
-rwxr-xr-xsrc/dynarec/dynarec.c2
-rwxr-xr-xsrc/dynarec/dynarec_arm64.c60
-rwxr-xr-xsrc/dynarec/dynarec_arm64_pass.c6
-rwxr-xr-xsrc/dynarec/dynarec_arm64_pass0.h4
-rwxr-xr-xsrc/dynarec/dynarec_arm64_private.h2
-rwxr-xr-xsrc/include/debug.h1
-rwxr-xr-xsrc/include/dynablock.h2
-rwxr-xr-xsrc/include/dynarec_arm64.h1
-rwxr-xr-xsrc/libtools/signals.c8
-rwxr-xr-xsrc/main.c17
12 files changed, 114 insertions, 74 deletions
diff --git a/src/custommem.c b/src/custommem.c
index 72fa4db4..3718aebe 100644
--- a/src/custommem.c
+++ b/src/custommem.c
@@ -31,7 +31,6 @@
 // init inside dynablocks.c
 KHASH_MAP_INIT_INT64(dynablocks, dynablock_t*)
 static dynablocklist_t***  dynmap123[1<<DYNAMAP_SHIFT]; // 64bits.. in 4x16bits array
-static pthread_mutex_t     mutex_mmap;
 static mmaplist_t          *mmaplist = NULL;
 static size_t              mmapsize = 0;
 static size_t              mmapcap = 0;
@@ -497,11 +496,9 @@ uintptr_t AllocDynarecMap(dynablock_t* db, size_t size)
     if(!size)
         return 0;
     if(size>MMAPSIZE-2*sizeof(blockmark_t)) {
-        pthread_mutex_lock(&mutex_mmap);
         #ifndef USE_MMAP
         void *p = NULL;
         if(posix_memalign(&p, box64_pagesize, size)) {
-            pthread_mutex_unlock(&mutex_mmap);
             dynarec_log(LOG_INFO, "Cannot create dynamic map of %zu bytes\n", size);
             return 0;
         }
@@ -509,7 +506,6 @@ uintptr_t AllocDynarecMap(dynablock_t* db, size_t size)
         #else
         void* p = mmap(NULL, size, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
         if(p==(void*)-1) {
-            pthread_mutex_unlock(&mutex_mmap);
             dynarec_log(LOG_INFO, "Cannot create dynamic map of %zu bytes\n", size);
             return 0;
         }
@@ -524,18 +520,14 @@ uintptr_t AllocDynarecMap(dynablock_t* db, size_t size)
         int ret;
         k = kh_put(dynablocks, blocks, (uintptr_t)p, &ret);
         kh_value(blocks, k) = db;
-        pthread_mutex_unlock(&mutex_mmap);
         return (uintptr_t)p;
     }
     
-    pthread_mutex_lock(&mutex_mmap);
 
     uintptr_t ret = FindFreeDynarecMap(db, size);
     if(!ret)
         ret = AddNewDynarecMap(db, size);
 
-    pthread_mutex_unlock(&mutex_mmap);
-
     return ret;
 }
 
@@ -544,7 +536,6 @@ void FreeDynarecMap(dynablock_t* db, uintptr_t addr, size_t size)
     if(!addr || !size)
         return;
     if(size>MMAPSIZE-2*sizeof(blockmark_t)) {
-        pthread_mutex_lock(&mutex_mmap);
         #ifndef USE_MMAP
         free((void*)addr);
         #else
@@ -556,12 +547,9 @@ void FreeDynarecMap(dynablock_t* db, uintptr_t addr, size_t size)
             if(k!=kh_end(blocks))
                 kh_del(dynablocks, blocks, k);
         }
-        pthread_mutex_unlock(&mutex_mmap);
         return;
     }
-    pthread_mutex_lock(&mutex_mmap);
     ActuallyFreeDynarecMap(db, addr, size);
-    pthread_mutex_unlock(&mutex_mmap);
 }
 
 dynablocklist_t* getDB(uintptr_t idx)
@@ -883,7 +871,7 @@ void setProtection(uintptr_t addr, size_t size, uint32_t prot)
     pthread_mutex_lock(&mutex_prot);
     for (uintptr_t i=(idx>>16); i<=(end>>16); ++i)
         if(memprot[i]==memprot_default) {
-            uint8_t* newblock = calloc(1<<16, sizeof(uint8_t));
+            uint8_t* newblock = calloc(MEMPROT_SIZE, sizeof(uint8_t));
 #if 0 //def ARM64   //disabled for now, not usefull with the mutex
             if (arm64_lock_storeifref(&memprot[i], newblock, memprot_default) != newblock) {
                 free(newblock);
@@ -1121,9 +1109,6 @@ int unlockCustommemMutex()
         }
     GO(mutex_blocks, 0)
     GO(mutex_prot, 1)
-    #ifdef DYNAREC
-    GO(mutex_mmap, 2)
-    #endif
     #undef GO
     return ret;
 }
@@ -1136,9 +1121,6 @@ void relockCustommemMutex(int locks)
 
     GO(mutex_blocks, 0)
     GO(mutex_prot, 1)
-    #ifdef DYNAREC
-    GO(mutex_mmap, 2)
-    #endif
     #undef GO
 }
 
@@ -1149,9 +1131,6 @@ static void init_mutexes(void)
     pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
     pthread_mutex_init(&mutex_blocks, &attr);
     pthread_mutex_init(&mutex_prot, &attr);
-#ifdef DYNAREC
-    pthread_mutex_init(&mutex_mmap, &attr);
-#endif
 
     pthread_mutexattr_destroy(&attr);
 }
@@ -1233,7 +1212,6 @@ void fini_custommem_helper(box64context_t *ctx)
             }
 
         free(mmaplist);
-        pthread_mutex_destroy(&mutex_mmap);
         for (int i3=0; i3<(1<<DYNAMAP_SHIFT); ++i3)
             if(box64_jmptbl3[i3]!=box64_jmptbldefault2) {
                 for (int i2=0; i2<(1<<DYNAMAP_SHIFT); ++i2)
diff --git a/src/dynarec/dynablock.c b/src/dynarec/dynablock.c
index 469357a7..8a1a37e2 100755
--- a/src/dynarec/dynablock.c
+++ b/src/dynarec/dynablock.c
@@ -56,12 +56,14 @@ dynablocklist_t* NewDynablockList(uintptr_t text, int textsz, int direct)
     return ret;
 }
 
-void FreeDynablock(dynablock_t* db)
+void FreeDynablock(dynablock_t* db, int need_lock)
 {
     if(db) {
-        dynarec_log(LOG_DEBUG, "FreeDynablock(%p), db->block=%p x64=%p:%p parent=%p, father=%p, with %d son(s) already gone=%d\n", db, db->block, db->x64_addr, db->x64_addr+db->x64_size, db->parent, db->father, db->sons_size, db->gone);
         if(db->gone)
             return; // already in the process of deletion!
+        dynarec_log(LOG_DEBUG, "FreeDynablock(%p), db->block=%p x64=%p:%p parent=%p, father=%p, with %d son(s) already gone=%d\n", db, db->block, db->x64_addr, db->x64_addr+db->x64_size, db->parent, db->father, db->sons_size, db->gone);
+        if(need_lock)
+            pthread_mutex_lock(&my_context->mutex_dyndump);
         db->done = 0;
         db->gone = 1;
         // remove from direct if there
@@ -77,16 +79,18 @@ void FreeDynablock(dynablock_t* db)
         // remove and free the sons
         for (int i=0; i<db->sons_size; ++i) {
             dynablock_t *son = (dynablock_t*)arm64_lock_xchg(&db->sons[i], 0);
-            FreeDynablock(son);
+            FreeDynablock(son, 0);
         }
         // only the father free the DynarecMap
         if(!db->father) {
             dynarec_log(LOG_DEBUG, " -- FreeDyrecMap(%p, %d)\n", db->block, db->size);
             FreeDynarecMap(db, (uintptr_t)db->block, db->size);
+            free(db->sons);
+            free(db->instsize);
         }
-        free(db->sons);
-        free(db->instsize);
         free(db);
+        if(need_lock)
+            pthread_mutex_unlock(&my_context->mutex_dyndump);
     }
 }
 
@@ -100,7 +104,7 @@ void FreeDynablockList(dynablocklist_t** dynablocks)
     if((*dynablocks)->direct) {
         for (int i=0; i<(*dynablocks)->textsz; ++i) {
             if((*dynablocks)->direct[i] && !(*dynablocks)->direct[i]->father) 
-                FreeDynablock((*dynablocks)->direct[i]);
+                FreeDynablock((*dynablocks)->direct[i], 1);
         }
         free((*dynablocks)->direct);
     }
@@ -117,7 +121,7 @@ void MarkDynablock(dynablock_t* db)
             db = db->father;    // mark only father
         if(db->need_test)
             return; // already done
-        db->need_test = 1;  // test only blocks that can be marked (and so deleted)
+        db->need_test = 1;
         setJumpTableDefault64(db->x64_addr);
         for(int i=0; i<db->sons_size; ++i)
             setJumpTableDefault64(db->sons[i]->x64_addr);
@@ -199,7 +203,7 @@ int FreeRangeDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t si
             }
         // purge the list
         kh_foreach_value(blocks, db,
-            FreeDynablock(db);
+            FreeDynablock(db, 1);
         );
         kh_destroy(dynablocks, blocks);
         // check emptyness
@@ -268,6 +272,7 @@ dynablock_t *AddNewDynablock(dynablocklist_t* dynablocks, uintptr_t addr, int* c
     if (!*created)
         return block;
     
+    pthread_mutex_lock(&my_context->mutex_dyndump);
     if(!dynablocks->direct) {
         dynablock_t** p = (dynablock_t**)calloc(dynablocks->textsz, sizeof(dynablock_t*));
         if(arm64_lock_storeifnull(&dynablocks->direct, p)!=p)
@@ -282,12 +287,14 @@ dynablock_t *AddNewDynablock(dynablocklist_t* dynablocks, uintptr_t addr, int* c
     dynablock_t* tmp = (dynablock_t*)arm64_lock_storeifnull(&dynablocks->direct[addr-dynablocks->text], block);
     if(tmp !=  block) {
         // a block appeard!
+        pthread_mutex_unlock(&my_context->mutex_dyndump);
         free(block);
         *created = 0;
         return tmp;
     }
 
     *created = 1;
+    pthread_mutex_lock(&my_context->mutex_dyndump);
     return block;
 }
 
@@ -303,7 +310,7 @@ void cancelFillBlock()
     return NULL if block is not found / cannot be created. 
     Don't create if create==0
 */
-static dynablock_t* internalDBGetBlock(x64emu_t* emu, uintptr_t addr, uintptr_t filladdr, int create, dynablock_t* current)
+static dynablock_t* internalDBGetBlock(x64emu_t* emu, uintptr_t addr, uintptr_t filladdr, int create, dynablock_t* current, int need_lock)
 {
     // try the quickest way first: get parent of current and check if ok!
     dynablocklist_t *dynablocks = NULL;
@@ -332,19 +339,19 @@ static dynablock_t* internalDBGetBlock(x64emu_t* emu, uintptr_t addr, uintptr_t
     if(!created)
         return block;   // existing block...
 
-    #if 0
-    if(box64_dynarec_dump)
-        pthread_mutex_lock(&my_context->mutex_dyndump);
-    #endif
     // fill the block
     block->x64_addr = (void*)addr;
-    pthread_mutex_lock(&my_context->mutex_dyndump);
+    if(need_lock)
+        pthread_mutex_lock(&my_context->mutex_dyndump);
     if(sigsetjmp(&dynarec_jmpbuf, 1)) {
         printf_log(LOG_INFO, "FillBlock at %p triggered a segfault, cancelling\n", (void*)addr);
+        if(need_lock)
+            pthread_mutex_unlock(&my_context->mutex_dyndump);
         return NULL;
     }
     void* ret = FillBlock64(block, filladdr);
-    pthread_mutex_unlock(&my_context->mutex_dyndump);
+    if(need_lock)
+        pthread_mutex_unlock(&my_context->mutex_dyndump);
     if(!ret) {
         dynarec_log(LOG_DEBUG, "Fillblock of block %p for %p returned an error\n", block, (void*)addr);
         void* old = (void*)arm64_lock_storeifref(&dynablocks->direct[addr-dynablocks->text], 0, block);
@@ -355,10 +362,6 @@ static dynablock_t* internalDBGetBlock(x64emu_t* emu, uintptr_t addr, uintptr_t
         free(block);
         block = NULL;
     }
-    #if 0
-    if(box64_dynarec_dump)
-        pthread_mutex_unlock(&my_context->mutex_dyndump);
-    #endif
     // check size
     if(block && block->x64_size) {
         int blocksz = block->x64_size;
@@ -388,19 +391,22 @@ static dynablock_t* internalDBGetBlock(x64emu_t* emu, uintptr_t addr, uintptr_t
 
 dynablock_t* DBGetBlock(x64emu_t* emu, uintptr_t addr, int create, dynablock_t** current)
 {
-    dynablock_t *db = internalDBGetBlock(emu, addr, addr, create, *current);
+    dynablock_t *db = internalDBGetBlock(emu, addr, addr, create, *current, 1);
     if(db && db->done && db->block && (db->need_test || (db->father && db->father->need_test))) {
+        if(pthread_mutex_trylock(&my_context->mutex_dyndump))
+            return NULL;
         dynablock_t *father = db->father?db->father:db;
         uint32_t hash = X31_hash_code(father->x64_addr, father->x64_size);
         if(hash!=father->hash) {
+            father->done = 0;   // invalidating the block
             dynarec_log(LOG_DEBUG, "Invalidating block %p from %p:%p (hash:%X/%X) with %d son(s) for %p\n", father, father->x64_addr, father->x64_addr+father->x64_size, hash, father->hash, father->sons_size, (void*)addr);
             // no more current if it gets invalidated too
             if(*current && father->x64_addr>=(*current)->x64_addr && (father->x64_addr+father->x64_size)<(*current)->x64_addr)
                 *current = NULL;
             // Free father, it's now invalid!
-            FreeDynablock(father);
+            FreeDynablock(father, 0);
             // start again... (will create a new block)
-            db = internalDBGetBlock(emu, addr, addr, create, *current);
+            db = internalDBGetBlock(emu, addr, addr, create, *current, 0);
         } else {
             father->need_test = 0;
             protectDB((uintptr_t)father->x64_addr, father->x64_size);
@@ -409,6 +415,7 @@ dynablock_t* DBGetBlock(x64emu_t* emu, uintptr_t addr, int create, dynablock_t**
             for(int i=0; i<father->sons_size; ++i)
                 addJumpTableIfDefault64(father->sons[i]->x64_addr, father->sons[i]->block);
         }
+        pthread_mutex_unlock(&my_context->mutex_dyndump);
     } 
     return db;
 }
@@ -417,16 +424,19 @@ dynablock_t* DBAlternateBlock(x64emu_t* emu, uintptr_t addr, uintptr_t filladdr)
 {
     dynarec_log(LOG_DEBUG, "Creating AlternateBlock at %p for %p\n", (void*)addr, (void*)filladdr);
     int create = 1;
-    dynablock_t *db = internalDBGetBlock(emu, addr, filladdr, create, NULL);
+    dynablock_t *db = internalDBGetBlock(emu, addr, filladdr, create, NULL, 1);
     if(db && db->done && db->block && (db->need_test || (db->father && db->father->need_test))) {
+        if(pthread_mutex_trylock(&my_context->mutex_dyndump))
+            return NULL;
         dynablock_t *father = db->father?db->father:db;
         uint32_t hash = X31_hash_code(father->x64_addr, father->x64_size);
         if(hash!=father->hash) {
+            father->done = 0;   // invalidating the block
             dynarec_log(LOG_DEBUG, "Invalidating alt block %p from %p:%p (hash:%X/%X) with %d son(s) for %p\n", father, father->x64_addr, father->x64_addr+father->x64_size, hash, father->hash, father->sons_size, (void*)addr);
             // Free father, it's now invalid!
-            FreeDynablock(father);
+            FreeDynablock(father, 0);
             // start again... (will create a new block)
-            db = internalDBGetBlock(emu, addr, filladdr, create, NULL);
+            db = internalDBGetBlock(emu, addr, filladdr, create, NULL, 0);
         } else {
             father->need_test = 0;
             protectDB((uintptr_t)father->x64_addr, father->x64_size);
@@ -435,6 +445,7 @@ dynablock_t* DBAlternateBlock(x64emu_t* emu, uintptr_t addr, uintptr_t filladdr)
             for(int i=0; i<father->sons_size; ++i)
                 addJumpTableIfDefault64(father->sons[i]->x64_addr, father->sons[i]->block);
         }
+        pthread_mutex_unlock(&my_context->mutex_dyndump);
     } 
     return db;
 }
diff --git a/src/dynarec/dynarec.c b/src/dynarec/dynarec.c
index 976070ab..15d9fd13 100755
--- a/src/dynarec/dynarec.c
+++ b/src/dynarec/dynarec.c
@@ -57,7 +57,7 @@ void* LinkNext(x64emu_t* emu, uintptr_t addr, void* x2, uintptr_t* x3)
         if(!block) {
             #ifdef HAVE_TRACE
             dynablock_t* db = FindDynablockFromNativeAddress(x2-4);
-            printf_log(LOG_INFO, "Warning, jumping to a no-block address %p from %p (db=%p, x64addr=%p)\n", (void*)addr, x2-4, db, db?(void*)getX64Address(db, (uintptr_t)x2-4):NULL);
+            dynarec_log(LOG_INFO, "Warning, jumping to a no-block address %p from %p (db=%p, x64addr=%p)\n", (void*)addr, x2-4, db, db?(void*)getX64Address(db, (uintptr_t)x2-4):NULL);
             #endif
             //tableupdate(arm64_epilog, addr, table);
             return arm64_epilog;
diff --git a/src/dynarec/dynarec_arm64.c b/src/dynarec/dynarec_arm64.c
index 22ea6ad1..bcdcb16d 100755
--- a/src/dynarec/dynarec_arm64.c
+++ b/src/dynarec/dynarec_arm64.c
@@ -58,13 +58,15 @@ void printf_x64_instruction(zydis_dec_t* dec, instruction_x64_t* inst, const cha
 }
 
 void add_next(dynarec_arm_t *dyn, uintptr_t addr) {
+    if(!box64_dynarec_bigblock)
+        return;
+    for(int i=0; i<dyn->next_sz; ++i)
+        if(dyn->next[i]==addr)
+            return;
     if(dyn->next_sz == dyn->next_cap) {
         dyn->next_cap += 16;
         dyn->next = (uintptr_t*)realloc(dyn->next, dyn->next_cap*sizeof(uintptr_t));
     }
-    for(int i=0; i<dyn->next_sz; ++i)
-        if(dyn->next[i]==addr)
-            return;
     dyn->next[dyn->next_sz++] = addr;
 }
 uintptr_t get_closest_next(dynarec_arm_t *dyn, uintptr_t addr) {
@@ -333,6 +335,23 @@ uintptr_t arm_pass1(dynarec_arm_t* dyn, uintptr_t addr);
 uintptr_t arm_pass2(dynarec_arm_t* dyn, uintptr_t addr);
 uintptr_t arm_pass3(dynarec_arm_t* dyn, uintptr_t addr);
 
+__thread void* current_helper = NULL;
+
+void CancelBlock64()
+{
+    dynarec_arm_t* helper = (dynarec_arm_t*)current_helper;
+    current_helper = NULL;
+    if(!helper)
+        return;
+    free(helper->next);
+    free(helper->insts);
+    free(helper->table64);
+    free(helper->sons_x64);
+    free(helper->sons_arm);
+    if(helper->dynablock && helper->dynablock->block)
+        FreeDynarecMap(helper->dynablock, (uintptr_t)helper->dynablock->block, helper->dynablock->size);
+}
+
 void* FillBlock64(dynablock_t* block, uintptr_t addr) {
     if(addr>=box64_nodynarec_start && addr<box64_nodynarec_end) {
         block->done = 1;
@@ -342,29 +361,33 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr) {
     protectDB(addr, 1);
     // init the helper
     dynarec_arm_t helper = {0};
+    current_helper = &helper;
+    helper.dynablock = block;
     helper.start = addr;
     uintptr_t start = addr;
     helper.cap = 64; // needs epilog handling
     helper.insts = (instruction_arm64_t*)calloc(helper.cap, sizeof(instruction_arm64_t));
     // pass 0, addresses, x86 jump addresses, overall size of the block
     uintptr_t end = arm_pass0(&helper, addr);
+    // no need for next anymore
+    free(helper.next);
+    helper.next_sz = helper.next_cap = 0;
+    helper.next = NULL;
+    // basic checks
     if(!helper.size) {
         dynarec_log(LOG_INFO, "Warning, null-sized dynarec block (%p)\n", (void*)addr);
-        free(helper.next);
-        free(helper.insts);
-        block->done = 1;
+        CancelBlock64();
         return (void*)block;
     }
     if(!isprotectedDB(addr, 1)) {
         dynarec_log(LOG_INFO, "Warning, write on current page on pass0, aborting dynablock creation (%p)\n", (void*)addr);
-        free(helper.next);
-        free(helper.insts);
-        block->done = 1;
+        CancelBlock64();
         return NULL;
     }
-    // already protect the block and compute hash signature
+    // protect the block of it goes over the 1st page
     if((addr&~0xfff)!=(end&~0xfff)) // need to protect some other pages too
         protectDB(addr, end-addr);  //end is 1byte after actual end
+    // compute hash signature
     uint32_t hash = X31_hash_code((void*)addr, end-addr);
     // calculate barriers
     for(int i=0; i<helper.size; ++i)
@@ -400,9 +423,7 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr) {
     void* p = (void*)AllocDynarecMap(block, sz);
     if(p==NULL) {
         dynarec_log(LOG_INFO, "AllocDynarecMap(%p, %zu) failed, cancelling block\n", block, sz);
-        free(helper.insts);
-        free(helper.next);
-        free(helper.table64);
+        CancelBlock64();
         return NULL;
     }
     helper.block = p;
@@ -456,8 +477,9 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr) {
     }
     // ok, free the helper now
     free(helper.insts);
-    free(helper.next);
+    helper.insts = NULL;
     free(helper.table64);
+    helper.table64 = NULL;
     block->size = sz;
     block->isize = helper.size;
     block->block = p;
@@ -466,13 +488,13 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr) {
     block->x64_size = end-start;
     block->hash = X31_hash_code(block->x64_addr, block->x64_size);
     // Check if something changed, to abbort if it as
-    if((block->hash != hash) || !isprotectedDB(addr, end-addr)) {
+    if((block->hash != hash)) {
         dynarec_log(LOG_INFO, "Warning, a block changed while beeing processed hash(%p:%ld)=%x/%x\n", block->x64_addr, block->x64_size, block->hash, hash);
-        free(helper.sons_x64);
-        free(helper.sons_arm);
-        FreeDynarecMap(block, (uintptr_t)p, sz);
+        CancelBlock64();
         return NULL;
     }    // fill sons if any
+    if(!isprotectedDB(addr, end-addr))
+        protectDB(addr, end-addr);
     dynablock_t** sons = NULL;
     int sons_size = 0;
     if(helper.sons_size) {
@@ -501,7 +523,9 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr) {
             free(sons);
     }
     free(helper.sons_x64);
+    helper.sons_x64 = NULL;
     free(helper.sons_arm);
+    helper.sons_arm = NULL;
     //block->done = 1;
     return (void*)block;
 }
diff --git a/src/dynarec/dynarec_arm64_pass.c b/src/dynarec/dynarec_arm64_pass.c
index f8b98ce8..cd6ba45f 100755
--- a/src/dynarec/dynarec_arm64_pass.c
+++ b/src/dynarec/dynarec_arm64_pass.c
@@ -98,10 +98,11 @@ uintptr_t arm_pass(dynarec_arm_t* dyn, uintptr_t addr)
                 dyn->dfnone = 0;
             }
         }
-        if(!ok && !need_epilog && dyn->insts && (addr < (dyn->start+dyn->isize))) {
+        if(!ok && !need_epilog && (addr < (dyn->start+dyn->isize))) {
             ok = 1;
         }
-        if(!ok && !need_epilog && !dyn->insts && getProtection(addr+3)&~PROT_CUSTOM)
+        #if STEP == 0
+        if(!ok && !need_epilog && box64_dynarec_bigblock && getProtection(addr+3)&~PROT_CUSTOM)
             if(*(uint32_t*)addr!=0) {   // check if need to continue (but is next 4 bytes are 0, stop)
                 uintptr_t next = get_closest_next(dyn, addr);
                 if(next && (
@@ -114,6 +115,7 @@ uintptr_t arm_pass(dynarec_arm_t* dyn, uintptr_t addr)
                     dynarec_log(LOG_DEBUG, "Cannot extend block %p -> %p (%02X %02X %02X %02X %02X %02X %02X %02x)\n", (void*)addr, (void*)next, PK(0), PK(1), PK(2), PK(3), PK(4), PK(5), PK(6), PK(7));
                 }
             }
+        #endif
         if(ok<0)  {ok = 0; need_epilog=1;}
         ++ninst;
         #if STEP == 0
diff --git a/src/dynarec/dynarec_arm64_pass0.h b/src/dynarec/dynarec_arm64_pass0.h
index cee80a14..98d683ab 100755
--- a/src/dynarec/dynarec_arm64_pass0.h
+++ b/src/dynarec/dynarec_arm64_pass0.h
@@ -9,12 +9,12 @@
 #define BARRIER(A)      dyn->insts[ninst].x64.barrier = A
 #define BARRIER_NEXT(A) if(ninst<dyn->size) dyn->insts[ninst+1].x64.barrier = A
 #define NEW_INST \
-        ++dyn->size;                            \
         if(dyn->size+3>=dyn->cap) {             \
                 dyn->insts = (instruction_arm64_t*)realloc(dyn->insts, sizeof(instruction_arm64_t)*dyn->cap*2);     \
                 memset(&dyn->insts[dyn->cap], 0, sizeof(instruction_arm64_t)*dyn->cap);   \
                 dyn->cap *= 2;                  \
-        }
+        }                                       \
+        ++dyn->size
 #define INST_EPILOG         
 #define INST_NAME(name) 
 #define DEFAULT                         \
diff --git a/src/dynarec/dynarec_arm64_private.h b/src/dynarec/dynarec_arm64_private.h
index e048a312..cae1b4bd 100755
--- a/src/dynarec/dynarec_arm64_private.h
+++ b/src/dynarec/dynarec_arm64_private.h
@@ -4,6 +4,7 @@
 #include "dynarec_private.h"
 
 typedef struct x64emu_s x64emu_t;
+typedef struct dynablock_s dynablock_t;
 
 typedef struct instruction_arm64_s {
     instruction_x64_t   x64;
@@ -50,6 +51,7 @@ typedef struct dynarec_arm_s {
     uintptr_t*          sons_x64;   // the x64 address of potential dynablock sons
     void**              sons_arm;   // the arm address of potential dynablock sons
     int                 sons_size;  // number of potential dynablock sons
+    dynablock_t*        dynablock;
 } dynarec_arm_t;
 
 void add_next(dynarec_arm_t *dyn, uintptr_t addr);
diff --git a/src/include/debug.h b/src/include/debug.h
index af433dd2..80288c96 100755
--- a/src/include/debug.h
+++ b/src/include/debug.h
@@ -13,6 +13,7 @@ extern int box64_dynarec_dump;
 extern int box64_dynarec_trace;
 extern int box64_dynarec_forced;
 extern uintptr_t box64_nodynarec_start, box64_nodynarec_end;
+extern int box64_dynarec_bigblock;
 #ifdef ARM64
 extern int arm64_asimd;
 extern int arm64_aes;
diff --git a/src/include/dynablock.h b/src/include/dynablock.h
index d6424c4f..b83262cc 100755
--- a/src/include/dynablock.h
+++ b/src/include/dynablock.h
@@ -9,7 +9,7 @@ typedef struct kh_dynablocks_s  kh_dynablocks_t;
 uint32_t X31_hash_code(void* addr, int len);
 dynablocklist_t* NewDynablockList(uintptr_t text, int textsz, int direct);
 void FreeDynablockList(dynablocklist_t** dynablocks);
-void FreeDynablock(dynablock_t* db);
+void FreeDynablock(dynablock_t* db, int need_lock);
 void MarkDynablock(dynablock_t* db);
 //return 1 if Dynareblock is empty
 int FreeRangeDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size);
diff --git a/src/include/dynarec_arm64.h b/src/include/dynarec_arm64.h
index 1225153d..bc4cf3f6 100755
--- a/src/include/dynarec_arm64.h
+++ b/src/include/dynarec_arm64.h
@@ -4,6 +4,7 @@
 typedef struct dynablock_s dynablock_t;
 typedef struct x64emu_s x64emu_t;
 
+void CancelBlock64();
 void* FillBlock64(dynablock_t* block, uintptr_t addr);
 
 #endif //__DYNAREC_ARM_H_
\ No newline at end of file
diff --git a/src/libtools/signals.c b/src/libtools/signals.c
index 2d3a8aed..3cb84d7d 100755
--- a/src/libtools/signals.c
+++ b/src/libtools/signals.c
@@ -705,6 +705,8 @@ void my_sigactionhandler_oldcode(int32_t sig, int simple, siginfo_t* info, void
     relockMutex(Locks);
 }
 
+extern __thread void* current_helper;
+
 void my_box64signalhandler(int32_t sig, siginfo_t* info, void * ucntx)
 {
     // sig==SIGSEGV || sig==SIGBUS || sig==SIGILL here!
@@ -736,8 +738,10 @@ void my_box64signalhandler(int32_t sig, siginfo_t* info, void * ucntx)
     int Locks = unlockMutex();
     uint32_t prot = getProtection((uintptr_t)addr);
 #ifdef DYNAREC
-    if((Locks & (1<<8)) && (sig==SIGSEGV)) //1<<8 is mutex_dyndump
-        cancelFillBlock();  // Segfault inside a Fillblock, just cancel it's creation, don't relock mutex
+    if((Locks & (1<<8)) && (sig==SIGSEGV) && current_helper) {//1<<8 is mutex_dyndump
+        relockMutex(Locks);
+        cancelFillBlock();  // Segfault inside a Fillblock, cancel it's creation...
+    }
     dynablock_t* db = NULL;
     int db_searched = 0;
     if ((sig==SIGSEGV) && (addr) && (info->si_code == SEGV_ACCERR) && (prot&PROT_DYNAREC)) {
diff --git a/src/main.c b/src/main.c
index 7cb84b43..682f4fe6 100755
--- a/src/main.c
+++ b/src/main.c
@@ -42,6 +42,7 @@ int box64_pagesize;
 int box64_dynarec = 1;
 int box64_dynarec_dump = 0;
 int box64_dynarec_forced = 0;
+int box64_dynarec_bigblock = 1;
 uintptr_t box64_nodynarec_start = 0;
 uintptr_t box64_nodynarec_end = 0;
 #ifdef ARM64
@@ -262,6 +263,15 @@ void LoadLogEnv()
         if(box64_dynarec_forced)
         printf_log(LOG_INFO, "Dynarec is Forced on all addresses\n");
     }
+    p = getenv("BOX64_DYNAREC_BIGBLOCK");
+    if(p) {
+        if(strlen(p)==1) {
+            if(p[0]>='0' && p[0]<='1')
+                box64_dynarec_bigblock = p[0]-'0';
+        }
+        if(!box64_dynarec_bigblock)
+        printf_log(LOG_INFO, "Dynarec will not try to make big block\n");
+    }
     p = getenv("BOX64_NODYNAREC");
     if(p) {
         if (strchr(p,'-')) {
@@ -938,6 +948,13 @@ int main(int argc, const char **argv, const char **env) {
         printf_log(LOG_INFO, "Zoom detected, trying to use system libturbojpeg if possible\n");
         box64_zoom = 1;
     }
+    // special case for RimWorldLinux
+    #ifdef DYNAREC
+    if(strstr(prgname, "RimWorldLinux")==prgname) {
+        printf_log(LOG_INFO, "RimWorld detected, disabling bigblock on the Dynarec\n");
+        box64_dynarec_bigblock = 0;
+    }
+    #endif
     /*if(strstr(prgname, "awesomium_process")==prgname) {
         printf_log(LOG_INFO, "awesomium_process detected, forcing emulated libpng12\n");
         AddPath("libpng12.so.0", &my_context->box64_emulated_libs, 0);