about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
authorptitSeb <sebastien.chev@gmail.com>2023-04-16 10:50:12 +0200
committerptitSeb <sebastien.chev@gmail.com>2023-04-16 10:50:12 +0200
commit3adf31c85b8bb4366d063fbe8f7d9fc36084366d (patch)
tree42d8fb12e6079f362c54226a862cabd8b1980ad9 /src
parent9b2c6caf22e6dc91ad72f4d90116b80237bd3487 (diff)
downloadbox64-3adf31c85b8bb4366d063fbe8f7d9fc36084366d.tar.gz
box64-3adf31c85b8bb4366d063fbe8f7d9fc36084366d.zip
[DYNAREC] General fixes and improvment for multithread and jit program. Helps Java, mono and Unity3d program... (should help #519, #464, #433, #272, #232, #193, #112...)
Diffstat (limited to 'src')
-rw-r--r--src/custommem.c27
-rwxr-xr-xsrc/dynarec/arm64/dynarec_arm64_pass2.h4
-rwxr-xr-xsrc/dynarec/arm64/dynarec_arm64_pass3.h7
-rwxr-xr-xsrc/dynarec/arm64/dynarec_arm64_private.h4
-rwxr-xr-xsrc/dynarec/dynablock.c129
-rwxr-xr-xsrc/dynarec/dynablock_private.h5
-rwxr-xr-xsrc/dynarec/dynarec_native.c82
-rw-r--r--src/dynarec/rv64/dynarec_rv64_pass2.h4
-rw-r--r--src/dynarec/rv64/dynarec_rv64_pass3.h4
-rw-r--r--src/dynarec/rv64/dynarec_rv64_private.h4
-rw-r--r--src/include/custommem.h1
-rwxr-xr-xsrc/include/dynablock.h2
-rwxr-xr-xsrc/libtools/signals.c13
13 files changed, 193 insertions, 93 deletions
diff --git a/src/custommem.c b/src/custommem.c
index 4cf1dd0a..45c7a01f 100644
--- a/src/custommem.c
+++ b/src/custommem.c
@@ -26,6 +26,7 @@
 #include "threads.h"
 #ifdef DYNAREC
 #include "dynablock.h"
+#include "dynarec/dynablock_private.h"
 #include "dynarec/native_lock.h"
 #include "dynarec/dynarec_next.h"
 
@@ -770,6 +771,28 @@ dynablock_t* getDB(uintptr_t addr)
     return *(dynablock_t**)(ret - sizeof(void*));
 }
 
+int getNeedTest(uintptr_t addr)
+{
+    uintptr_t idx3, idx2, idx1, idx0;
+    idx3 = ((addr)>>JMPTABL_START3)&JMPTABLE_MASK3;
+    idx2 = ((addr)>>JMPTABL_START2)&JMPTABLE_MASK2;
+    idx1 = ((addr)>>JMPTABL_START1)&JMPTABLE_MASK1;
+    idx0 = ((addr)                )&JMPTABLE_MASK0;
+    uintptr_t ret = (uintptr_t)box64_jmptbl3[idx3][idx2][idx1][idx0];
+    dynablock_t* db = *(dynablock_t**)(ret - sizeof(void*));
+    return db?((ret!=(uintptr_t)db->block)?1:0):0;
+}
+
+uintptr_t getJumpAddress64(uintptr_t addr)
+{
+    uintptr_t idx3, idx2, idx1, idx0;
+    idx3 = ((addr)>>JMPTABL_START3)&JMPTABLE_MASK3;
+    idx2 = ((addr)>>JMPTABL_START2)&JMPTABLE_MASK2;
+    idx1 = ((addr)>>JMPTABL_START1)&JMPTABLE_MASK1;
+    idx0 = ((addr)                )&JMPTABLE_MASK0;
+    return (uintptr_t)box64_jmptbl3[idx3][idx2][idx1][idx0];
+}
+
 // Remove the Write flag from an adress range, so DB can be executed safely
 void protectDB(uintptr_t addr, uintptr_t size)
 {
@@ -1032,8 +1055,10 @@ void refreshProtection(uintptr_t addr)
     uintptr_t idx = (addr>>MEMPROT_SHIFT);
     if(memprot[idx>>16].prot!=memprot_default) {
         int prot = memprot[idx>>16].prot[idx&0xffff];
-        int ret = mprotect((void*)(idx<<MEMPROT_SHIFT), box64_pagesize, prot&~PROT_CUSTOM);
+        if(!(prot&PROT_DYNAREC)) {
+            int ret = mprotect((void*)(idx<<MEMPROT_SHIFT), box64_pagesize, prot&~PROT_CUSTOM);
 printf_log(LOG_INFO, "refreshProtection(%p): %p/0x%x (ret=%d/%s)\n", (void*)addr, (void*)(idx<<MEMPROT_SHIFT), prot, ret, ret?strerror(errno):"ok");
+        }
     }
     mutex_unlock(&mutex_prot);
 }
diff --git a/src/dynarec/arm64/dynarec_arm64_pass2.h b/src/dynarec/arm64/dynarec_arm64_pass2.h
index 57a37572..86692795 100755
--- a/src/dynarec/arm64/dynarec_arm64_pass2.h
+++ b/src/dynarec/arm64/dynarec_arm64_pass2.h
@@ -14,5 +14,5 @@
         }
 #define INST_EPILOG dyn->insts[ninst].epilog = dyn->native_size; 
 #define INST_NAME(name) 
-#define TABLE64(A, V)   {Table64(dyn, (V)); EMIT(0);}
-#define FTABLE64(A, V)  {mmx87_regs_t v = {.d = V}; Table64(dyn, v.q); EMIT(0);}
\ No newline at end of file
+#define TABLE64(A, V)   {Table64(dyn, (V), 2); EMIT(0);}
+#define FTABLE64(A, V)  {mmx87_regs_t v = {.d = V}; Table64(dyn, v.q, 2); EMIT(0);}
\ No newline at end of file
diff --git a/src/dynarec/arm64/dynarec_arm64_pass3.h b/src/dynarec/arm64/dynarec_arm64_pass3.h
index c39aa5e4..bdc41db9 100755
--- a/src/dynarec/arm64/dynarec_arm64_pass3.h
+++ b/src/dynarec/arm64/dynarec_arm64_pass3.h
@@ -6,7 +6,8 @@
 #define EMIT(A)                                         \
     do{                                                 \
         if(box64_dynarec_dump) print_opcode(dyn, ninst, (uint32_t)(A)); \
-        *(uint32_t*)(dyn->block) = (uint32_t)(A);       \
+        if((uintptr_t)dyn->block<dyn->tablestart)       \
+            *(uint32_t*)(dyn->block) = (uint32_t)(A);   \
         dyn->block += 4; dyn->native_size += 4;         \
         dyn->insts[ninst].size2 += 4;                   \
     }while(0)
@@ -17,5 +18,5 @@
         addInst(dyn->instsize, &dyn->insts_size, dyn->insts[ninst-1].x64.size, dyn->insts[ninst-1].size/4);
 #define INST_EPILOG     
 #define INST_NAME(name) inst_name_pass3(dyn, ninst, name)
-#define TABLE64(A, V)   {int val64offset = Table64(dyn, (V)); MESSAGE(LOG_DUMP, "  Table64: 0x%lx\n", (V)); LDRx_literal(A, val64offset);}
-#define FTABLE64(A, V)  {mmx87_regs_t v = {.d = V}; int val64offset = Table64(dyn, v.q); MESSAGE(LOG_DUMP, "  FTable64: %g\n", v.d); VLDR64_literal(A, val64offset);}
+#define TABLE64(A, V)   {int val64offset = Table64(dyn, (V), 3); MESSAGE(LOG_DUMP, "  Table64: 0x%lx\n", (V)); LDRx_literal(A, val64offset);}
+#define FTABLE64(A, V)  {mmx87_regs_t v = {.d = V}; int val64offset = Table64(dyn, v.q, 3); MESSAGE(LOG_DUMP, "  FTable64: %g\n", v.d); VLDR64_literal(A, val64offset);}
diff --git a/src/dynarec/arm64/dynarec_arm64_private.h b/src/dynarec/arm64/dynarec_arm64_private.h
index 15705634..be57a790 100755
--- a/src/dynarec/arm64/dynarec_arm64_private.h
+++ b/src/dynarec/arm64/dynarec_arm64_private.h
@@ -95,6 +95,7 @@ typedef struct dynarec_arm_s {
     int                 table64size;// size of table (will be appended at end of executable code)
     int                 table64cap;
     uintptr_t           tablestart;
+    uintptr_t           jmp_next;   // address of the jump_next address
     flagcache_t         f;
     neoncache_t         n;          // cache for the 8..31 double reg from fpu, plus x87 stack delta
     uintptr_t*          next;       // variable array of "next" jump address
@@ -112,6 +113,7 @@ typedef struct dynarec_arm_s {
     int                 forward_ninst;  // ninst at the forward point
     uint8_t             doublepush;
     uint8_t             doublepop;
+    uint8_t             always_test;
 } dynarec_arm_t;
 
 void add_next(dynarec_arm_t *dyn, uintptr_t addr);
@@ -119,7 +121,7 @@ uintptr_t get_closest_next(dynarec_arm_t *dyn, uintptr_t addr);
 int is_nops(dynarec_arm_t *dyn, uintptr_t addr, int n);
 int is_instructions(dynarec_arm_t *dyn, uintptr_t addr, int n);
 
-int Table64(dynarec_arm_t *dyn, uint64_t val);  // add a value to etable64 (if needed) and gives back the imm19 to use in LDR_literal
+int Table64(dynarec_arm_t *dyn, uint64_t val, int pass);  // add a value to etable64 (if needed) and gives back the imm19 to use in LDR_literal
 
 void CreateJmpNext(void* addr, void* next);
 
diff --git a/src/dynarec/dynablock.c b/src/dynarec/dynablock.c
index 17c6aa0c..d5c95111 100755
--- a/src/dynarec/dynablock.c
+++ b/src/dynarec/dynablock.c
@@ -37,6 +37,39 @@ uint32_t X31_hash_code(void* addr, int len)
 	return (uint32_t)h;
 }
 
+dynablock_t* InvalidDynablock(dynablock_t* db, int need_lock)
+{
+    if(db) {
+        if(db->gone)
+            return NULL; // already in the process of deletion!
+        dynarec_log(LOG_DEBUG, "InvalidDynablock(%p), db->block=%p x64=%p:%p already gone=%d\n", db, db->block, db->x64_addr, db->x64_addr+db->x64_size-1, db->gone);
+        if(need_lock)
+            mutex_lock(&my_context->mutex_dyndump);
+        // remove jumptable
+        setJumpTableDefault64(db->x64_addr);
+        db->done = 0;
+        db->gone = 1;
+        if(need_lock)
+            mutex_unlock(&my_context->mutex_dyndump);
+    }
+    return db;
+}
+
+void FreeInvalidDynablock(dynablock_t* db, int need_lock)
+{
+    if(db) {
+        if(!db->gone)
+            return; // already in the process of deletion!
+        dynarec_log(LOG_DEBUG, "FreeInvalidDynablock(%p), db->block=%p x64=%p:%p already gone=%d\n", db, db->block, db->x64_addr, db->x64_addr+db->x64_size-1, db->gone);
+        if(need_lock)
+            mutex_lock(&my_context->mutex_dyndump);
+        FreeDynarecMap((uintptr_t)db->actual_block);
+        customFree(db);
+        if(need_lock)
+            mutex_unlock(&my_context->mutex_dyndump);
+    }
+}
+
 void FreeDynablock(dynablock_t* db, int need_lock)
 {
     if(db) {
@@ -50,6 +83,8 @@ void FreeDynablock(dynablock_t* db, int need_lock)
         dynarec_log(LOG_DEBUG, " -- FreeDyrecMap(%p, %d)\n", db->actual_block, db->size);
         db->done = 0;
         db->gone = 1;
+        if(db->previous)
+            FreeInvalidDynablock(db->previous, 0);
         FreeDynarecMap((uintptr_t)db->actual_block);
         customFree(db);
         if(need_lock)
@@ -57,14 +92,26 @@ void FreeDynablock(dynablock_t* db, int need_lock)
     }
 }
 
+
+
 void MarkDynablock(dynablock_t* db)
 {
     if(db) {
-        if(db->need_test)
-            return; // already done
         dynarec_log(LOG_DEBUG, "MarkDynablock %p %p-%p\n", db, db->x64_addr, db->x64_addr+db->x64_size-1);
-        db->need_test = 1;
-        setJumpTableIfRef64(db->x64_addr, db->jmpnext, db->block);
+        if(!setJumpTableIfRef64(db->x64_addr, db->jmpnext, db->block)) {
+            dynablock_t* old = db;
+            db = getDB((uintptr_t)old->x64_addr);
+            if(!old->gone && db!=old) {
+                printf_log(LOG_INFO, "Warning, couldn't mark block as dirty for %p, block=%p, current_block=%p\n", old->x64_addr, old, db);
+                // the block is lost, need to invalidate it...
+                old->gone = 1;
+                old->done = 0;
+                if(!db || db->previous)
+                    FreeInvalidDynablock(old, 1);
+                else
+                    db->previous = old;
+            }
+        }
     }
 }
 
@@ -78,7 +125,7 @@ static int IntervalIntersects(uintptr_t start1, uintptr_t end1, uintptr_t start2
 static int MarkedDynablock(dynablock_t* db)
 {
     if(db) {
-        if(db->need_test)
+        if(getNeedTest((uintptr_t)db->x64_addr))
             return 1; // already done
     }
     return 0;
@@ -90,9 +137,8 @@ void MarkRangeDynablock(dynablock_t* db, uintptr_t addr, uintptr_t size)
     if(!db)
         return;
     dynarec_log(LOG_DEBUG, "MarkRangeDynablock %p-%p .. startdb=%p, sizedb=%p\n", (void*)addr, (void*)addr+size-1, (void*)db->x64_addr, (void*)db->x64_size);
-    if(!MarkedDynablock(db))
-        if(IntervalIntersects((uintptr_t)db->x64_addr, (uintptr_t)db->x64_addr+db->x64_size-1, addr, addr+size+1))
-            MarkDynablock(db);
+    if(IntervalIntersects((uintptr_t)db->x64_addr, (uintptr_t)db->x64_addr+db->x64_size-1, addr, addr+size+1))
+        MarkDynablock(db);
 }
 
 int FreeRangeDynablock(dynablock_t* db, uintptr_t addr, uintptr_t size)
@@ -153,13 +199,11 @@ static dynablock_t* internalDBGetBlock(x64emu_t* emu, uintptr_t addr, uintptr_t
             if(mutex_trylock(&my_context->mutex_dyndump))   // FillBlock not available for now
                 return NULL;
         }
-    }
-    
-    block = getDB(addr);    // just in case
-    if(block) {
-        if(need_lock)
+        block = getDB(addr);    // just in case
+        if(block) {
             mutex_unlock(&my_context->mutex_dyndump);
-        return block;
+            return block;
+        }
     }
     
     block = AddNewDynablock(addr);
@@ -184,9 +228,10 @@ static dynablock_t* internalDBGetBlock(x64emu_t* emu, uintptr_t addr, uintptr_t
         if(blocksz>my_context->max_db_size)
             my_context->max_db_size = blocksz;
         // fill-in jumptable
-        if(!addJumpTableIfDefault64(block->x64_addr, block->block)) {
+        if(!addJumpTableIfDefault64(block->x64_addr, block->dirty?block->jmpnext:block->block)) {
             FreeDynablock(block, 0);
             block = getDB(addr);
+            MarkDynablock(block);   // just in case...
         } else {
             if(block->x64_size)
                 block->done = 1;    // don't validate the block if the size is null, but keep the block
@@ -203,7 +248,9 @@ 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 *db = internalDBGetBlock(emu, addr, addr, create, 1);
-    if(db && db->done && db->block && db->need_test) {
+    if(db && db->done && db->block && getNeedTest(addr)) {
+        if(db->always_test)
+            sched_yield();  // just calm down...
         if(AreaInHotPage((uintptr_t)db->x64_addr, (uintptr_t)db->x64_addr + db->x64_size - 1)) {
             emu->test.test = 0;
             if(box64_dynarec_fastpage) {
@@ -221,25 +268,30 @@ dynablock_t* DBGetBlock(x64emu_t* emu, uintptr_t addr, int create)
             }
         }
         uint32_t hash = X31_hash_code(db->x64_addr, db->x64_size);
-        if(mutex_trylock(&my_context->mutex_dyndump)) {
-            dynarec_log(LOG_DEBUG, "mutex_dyndump not available when trying to validate block %p from %p:%p (hash:%X) for %p\n", db, db->x64_addr, db->x64_addr+db->x64_size-1, db->hash, (void*)addr);
-            return NULL;
-        }
+        int need_lock = mutex_trylock(&my_context->mutex_dyndump);
         if(hash!=db->hash) {
             db->done = 0;   // invalidating the block
             dynarec_log(LOG_DEBUG, "Invalidating block %p from %p:%p (hash:%X/%X) for %p\n", db, db->x64_addr, db->x64_addr+db->x64_size-1, hash, db->hash, (void*)addr);
             // Free db, it's now invalid!
-            FreeDynablock(db, 0);
+            dynablock_t* old = InvalidDynablock(db, need_lock);
             // start again... (will create a new block)
-            db = internalDBGetBlock(emu, addr, addr, create, 0);
+            db = internalDBGetBlock(emu, addr, addr, create, need_lock);
+            if(db) {
+                if(db->previous)
+                    FreeInvalidDynablock(db->previous, need_lock);
+                db->previous = old;
+            } else
+                FreeInvalidDynablock(old, need_lock);
         } else {
-            db->need_test = 0;
             dynarec_log(LOG_DEBUG, "Validating block %p from %p:%p (hash:%X) for %p\n", db, db->x64_addr, db->x64_addr+db->x64_size-1, db->hash, (void*)addr);
             protectDB((uintptr_t)db->x64_addr, db->x64_size);
             // fill back jumptable
-            setJumpTableIfRef64(db->x64_addr, db->block, db->jmpnext);
+            if(isprotectedDB((uintptr_t)db->x64_addr, db->x64_size) && !db->always_test) {
+                setJumpTableIfRef64(db->x64_addr, db->block, db->jmpnext);
+            }
         }
-        mutex_unlock(&my_context->mutex_dyndump);
+        if(!need_lock)
+            mutex_unlock(&my_context->mutex_dyndump);
     } 
     if(!db || !db->block || !db->done)
         emu->test.test = 0;
@@ -251,26 +303,33 @@ 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, 1);
-    if(db && db->done && db->block && db->need_test) {
-        if(mutex_trylock(&my_context->mutex_dyndump)) {
-            emu->test.test = 0;
-            return NULL;
-        }
+    if(db && db->done && db->block && getNeedTest(filladdr)) {
+        if(db->always_test)
+            sched_yield();  // just calm down...
+        int need_lock = mutex_trylock(&my_context->mutex_dyndump);
         uint32_t hash = X31_hash_code(db->x64_addr, db->x64_size);
         if(hash!=db->hash) {
             db->done = 0;   // invalidating the block
             dynarec_log(LOG_DEBUG, "Invalidating alt block %p from %p:%p (hash:%X/%X) for %p\n", db, db->x64_addr, db->x64_addr+db->x64_size, hash, db->hash, (void*)addr);
             // Free db, it's now invalid!
-            FreeDynablock(db, 0);
+            dynablock_t* old = InvalidDynablock(db, need_lock);
             // start again... (will create a new block)
-            db = internalDBGetBlock(emu, addr, filladdr, create, 0);
+            db = internalDBGetBlock(emu, addr, filladdr, create, need_lock);
+            if(db) {
+                if(db->previous)
+                    FreeInvalidDynablock(db->previous, need_lock);
+                db->previous = old;
+            } else
+                FreeInvalidDynablock(old, need_lock);
         } else {
-            db->need_test = 0;
             protectDB((uintptr_t)db->x64_addr, db->x64_size);
             // fill back jumptable
-            addJumpTableIfDefault64(db->x64_addr, db->block);
+            if(isprotectedDB((uintptr_t)db->x64_addr, db->x64_size) && !db->always_test) {
+                setJumpTableIfRef64(db->x64_addr, db->block, db->jmpnext);
+            }
         }
-        mutex_unlock(&my_context->mutex_dyndump);
+        if(!need_lock)
+            mutex_unlock(&my_context->mutex_dyndump);
     } 
     if(!db || !db->block || !db->done)
         emu->test.test = 0;
diff --git a/src/dynarec/dynablock_private.h b/src/dynarec/dynablock_private.h
index dbe8c502..18666e04 100755
--- a/src/dynarec/dynablock_private.h
+++ b/src/dynarec/dynablock_private.h
@@ -9,14 +9,15 @@ typedef struct instsize_s {
 typedef struct dynablock_s {
     void*           block;  // block-sizeof(void*) == self
     void*           actual_block;   // the actual start of the block (so block-sizeof(void*))
+    struct dynablock_s*    previous;   // a previous block that might need to be freed
     int             size;
     void*           x64_addr;
     uintptr_t       x64_size;
     uint32_t        hash;
-    uint8_t         need_test;
     uint8_t         done;
     uint8_t         gone;
-    uint8_t         dummy;
+    uint8_t         always_test;
+    uint8_t         dirty;      // if need to be tested as soon as it's created
     int             isize;
     instsize_t*     instsize;
     void*           jmpnext;    // a branch jmpnext code when block is marked
diff --git a/src/dynarec/dynarec_native.c b/src/dynarec/dynarec_native.c
index c57b7d64..64d28342 100755
--- a/src/dynarec/dynarec_native.c
+++ b/src/dynarec/dynarec_native.c
@@ -267,7 +267,7 @@ void addInst(instsize_t* insts, size_t* size, int x64_size, int native_size)
 }
 
 // add a value to table64 (if needed) and gives back the imm19 to use in LDR_literal
-int Table64(dynarec_native_t *dyn, uint64_t val)
+int Table64(dynarec_native_t *dyn, uint64_t val, int pass)
 {
     // find the value if already present
     int idx = -1;
@@ -278,10 +278,12 @@ int Table64(dynarec_native_t *dyn, uint64_t val)
     if(idx==-1) {
         if(dyn->table64size == dyn->table64cap) {
             dyn->table64cap+=16;
-            dyn->table64 = (uint64_t*)customRealloc(dyn->table64, dyn->table64cap * sizeof(uint64_t));
+            if(pass<3)  // do not resize on pass3, it's not the same type of memory anymore
+                dyn->table64 = (uint64_t*)customRealloc(dyn->table64, dyn->table64cap * sizeof(uint64_t));
         }
         idx = dyn->table64size++;
-        dyn->table64[idx] = val;
+        if(dyn->table64size <= dyn->table64cap)
+            dyn->table64[idx] = val;
     }
     // calculate offset
     int delta = dyn->tablestart + idx*sizeof(uint64_t) - (uintptr_t)dyn->block;
@@ -381,19 +383,17 @@ void CancelBlock64(int need_lock)
         mutex_lock(&my_context->mutex_dyndump);
     dynarec_native_t* helper = (dynarec_native_t*)current_helper;
     current_helper = NULL;
-    if(!helper) {
-        if(need_lock)
-            mutex_unlock(&my_context->mutex_dyndump);
-        return;
+    if(helper) {
+        customFree(helper->next);
+        customFree(helper->insts);
+        customFree(helper->predecessor);
+        if(helper->table64 && (helper->table64!=(uint64_t*)helper->tablestart))
+            customFree(helper->table64);
+        if(helper->dynablock && helper->dynablock->actual_block) {
+            FreeDynarecMap((uintptr_t)helper->dynablock->actual_block);
+            helper->dynablock->actual_block = NULL;
+        }
     }
-    customFree(helper->next);
-    customFree(helper->insts);
-    customFree(helper->predecessor);
-    customFree(helper->table64);
-    if(helper->dynablock && helper->dynablock->actual_block)
-        FreeDynarecMap((uintptr_t)helper->dynablock->actual_block);
-    else if(helper->dynablock && helper->block)
-        FreeDynarecMap((uintptr_t)helper->block-sizeof(void*));
     if(need_lock)
         mutex_unlock(&my_context->mutex_dyndump);
 }
@@ -421,7 +421,6 @@ void* CreateEmptyBlock(dynablock_t* block, uintptr_t addr) {
     *(dynablock_t**)actual_p = block;
     *(void**)(p+2*sizeof(void*)) = native_epilog;
     CreateJmpNext(block->jmpnext, p+2*sizeof(void*));
-    block->need_test = 0;
     // all done...
     __clear_cache(actual_p, actual_p+sz);   // need to clear the cache before execution...
     return block;
@@ -491,6 +490,8 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr) {
         if(helper.insts[i].x64.jmp) {
             uintptr_t j = helper.insts[i].x64.jmp;
             if(j<start || j>=end || j==helper.insts[i].x64.addr) {
+                if(j==helper.insts[i].x64.addr) // if there is a loop on some opcode, make the block "always to tested"
+                    helper.always_test = 1;
                 helper.insts[i].x64.jmp_insts = -1;
                 helper.insts[i].x64.need_after |= X_PEND;
             } else {
@@ -525,7 +526,7 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr) {
     size_t sz = sizeof(void*) + native_size + helper.table64size*sizeof(uint64_t) + 4*sizeof(void*) + insts_rsize;
     //           dynablock_t*     block (arm insts)            table64                       jmpnext code       instsize
     void* actual_p = (void*)AllocDynarecMap(sz);
-    void* p = actual_p + sizeof(void*);
+    void* p = (void*)(((uintptr_t)actual_p) + sizeof(void*));
     void* next = p + native_size + helper.table64size*sizeof(uint64_t);
     void* instsize = next + 4*sizeof(void*);
     if(actual_p==NULL) {
@@ -534,11 +535,16 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr) {
         return NULL;
     }
     helper.block = p;
+    block->actual_block = actual_p;
     helper.native_start = (uintptr_t)p;
     helper.tablestart = helper.native_start + native_size;
+    helper.jmp_next = (uintptr_t)next+sizeof(void*);
     helper.insts_size = 0;  // reset
     helper.instsize = (instsize_t*)instsize;
     *(dynablock_t**)actual_p = block;
+    helper.table64cap = helper.table64size;
+    customFree(helper.table64);
+    helper.table64 = (uint64_t*)helper.tablestart;
     // pass 3, emit (log emit native opcode)
     if(box64_dynarec_dump) {
         dynarec_log(LOG_NONE, "%s%04d|Emitting %zu bytes for %u x64 bytes", (box64_dynarec_dump>1)?"\e[01;36m":"", GetTID(), helper.native_size, helper.isize); 
@@ -550,43 +556,24 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr) {
     helper.native_size = 0;
     helper.table64size = 0; // reset table64 (but not the cap)
     native_pass3(&helper, addr);
-    if((oldnativesize!=helper.native_size) || (oldtable64size<helper.table64size)) {
-        printf_log(LOG_NONE, "BOX64: Warning, size difference in block between pass2 (%zu) & pass3 (%zu)!\n", sz, helper.native_size+helper.table64size*8);
-        uint8_t *dump = (uint8_t*)helper.start;
-        printf_log(LOG_NONE, "Dump of %d x64 opcodes:\n", helper.size);
-        for(int i=0; i<helper.size; ++i) {
-            printf_log(LOG_NONE, "%p:", dump);
-            for(; dump<(uint8_t*)helper.insts[i+1].x64.addr; ++dump)
-                printf_log(LOG_NONE, " %02X", *dump);
-            printf_log(LOG_NONE, "\t%d -> %d\n", helper.insts[i].size2, helper.insts[i].size);
-        }
-        printf_log(LOG_NONE, "Table64 \t%d -> %d\n", oldtable64size*8, helper.table64size*8);
-        printf_log(LOG_NONE, " ------------\n");
-        //TODO: Cancel block and return empty one
-    }
-    // add table64 if needed
-    if(helper.table64size) {
-        memcpy((void*)helper.tablestart, helper.table64, helper.table64size*8);
-    }
     // keep size of instructions for signal handling
     block->instsize = instsize;
     // ok, free the helper now
     customFree(helper.insts);
     helper.insts = NULL;
-    customFree(helper.table64);
     helper.table64 = NULL;
     helper.instsize = NULL;
     customFree(helper.predecessor);
     helper.predecessor = NULL;
     block->size = sz;
     block->isize = helper.size;
-    block->actual_block = actual_p;
     block->block = p;
     block->jmpnext = next+sizeof(void*);
+    block->always_test = helper.always_test;
+    block->dirty = block->always_test;
     *(dynablock_t**)next = block;
     *(void**)(next+3*sizeof(void*)) = native_next;
     CreateJmpNext(block->jmpnext, next+3*sizeof(void*));
-    block->need_test = 0;
     //block->x64_addr = (void*)start;
     block->x64_size = end-start;
     // all done...
@@ -599,10 +586,25 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr) {
         CancelBlock64(0);
         return NULL;
     }
+    if((oldnativesize!=helper.native_size) || (oldtable64size<helper.table64size)) {
+        printf_log(LOG_NONE, "BOX64: Warning, size difference in block between pass2 (%zu) & pass3 (%zu)!\n", sz, helper.native_size+helper.table64size*8);
+        uint8_t *dump = (uint8_t*)helper.start;
+        printf_log(LOG_NONE, "Dump of %d x64 opcodes:\n", helper.size);
+        for(int i=0; i<helper.size; ++i) {
+            printf_log(LOG_NONE, "%p:", dump);
+            for(; dump<(uint8_t*)helper.insts[i+1].x64.addr; ++dump)
+                printf_log(LOG_NONE, " %02X", *dump);
+            printf_log(LOG_NONE, "\t%d -> %d\n", helper.insts[i].size2, helper.insts[i].size);
+        }
+        printf_log(LOG_NONE, "Table64 \t%d -> %d\n", oldtable64size*8, helper.table64size*8);
+        printf_log(LOG_NONE, " ------------\n");
+        CancelBlock64(0);
+        return NULL;
+    }
     if(!isprotectedDB(addr, end-addr)) {
-        dynarec_log(LOG_DEBUG, "Warning, block unprotected while being processed %p:%ld, cancelling\n", block->x64_addr, block->x64_size);
+        dynarec_log(LOG_DEBUG, "Warning, block unprotected while being processed %p:%ld, marking as need_test\n", block->x64_addr, block->x64_size);
         AddHotPage(addr);
-        block->need_test = 1;
+        block->dirty = 1;
         //protectDB(addr, end-addr);
     }
     current_helper = NULL;
diff --git a/src/dynarec/rv64/dynarec_rv64_pass2.h b/src/dynarec/rv64/dynarec_rv64_pass2.h
index 176d512d..d71f9180 100644
--- a/src/dynarec/rv64/dynarec_rv64_pass2.h
+++ b/src/dynarec/rv64/dynarec_rv64_pass2.h
@@ -14,5 +14,5 @@
         }
 #define INST_EPILOG dyn->insts[ninst].epilog = dyn->native_size; 
 #define INST_NAME(name) 
-#define TABLE64(A, V)   {Table64(dyn, (V)); EMIT(0); EMIT(0);}
-#define FTABLE64(A, V)  {mmx87_regs_t v = {.d = V}; Table64(dyn, v.q); EMIT(0); EMIT(0);}
\ No newline at end of file
+#define TABLE64(A, V)   {Table64(dyn, (V), 2); EMIT(0); EMIT(0);}
+#define FTABLE64(A, V)  {mmx87_regs_t v = {.d = V}; Table64(dyn, v.q, 2); EMIT(0); EMIT(0);}
\ No newline at end of file
diff --git a/src/dynarec/rv64/dynarec_rv64_pass3.h b/src/dynarec/rv64/dynarec_rv64_pass3.h
index 24ab0dfa..dafef0c5 100644
--- a/src/dynarec/rv64/dynarec_rv64_pass3.h
+++ b/src/dynarec/rv64/dynarec_rv64_pass3.h
@@ -19,5 +19,5 @@
 #define INST_EPILOG     
 #define INST_NAME(name) inst_name_pass3(dyn, ninst, name)
 
-#define TABLE64(A, V)   {int val64offset = Table64(dyn, (V)); MESSAGE(LOG_DUMP, "  Table64: 0x%lx\n", (V)); AUIPC(A, SPLIT20(val64offset)); LD(A, A, SPLIT12(val64offset));}
-#define FTABLE64(A, V)  {mmx87_regs_t v = {.d = V}; int val64offset = Table64(dyn, v.q); MESSAGE(LOG_DUMP, "  FTable64: %g\n", v.d); AUIPC(x1, SPLIT20(val64offset)); FLD(A, x1, SPLIT12(val64offset));}
+#define TABLE64(A, V)   {int val64offset = Table64(dyn, (V), 3); MESSAGE(LOG_DUMP, "  Table64: 0x%lx\n", (V)); AUIPC(A, SPLIT20(val64offset)); LD(A, A, SPLIT12(val64offset));}
+#define FTABLE64(A, V)  {mmx87_regs_t v = {.d = V}; int val64offset = Table64(dyn, v.q, 3); MESSAGE(LOG_DUMP, "  FTable64: %g\n", v.d); AUIPC(x1, SPLIT20(val64offset)); FLD(A, x1, SPLIT12(val64offset));}
diff --git a/src/dynarec/rv64/dynarec_rv64_private.h b/src/dynarec/rv64/dynarec_rv64_private.h
index 3d6205d9..01657427 100644
--- a/src/dynarec/rv64/dynarec_rv64_private.h
+++ b/src/dynarec/rv64/dynarec_rv64_private.h
@@ -96,6 +96,7 @@ typedef struct dynarec_rv64_s {
     int                 table64size;// size of table (will be appended at end of executable code)
     int                 table64cap;
     uintptr_t           tablestart;
+    uintptr_t           jmp_next;   // address of the jump_next address
     flagcache_t         f;
     extcache_t          e;          // cache for the 10..31 0..1 double reg from fpu, plus x87 stack delta
     uintptr_t*          next;       // variable array of "next" jump address
@@ -111,6 +112,7 @@ typedef struct dynarec_rv64_s {
     uintptr_t           forward_to; // address of the next jump to (to check if everything is ok)
     int32_t             forward_size;   // size at the forward point
     int                 forward_ninst;  // ninst at the forward point
+    uint8_t             always_test;
 } dynarec_rv64_t;
 
 // convert idx (0..24) to reg index (10..31 0..1)
@@ -123,7 +125,7 @@ uintptr_t get_closest_next(dynarec_rv64_t *dyn, uintptr_t addr);
 int is_nops(dynarec_rv64_t *dyn, uintptr_t addr, int n);
 int is_instructions(dynarec_rv64_t *dyn, uintptr_t addr, int n);
 
-int Table64(dynarec_rv64_t *dyn, uint64_t val);  // add a value to etable64 (if needed) and gives back the imm19 to use in LDR_literal
+int Table64(dynarec_rv64_t *dyn, uint64_t val, int pass);  // add a value to etable64 (if needed) and gives back the imm19 to use in LDR_literal
 
 void CreateJmpNext(void* addr, void* next);
 
diff --git a/src/include/custommem.h b/src/include/custommem.h
index 5f9164f3..e7623db2 100644
--- a/src/include/custommem.h
+++ b/src/include/custommem.h
@@ -26,6 +26,7 @@ void addDBFromAddressRange(uintptr_t addr, size_t size);
 void cleanDBFromAddressRange(uintptr_t addr, size_t size, int destroy);
 
 dynablock_t* getDB(uintptr_t idx);
+int getNeedTest(uintptr_t idx);
 int addJumpTableIfDefault64(void* addr, void* jmp); // return 1 if write was succesfull
 int setJumpTableIfRef64(void* addr, void* jmp, void* ref); // return 1 if write was succesfull
 void setJumpTableDefault64(void* addr);
diff --git a/src/include/dynablock.h b/src/include/dynablock.h
index 1868deea..4e9d0b36 100755
--- a/src/include/dynablock.h
+++ b/src/include/dynablock.h
@@ -9,6 +9,8 @@ void FreeDynablock(dynablock_t* db, int need_lock);
 void MarkDynablock(dynablock_t* db);
 void MarkRangeDynablock(dynablock_t* db, uintptr_t addr, uintptr_t size);
 int FreeRangeDynablock(dynablock_t* db, uintptr_t addr, uintptr_t size);
+void FreeInvalidDynablock(dynablock_t* db, int need_lock);
+dynablock_t* InvalidDynablock(dynablock_t* db, int need_lock);
 
 dynablock_t* FindDynablockFromNativeAddress(void* addr);    // defined in box64context.h
 
diff --git a/src/libtools/signals.c b/src/libtools/signals.c
index 3e9bbce5..263711f2 100755
--- a/src/libtools/signals.c
+++ b/src/libtools/signals.c
@@ -939,7 +939,7 @@ void my_box64signalhandler(int32_t sig, siginfo_t* info, void * ucntx)
         }
         // access error, unprotect the block (and mark them dirty)
         unprotectDB((uintptr_t)addr, 1, 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)) {
+        if(db && ((addr>=db->x64_addr && addr<(db->x64_addr+db->x64_size)) || getNeedTest((uintptr_t)db->x64_addr))) {
             // dynablock got auto-dirty! need to get out of it!!!
             emu_jmpbuf_t* ejb = GetJmpBuf();
             if(ejb->jmpbuf_ok) {
@@ -998,6 +998,8 @@ void my_box64signalhandler(int32_t sig, siginfo_t* info, void * ucntx)
         if(db && db->x64_addr>= addr && (db->x64_addr+db->x64_size)<addr) {
             dynarec_log(LOG_INFO, "Warning, addr inside current dynablock!\n");
         }
+        // mark stuff as unclean
+        cleanDBFromAddressRange(((uintptr_t)addr)&~(box64_pagesize-1), box64_pagesize, 0);
         static void* glitch_pc = NULL;
         static void* glitch_addr = NULL;
         static int glitch_prot = 0;
@@ -1057,10 +1059,13 @@ dynarec_log(/*LOG_DEBUG*/LOG_INFO, "Repeated SIGSEGV with Access error on %p for
         printf_log(log_minimum, "%04d|Double %s (code=%d, pc=%p, addr=%p)!\n", GetTID(), signame, old_code, old_pc, old_addr);
 exit(-1);
     } else {
-        if(sig==SIGSEGV && info->si_code==2 && ((prot&~PROT_DYN)==5 || (prot&~PROT_DYN)==7)) {
+        if((sig==SIGSEGV) && (info->si_code == SEGV_ACCERR) && ((prot&~PROT_CUSTOM)==5 || (prot&~PROT_CUSTOM)==7)) {
             static uintptr_t old_addr = 0;
         printf_log(/*LOG_DEBUG*/LOG_INFO, "Strange SIGSEGV with Access error on %p for %p, db=%p, prot=0x%x (old_addr=%p)\n", pc, addr, db, prot, (void*)old_addr);
-            if(old_addr!=(uintptr_t)addr) {
+            #ifdef DYNAREC
+            cleanDBFromAddressRange(((uintptr_t)addr)&~(box64_pagesize-1), box64_pagesize, 0);
+            #endif
+            if(old_addr!=(uintptr_t)addr || getMmapped((uintptr_t)addr)) {
                 old_addr = (uintptr_t)addr;
                 refreshProtection(old_addr);
                 relockMutex(Locks);
@@ -1222,7 +1227,7 @@ exit(-1);
             prot, db, db?db->block:0, db?(db->block+db->size):0, 
             db?db->x64_addr:0, db?(db->x64_addr+db->x64_size):0, 
             getAddrFunctionName((uintptr_t)(db?db->x64_addr:0)), 
-            (db?db->need_test:0)?"need_stest":"clean", db?db->hash:0, hash, 
+            (db?getNeedTest((uintptr_t)db->x64_addr):0)?"need_stest":"clean", db?db->hash:0, hash, 
             (void*)my_context->signals[sig]);
 #if defined(ARM64)
         if(db) {