about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/dynarec/arm64/dynarec_arm64_00.c8
-rw-r--r--src/dynarec/arm64/dynarec_arm64_helper.c10
-rw-r--r--src/dynarec/arm64/dynarec_arm64_helper.h3
-rw-r--r--src/dynarec/arm64/dynarec_arm64_pass0.h3
-rw-r--r--src/dynarec/dynarec_native_pass.c27
-rw-r--r--src/dynarec/dynarec_private.h2
-rw-r--r--src/dynarec/rv64/dynarec_rv64_helper.h3
-rw-r--r--src/dynarec/rv64/dynarec_rv64_pass0.h3
8 files changed, 45 insertions, 14 deletions
diff --git a/src/dynarec/arm64/dynarec_arm64_00.c b/src/dynarec/arm64/dynarec_arm64_00.c
index a0177a3a..9967f784 100644
--- a/src/dynarec/arm64/dynarec_arm64_00.c
+++ b/src/dynarec/arm64/dynarec_arm64_00.c
@@ -2749,12 +2749,16 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
                     }
                     PUSH1z(x2);
                     if(box64_dynarec_callret) {
+                        SET_HASCALLRET();
                         // Push actual return address
                         if(addr < (dyn->start+dyn->isize)) {
+                            BARRIER_NEXT(BARRIER_FULL);
                             // there is a next...
                             j64 = (dyn->insts)?(dyn->insts[ninst].epilog-(dyn->native_size)):0;
                             ADR_S20(x4, j64);
+                            MESSAGE(LOG_NONE, "\tCALLRET set return to +%di\n", j64>>2);
                         } else {
+                            MESSAGE(LOG_NONE, "\tCALLRET set return to Jmptable(%p)\n", (void*)addr);
                             j64 = getJumpTableAddress64(addr);
                             TABLE64(x4, j64);
                             LDRx_U12(x4, x4, 0);
@@ -3152,12 +3156,16 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
                     }
                     GETIP_(addr);
                     if(box64_dynarec_callret) {
+                        SET_HASCALLRET();
                         // Push actual return address
                         if(addr < (dyn->start+dyn->isize)) {
                             // there is a next...
+                            BARRIER_NEXT(BARRIER_FULL);
                             j64 = (dyn->insts)?(dyn->insts[ninst].epilog-(dyn->native_size)):0;
                             ADR_S20(x4, j64);
+                            MESSAGE(LOG_NONE, "\tCALLRET set return to +%di\n", j64>>2);
                         } else {
+                            MESSAGE(LOG_NONE, "\tCALLRET set return to Jmptable(%p)\n", (void*)addr);
                             j64 = getJumpTableAddress64(addr);
                             TABLE64(x4, j64);
                             LDRx_U12(x4, x4, 0);
diff --git a/src/dynarec/arm64/dynarec_arm64_helper.c b/src/dynarec/arm64/dynarec_arm64_helper.c
index 8fbfbc73..1048b31c 100644
--- a/src/dynarec/arm64/dynarec_arm64_helper.c
+++ b/src/dynarec/arm64/dynarec_arm64_helper.c
@@ -618,12 +618,14 @@ void ret_to_epilog(dynarec_arm_t* dyn, int ninst, rex_t rex)
     if(box64_dynarec_callret) {
         // pop the actual return address for ARM stack
         LDPx_S7_offset(x2, x6, xSP, 0);
-        CBZx(x6, 5*4);
+        CBZx(x6, 7*4);
         ADDx_U12(xSP, xSP, 16);
         SUBx_REG(x6, x6, xRIP); // is it the right address?
         CBNZx(x6, 2*4);
         BLR(x2);
-        // not the correct return address, regular jump
+        // not the correct return address, regular jump, but purge the stack first, it's unsync now...
+        LDPx_S7_postindex(x2, x6, xSP, 16);
+        CBNZx(x6, -1*4);
     }
     uintptr_t tbl = getJumpTable64();
     NOTEST(x2);
@@ -660,12 +662,14 @@ void retn_to_epilog(dynarec_arm_t* dyn, int ninst, rex_t rex, int n)
     if(box64_dynarec_callret) {
         // pop the actual return address for ARM stack
         LDPx_S7_offset(x2, x6, xSP, 0);
-        CBZx(x6, 5*4);
+        CBZx(x6, 7*4);
         ADDx_U12(xSP, xSP, 16);
         SUBx_REG(x6, x6, xRIP); // is it the right address?
         CBNZx(x6, 2*4);
         BLR(x2);
         // not the correct return address, regular jump
+        LDPx_S7_postindex(x2, x6, xSP, 16);
+        CBNZx(x6, -1*4);
     }
     uintptr_t tbl = getJumpTable64();
     NOTEST(x2);
diff --git a/src/dynarec/arm64/dynarec_arm64_helper.h b/src/dynarec/arm64/dynarec_arm64_helper.h
index 2fbd8832..310cd571 100644
--- a/src/dynarec/arm64/dynarec_arm64_helper.h
+++ b/src/dynarec/arm64/dynarec_arm64_helper.h
@@ -846,6 +846,9 @@
 #ifndef BARRIER_NEXT
 #define BARRIER_NEXT(A)
 #endif
+#ifndef SET_HASCALLRET
+#define SET_HASCALLRET()
+#endif
 #define UFLAG_OP1(A) if(dyn->insts[ninst].x64.gen_flags) {STRxw_U12(A, xEmu, offsetof(x64emu_t, op1));}
 #define UFLAG_OP2(A) if(dyn->insts[ninst].x64.gen_flags) {STRxw_U12(A, xEmu, offsetof(x64emu_t, op2));}
 #define UFLAG_OP12(A1, A2) if(dyn->insts[ninst].x64.gen_flags) {STRxw_U12(A1, xEmu, offsetof(x64emu_t, op1));STRxw_U12(A2, xEmu, offsetof(x64emu_t, op2));}
diff --git a/src/dynarec/arm64/dynarec_arm64_pass0.h b/src/dynarec/arm64/dynarec_arm64_pass0.h
index 4bfc0acf..6e2dd09e 100644
--- a/src/dynarec/arm64/dynarec_arm64_pass0.h
+++ b/src/dynarec/arm64/dynarec_arm64_pass0.h
@@ -18,7 +18,8 @@
 #define EMIT(A)     
 #define JUMP(A, C)         add_next(dyn, (uintptr_t)A); SMEND(); dyn->insts[ninst].x64.jmp = A; dyn->insts[ninst].x64.jmp_cond = C
 #define BARRIER(A)      if(A!=BARRIER_MAYBE) {fpu_purgecache(dyn, ninst, 0, x1, x2, x3); dyn->insts[ninst].x64.barrier = A;} else dyn->insts[ninst].barrier_maybe = 1
-#define BARRIER_NEXT(A) dyn->insts[ninst+1].x64.barrier = A
+#define BARRIER_NEXT(A) dyn->insts[ninst+1].x64.barrier_next = A
+#define SET_HASCALLRET()    dyn->insts[ninst].x64.has_callret = 1
 #define NEW_INST \
         ++dyn->size;                            \
         if(dyn->size+3>=dyn->cap) {             \
diff --git a/src/dynarec/dynarec_native_pass.c b/src/dynarec/dynarec_native_pass.c
index b6b31c12..e67a9848 100644
--- a/src/dynarec/dynarec_native_pass.c
+++ b/src/dynarec/dynarec_native_pass.c
@@ -77,6 +77,9 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
             dyn->last_ip = 0;   // reset IP if some jump are coming here
         fpu_propagate_stack(dyn, ninst);
         NEW_INST;
+        if(ninst && dyn->insts[ninst-1].x64.barrier_next) {
+            BARRIER(dyn->insts[ninst-1].x64.barrier_next);
+        }
         if(!ninst) {
             GOTEST(x1, x2);
         }
@@ -178,7 +181,9 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
         if(dyn->forward) {
             if(dyn->forward_to == addr && !need_epilog) {
                 // we made it!
-                if(box64_dynarec_dump) dynarec_log(LOG_NONE, "Forward extend block for %d bytes %p -> %p\n", dyn->forward_to-dyn->forward, (void*)dyn->forward, (void*)dyn->forward_to);
+                if(box64_dynarec_dump) dynarec_log(LOG_NONE, "Forward extend block for %d bytes %s%p -> %p\n", dyn->forward_to-dyn->forward, dyn->insts[dyn->forward_ninst].x64.has_callret?"(opt. call) ":"", (void*)dyn->forward, (void*)dyn->forward_to);
+                if(dyn->insts[dyn->forward_ninst].x64.has_callret && !dyn->insts[dyn->forward_ninst].x64.has_next)
+                    dyn->insts[dyn->forward_ninst].x64.has_next = 1;  // this block actually continue
                 dyn->forward = 0;
                 dyn->forward_to = 0;
                 dyn->forward_size = 0;
@@ -205,14 +210,18 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
                     /*||(((next-addr)<30) && is_instructions(dyn, addr, next-addr))*/ ))
                 {
                     ok = 1;
-                    // need to find back that instruction to copy the caches, as previous version cannot be used anymore
-                    reset_n = -2;
-                    for(int ii=0; ii<ninst; ++ii)
-                        if(dyn->insts[ii].x64.jmp == next) {
-                            reset_n = ii;
-                            ii=ninst;
-                        }
-                    if(box64_dynarec_dump) dynarec_log(LOG_NONE, "Extend block %p, %p -> %p (ninst=%d, jump from %d)\n", dyn, (void*)addr, (void*)next, ninst, reset_n);
+                    if(dyn->insts[ninst].x64.has_callret && !dyn->insts[ninst].x64.has_next) {
+                        dyn->insts[ninst].x64.has_next = 1;  // this block actually continue
+                    } else {
+                        // need to find back that instruction to copy the caches, as previous version cannot be used anymore
+                        reset_n = -2;
+                        for(int ii=0; ii<ninst; ++ii)
+                            if(dyn->insts[ii].x64.jmp == next) {
+                                reset_n = ii;
+                                ii=ninst;
+                            }
+                    }
+                    if(box64_dynarec_dump) dynarec_log(LOG_NONE, "Extend block %p, %s%p -> %p (ninst=%d, jump from %d)\n", dyn, dyn->insts[ninst].x64.has_callret?"(opt. call) ":"", (void*)addr, (void*)next, ninst, dyn->insts[ninst].x64.has_callret?ninst:reset_n);
                 } else if(next && (next-addr)<box64_dynarec_forward && (getProtection(next)&PROT_READ)/*box64_dynarec_bigblock>=stopblock*/) {
                     if(!((box64_dynarec_bigblock<stopblock) && !isJumpTableDefault64((void*)next))) {
                         if(dyn->forward) {
diff --git a/src/dynarec/dynarec_private.h b/src/dynarec/dynarec_private.h
index 0ab21df4..86920700 100644
--- a/src/dynarec/dynarec_private.h
+++ b/src/dynarec/dynarec_private.h
@@ -33,6 +33,8 @@ typedef struct instruction_x64_s {
     uint8_t     jmp_cond;   // 1 of conditionnal jump
     uint8_t     has_next;   // does this opcode can continue to the next?
     uint8_t     barrier;    // next instruction is a jump point, so no optim allowed
+    uint8_t     barrier_next;   // next instruction needs a barrier
+    uint8_t     has_callret;    // this instruction have an optimised call setup
     uint8_t     state_flags;// One of SF_XXX state
     uint8_t     use_flags;  // 0 or combination of X_?F
     uint8_t     set_flags;  // 0 or combination of X_?F
diff --git a/src/dynarec/rv64/dynarec_rv64_helper.h b/src/dynarec/rv64/dynarec_rv64_helper.h
index 5a6d1cdb..140d90c1 100644
--- a/src/dynarec/rv64/dynarec_rv64_helper.h
+++ b/src/dynarec/rv64/dynarec_rv64_helper.h
@@ -950,6 +950,9 @@
 #ifndef BARRIER_NEXT
 #define BARRIER_NEXT(A)
 #endif
+#ifndef SET_HASCALLRET
+#define SET_HASCALLRET()
+#endif
 #define UFLAG_OP1(A) \
     if (dyn->insts[ninst].x64.gen_flags) { SDxw(A, xEmu, offsetof(x64emu_t, op1)); }
 #define UFLAG_OP2(A) \
diff --git a/src/dynarec/rv64/dynarec_rv64_pass0.h b/src/dynarec/rv64/dynarec_rv64_pass0.h
index fbba8f22..8854a7f7 100644
--- a/src/dynarec/rv64/dynarec_rv64_pass0.h
+++ b/src/dynarec/rv64/dynarec_rv64_pass0.h
@@ -18,7 +18,8 @@
 #define EMIT(A)     
 #define JUMP(A, C)         add_next(dyn, (uintptr_t)A); dyn->insts[ninst].x64.jmp = A; dyn->insts[ninst].x64.jmp_cond = C
 #define BARRIER(A)      if(A!=BARRIER_MAYBE) {fpu_purgecache(dyn, ninst, 0, x1, x2, x3); dyn->insts[ninst].x64.barrier = A;} else dyn->insts[ninst].barrier_maybe = 1
-#define BARRIER_NEXT(A) dyn->insts[ninst+1].x64.barrier = A
+#define BARRIER_NEXT(A) dyn->insts[ninst+1].x64.barrier_next = A
+#define SET_HASCALLRET()    dyn->insts[ninst].x64.has_callret = 1
 #define NEW_INST \
         ++dyn->size;                            \
         if(dyn->size+3>=dyn->cap) {             \