about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/custommem.c29
-rwxr-xr-xsrc/dynarec/dynablock.c48
-rwxr-xr-xsrc/include/dynablock.h3
3 files changed, 54 insertions, 26 deletions
diff --git a/src/custommem.c b/src/custommem.c
index a3aa8358..151dad63 100644
--- a/src/custommem.c
+++ b/src/custommem.c
@@ -540,6 +540,14 @@ void addDBFromAddressRange(uintptr_t addr, size_t size)
     }
 }
 
+static int dynmapempty(void** mem)
+{
+    for (int i=0; i<(1<<DYNAMAP_SHIFT); ++i)
+        if(mem[i])
+            return 0;
+    return 1;
+}
+
 void cleanDBFromAddressRange(uintptr_t addr, size_t size, int destroy)
 {
     dynarec_log(LOG_DEBUG, "cleanDBFromAddressRange %p -> %p %s\n", (void*)addr, (void*)(addr+size-1), destroy?"destroy":"mark");
@@ -552,9 +560,24 @@ void cleanDBFromAddressRange(uintptr_t addr, size_t size, int destroy)
         if(dynmap123[idx3] && dynmap123[idx3][idx2]) {
             dynablocklist_t* dblist = dynmap123[idx3][idx2][idx1];
             if(dblist) {
-                if(destroy)
-                    FreeRangeDynablock(dblist, addr, size);
-                else
+                if(destroy) {
+                    if(FreeRangeDynablock(dblist, addr, size)) {    // dblist is empty, check if we can delete more...
+                        if(!arm64_lock_storeifref(&dynmap123[idx3][idx2][idx1], NULL, dblist)) {
+                            free(dblist);
+                            dynablocklist_t** p = dynmap123[idx3][idx2];
+                            if(dynmapempty((void**)p)) {
+                                if(!arm64_lock_storeifref(&dynmap123[idx3][idx2], NULL, p)) {
+                                    free(p);
+                                    dynablocklist_t*** p2 = dynmap123[idx3];
+                                    if(dynmapempty((void**)p2)) {
+                                        if(!arm64_lock_storeifref(&dynmap123[idx3], NULL, p2))
+                                            free(p2);
+                                    }
+                                }
+                            }
+                        }
+                    }
+                } else
                     MarkRangeDynablock(dblist, addr, size);
             }
         }
diff --git a/src/dynarec/dynablock.c b/src/dynarec/dynablock.c
index d4a79156..a592b28f 100755
--- a/src/dynarec/dynablock.c
+++ b/src/dynarec/dynablock.c
@@ -165,10 +165,10 @@ void MarkDirectDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t
                     MarkDynablock(db);
 }
 
-void FreeRangeDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size)
+int FreeRangeDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size)
 {
     if(!dynablocks)
-        return;
+        return 1;
 
     if(dynablocks->direct) {
         dynablock_t* db;
@@ -176,34 +176,38 @@ void FreeRangeDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t s
         khint_t k;
         kh_dynablocks_t *blocks = kh_init(dynablocks);
         // copy in a temporary list
-        if(dynablocks->direct) {
-            uintptr_t startdb = dynablocks->text;
-            uintptr_t enddb = startdb + dynablocks->textsz;
-            uintptr_t start = addr;
-            uintptr_t end = addr+size;
-            if(start<startdb)
-                start = startdb;
-            if(end>enddb)
-                end = enddb;
-            if(end>startdb && start<enddb)
-                for(uintptr_t i = start; i<end; ++i) {
-                    db = (dynablock_t*)arm64_lock_xchg(&dynablocks->direct[i-startdb], 0);
-                    if(db) {
-                        if(db->father)
-                            db = db->father;
-                        if(db->parent==dynablocks) {
-                            k = kh_put(dynablocks, blocks, (uintptr_t)db, &ret);
-                            kh_value(blocks, k) = db;
-                        }
+        uintptr_t startdb = dynablocks->text;
+        uintptr_t enddb = startdb + dynablocks->textsz;
+        uintptr_t start = addr;
+        uintptr_t end = addr+size;
+        if(start<startdb)
+            start = startdb;
+        if(end>enddb)
+            end = enddb;
+        if(end>startdb && start<enddb)
+            for(uintptr_t i = start; i<end; ++i) {
+                db = (dynablock_t*)arm64_lock_xchg(&dynablocks->direct[i-startdb], 0);
+                if(db) {
+                    if(db->father)
+                        db = db->father;
+                    if(db->parent==dynablocks) {
+                        k = kh_put(dynablocks, blocks, (uintptr_t)db, &ret);
+                        kh_value(blocks, k) = db;
                     }
                 }
-        }
+            }
         // purge the list
         kh_foreach_value(blocks, db,
             FreeDynablock(db);
         );
         kh_destroy(dynablocks, blocks);
+        // check emptyness
+        for(uintptr_t i=0; i<dynablocks->textsz; ++i)
+            if(dynablocks->direct[i])
+                return 0;
+        return 1;
     }
+    return 1;
 }
 void MarkRangeDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size)
 {
diff --git a/src/include/dynablock.h b/src/include/dynablock.h
index 76f1e5e0..618a3651 100755
--- a/src/include/dynablock.h
+++ b/src/include/dynablock.h
@@ -11,7 +11,8 @@ dynablocklist_t* NewDynablockList(uintptr_t text, int textsz, int direct);
 void FreeDynablockList(dynablocklist_t** dynablocks);
 void FreeDynablock(dynablock_t* db);
 void MarkDynablock(dynablock_t* db);
-void FreeRangeDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size);
+//return 1 if Dynareblock is empty
+int FreeRangeDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size);
 void MarkRangeDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size);
 
 dynablock_t* FindDynablockFromNativeAddress(void* addr);    // defined in box64context.h