mirror of
https://github.com/ptitSeb/box64.git
synced 2026-11-08 10:10:25 -10:00
[DYNAREC] Added dynablock in_used tracking and removed DYNAREC_PURGE (#4405)
With DYNAREC_CALLRET>1, a callee returns directly into the caller block. If that block is invalidated and its JIT memory reused before all pending returns are done, the returning thread jumps into random data. in_used is now tracked and the deferred free only recycles blocks with in_used==0. DYNAREC_PURGE and tick tracking were removed, they were marked as legacy and now it's a good time to remove.
This commit is contained in:
1 parent
b30ad56e97
commit
92527ded34
22 files changed
+140
-218
No files matched your search
@@ -823,20 +823,6 @@ Add an environment variable.
|
||||
|
||||
## Fragile or Legacy
|
||||
|
||||
### BOX64_DYNAREC_PURGE
|
||||
|
||||
Purge DynaBlocks that haven't been executed recently, based on tick age threshold (BOX64_DYNAREC_PURGE_AGE).
|
||||
|
||||
* 0: DynaRec will not purge old unused DynaBlocks. [Default]
|
||||
* 1: DynaRec will purge old unused DynaBlocks based on tick age.
|
||||
|
||||
### BOX64_DYNAREC_PURGE_AGE
|
||||
|
||||
Tick age threshold for DynaBlock purging (requires BOX64_DYNAREC_PURGE=1).
|
||||
|
||||
* 4096: Default age threshold. [Default]
|
||||
* XXXX: Custom age threshold (range: 10-65536).
|
||||
|
||||
### BOX64_DYNAREC_WAIT
|
||||
|
||||
Wait or not for the building of a DynaRec code block to be ready. Available in WowBox64.
|
||||
|
||||
@@ -246,20 +246,6 @@ Skip N first CPU cores (Is apply before MAXCPU) 在 WowBox64 中可用。
|
||||
|
||||
## 不稳定或遗留选项
|
||||
|
||||
### BOX64_DYNAREC_PURGE
|
||||
|
||||
根据年龄阈值(BOX64_DYNAREC_PURGE_AGE)清除最近未执行的代码块。
|
||||
|
||||
* 0: DynaRec 不会清除旧的未使用代码块。 [默认值]
|
||||
* 1: DynaRec 将根据年龄阈值清除旧的未使用代码块。
|
||||
|
||||
### BOX64_DYNAREC_PURGE_AGE
|
||||
|
||||
代码块清除的年龄阈值(需要 BOX64_DYNAREC_PURGE=1)。
|
||||
|
||||
* 4096: 默认年龄阈值。 [默认值]
|
||||
* XXXX: 自定义年龄阈值(范围:10-65536)。
|
||||
|
||||
### BOX64_DYNAREC_WAIT
|
||||
|
||||
是否等待代码块构建完成。 在 WowBox64 中可用。
|
||||
|
||||
@@ -338,22 +338,6 @@ Generate map file for Linux perf tool.
|
||||
* 1 : DynaRec will generate perf map.
|
||||
|
||||
|
||||
=item B<BOX64_DYNAREC_PURGE> =I<0|1>
|
||||
|
||||
Purge DynaBlocks that haven't been executed recently, based on tick age threshold (BOX64_DYNAREC_PURGE_AGE).
|
||||
|
||||
* 0 : DynaRec will not purge old unused DynaBlocks. [Default]
|
||||
* 1 : DynaRec will purge old unused DynaBlocks based on tick age.
|
||||
|
||||
|
||||
=item B<BOX64_DYNAREC_PURGE_AGE> =I<4096|XXXX>
|
||||
|
||||
Tick age threshold for DynaBlock purging (requires BOX64_DYNAREC_PURGE=1).
|
||||
|
||||
* 4096 : Default age threshold. [Default]
|
||||
* XXXX : Custom age threshold (range: 10-65536).
|
||||
|
||||
|
||||
=item B<BOX64_DYNAREC_SAFEFLAGS> =I<0|1|2>
|
||||
|
||||
Behaviour of flags emulation on CALL/RET opcodes and other edge cases. Available in WowBox64.
|
||||
|
||||
+1
-39
@@ -736,44 +736,6 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "BOX64_DYNAREC_PURGE",
|
||||
"description": "Purge DynaBlocks that haven't been executed recently, based on tick age threshold (BOX64_DYNAREC_PURGE_AGE).",
|
||||
"category": "Fragile or Legacy",
|
||||
"wine": false,
|
||||
"configurator": false,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
"description": "DynaRec will not purge old unused DynaBlocks.",
|
||||
"default": true
|
||||
},
|
||||
{
|
||||
"key": "1",
|
||||
"description": "DynaRec will purge old unused DynaBlocks based on tick age.",
|
||||
"default": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "BOX64_DYNAREC_PURGE_AGE",
|
||||
"description": "Tick age threshold for DynaBlock purging (requires BOX64_DYNAREC_PURGE=1).",
|
||||
"category": "Fragile or Legacy",
|
||||
"wine": false,
|
||||
"configurator": false,
|
||||
"options": [
|
||||
{
|
||||
"key": "4096",
|
||||
"description": "Default age threshold.",
|
||||
"default": true
|
||||
},
|
||||
{
|
||||
"key": "XXXX",
|
||||
"description": "Custom age threshold (range: 10-65536).",
|
||||
"default": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "BOX64_DYNAREC_SAFEFLAGS",
|
||||
"description": "Behaviour of flags emulation on CALL/RET opcodes and other edge cases.",
|
||||
@@ -2489,4 +2451,4 @@
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
]
|
||||
+1
-15
@@ -252,20 +252,6 @@
|
||||
"1": "DynaRec 将生成 perf 映射。"
|
||||
}
|
||||
},
|
||||
"BOX64_DYNAREC_PURGE": {
|
||||
"description": "根据年龄阈值(BOX64_DYNAREC_PURGE_AGE)清除最近未执行的代码块。",
|
||||
"options": {
|
||||
"0": "DynaRec 不会清除旧的未使用代码块。",
|
||||
"1": "DynaRec 将根据年龄阈值清除旧的未使用代码块。"
|
||||
}
|
||||
},
|
||||
"BOX64_DYNAREC_PURGE_AGE": {
|
||||
"description": "代码块清除的年龄阈值(需要 BOX64_DYNAREC_PURGE=1)。",
|
||||
"options": {
|
||||
"4096": "默认年龄阈值。",
|
||||
"XXXX": "自定义年龄阈值(范围:10-65536)。"
|
||||
}
|
||||
},
|
||||
"BOX64_DYNAREC_SAFEFLAGS": {
|
||||
"description": "在 CALL/RET 指令和其他边缘情况下 FLAGS 模拟的行为。",
|
||||
"options": {
|
||||
@@ -874,4 +860,4 @@
|
||||
"1": "不为 32 位二进制文件切换 personality。"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+12
-85
@@ -1697,68 +1697,6 @@ dynablock_t* FindDynablockFromNativeAddress(void* p)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// To measure speed at wich blocks are created, to avoid purge when lots of blocks are created in burst
|
||||
static uint64_t start_time = 0;
|
||||
static uint32_t start_tick = 0;
|
||||
static uint64_t tick_freq = 0;
|
||||
static uint64_t cur_speed = 0;
|
||||
|
||||
void UpdateBlockCreationSpeed()
|
||||
{
|
||||
if(!tick_freq) {
|
||||
tick_freq = ReadTSCFrequency(NULL);
|
||||
start_tick = my_context->tick;
|
||||
start_time = ReadTSC(NULL);
|
||||
}
|
||||
uint64_t cur_time = ReadTSC(NULL);
|
||||
// compute elapsed time is micro seconds
|
||||
uint64_t elapsed_time = (cur_time-start_time)*1000000LL/tick_freq;
|
||||
if(my_context->tick-start_tick>100 || elapsed_time>1000) {
|
||||
// update speed each 100 blocks created or 1ms elapsed
|
||||
cur_speed = (my_context->tick-start_tick)*1000000LL/elapsed_time;
|
||||
start_tick = my_context->tick;
|
||||
start_time = cur_time;
|
||||
}
|
||||
}
|
||||
|
||||
int PurgeDynarecMap(mmaplist_t* list, size_t size)
|
||||
{
|
||||
if(cur_speed>100) return 0; // 100 blocks / sec is a burst!
|
||||
// check all blocks where tick is old enough and in_used==0, then delete them
|
||||
// return 1 as soon as one block has been deleted, 0 else
|
||||
// beware that tick=0 blocks means they were never executed and should not be touched
|
||||
int ret = 0;
|
||||
for(int i=0; i<list->size && !ret; ++i) {
|
||||
blocklist_t* bl = list->chunks[i];
|
||||
blockmark_t* p = bl->block;
|
||||
blockmark_t* end = bl->block + bl->size - sizeof(blockmark_t);
|
||||
|
||||
while(p<end) {
|
||||
blockmark_t *n = NEXT_BLOCK(p);
|
||||
if(p->next.fill) {
|
||||
dynablock_t* dynablock = *(dynablock_t**)p->mark;
|
||||
int tick = native_lock_get_d(&dynablock->tick);
|
||||
if(tick && dynablock->done && (my_context->tick > tick) && ((my_context->tick-tick)>=BOX64ENV(dynarec_purge_age))) {
|
||||
int in_used = native_lock_get_d(&dynablock->in_used);
|
||||
if(!in_used) {
|
||||
// free the block, but unreference it first
|
||||
//if(setJumpTableDefaultIfRef64(dynablock->x64_addr, dynablock->block))
|
||||
{
|
||||
dynarec_log(LOG_INFO/*LOG_DEBUG*/, " PurgeDynablock %p\n", dynablock);
|
||||
if((n<end) && !n->next.fill )
|
||||
n = NEXT_BLOCK(n); //because the block will be agglomerated
|
||||
FreeDynablock(dynablock, 0, 1);
|
||||
if((bl->maxfree>=size))
|
||||
ret = 1;
|
||||
} // fail to set default jump, so skipping
|
||||
}
|
||||
}
|
||||
}
|
||||
p = n;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
#ifdef TRACE_MEMSTAT
|
||||
static uint64_t dynarec_allocated = 0;
|
||||
#endif
|
||||
@@ -1769,11 +1707,6 @@ uintptr_t AllocDynarecMap(uintptr_t x64_addr, size_t size, int is_new)
|
||||
|
||||
size = roundSize(size);
|
||||
|
||||
if(BOX64ENV(dynarec_purge)) {
|
||||
__atomic_fetch_add(&my_context->tick, 1, __ATOMIC_RELAXED);
|
||||
UpdateBlockCreationSpeed();
|
||||
}
|
||||
|
||||
mmaplist_t* list = GetMmaplistByAddr(x64_addr);
|
||||
if(!list)
|
||||
list = mmaplist;
|
||||
@@ -1783,26 +1716,20 @@ uintptr_t AllocDynarecMap(uintptr_t x64_addr, size_t size, int is_new)
|
||||
list->dirty = 1;
|
||||
// check if there is space in current open ones
|
||||
uintptr_t sz = size + 2*sizeof(blockmark_t);
|
||||
int recheck = 0;
|
||||
do {
|
||||
for(int i=0; i<list->size; ++i) {
|
||||
if(list->chunks[i]->maxfree>=size) {
|
||||
// looks free, try to alloc!
|
||||
size_t rsize = 0;
|
||||
void* sub = getFirstBlock(list->chunks[i]->block, size, &rsize, list->chunks[i]->first);
|
||||
if(sub) {
|
||||
void* ret = allocBlock(list->chunks[i]->block, sub, size, &list->chunks[i]->first);
|
||||
if(rsize==list->chunks[i]->maxfree)
|
||||
list->chunks[i]->maxfree = getMaxFreeBlock(list->chunks[i]->block, list->chunks[i]->size, list->chunks[i]->first);
|
||||
//rb_set_64(list->chunks[i].tree, (uintptr_t)ret, (uintptr_t)ret+size, (uintptr_t)ret);
|
||||
return (uintptr_t)ret;
|
||||
}
|
||||
for(int i=0; i<list->size; ++i) {
|
||||
if(list->chunks[i]->maxfree>=size) {
|
||||
// looks free, try to alloc!
|
||||
size_t rsize = 0;
|
||||
void* sub = getFirstBlock(list->chunks[i]->block, size, &rsize, list->chunks[i]->first);
|
||||
if(sub) {
|
||||
void* ret = allocBlock(list->chunks[i]->block, sub, size, &list->chunks[i]->first);
|
||||
if(rsize==list->chunks[i]->maxfree)
|
||||
list->chunks[i]->maxfree = getMaxFreeBlock(list->chunks[i]->block, list->chunks[i]->size, list->chunks[i]->first);
|
||||
//rb_set_64(list->chunks[i].tree, (uintptr_t)ret, (uintptr_t)ret+size, (uintptr_t)ret);
|
||||
return (uintptr_t)ret;
|
||||
}
|
||||
}
|
||||
// check if we can remove blocks before allocating a new one
|
||||
if(BOX64ENV(dynarec_purge))
|
||||
recheck = recheck?0:PurgeDynarecMap(list, size); // don't do purge all the time, it's too time consuming
|
||||
} while(recheck);
|
||||
}
|
||||
// need to add a new
|
||||
if(list->size == list->cap) {
|
||||
list->cap+=4;
|
||||
|
||||
@@ -343,7 +343,7 @@ void jump_to_epilog(dynarec_arm_t* dyn, uintptr_t ip, int reg, int ninst)
|
||||
TABLE64C(x2, const_epilog);
|
||||
SMEND();
|
||||
CHECK_DFNONE(0);
|
||||
if(dyn->have_purge)
|
||||
if (BOX64DRENV(dynarec_callret) >= 2)
|
||||
doLeaveBlock(dyn, ninst, x4, x5, x6);
|
||||
BR(x2);
|
||||
}
|
||||
@@ -419,7 +419,7 @@ void jump_to_next(dynarec_arm_t* dyn, uintptr_t ip, int reg, int ninst, int is32
|
||||
if(reg!=x1) {
|
||||
MOVx_REG(x1, xRIP);
|
||||
}
|
||||
if(dyn->have_purge && !dyn->insts[ninst].x64.has_callret)
|
||||
if(BOX64DRENV(dynarec_callret) >= 2 && !dyn->insts[ninst].x64.has_callret)
|
||||
doLeaveBlock(dyn, ninst, x4, x5, x6);
|
||||
// #ifdef HAVE_TRACE
|
||||
// The BLR form is only for gdb backtraces, but it breaks the
|
||||
@@ -445,7 +445,7 @@ void ret_to_next(dynarec_arm_t* dyn, uintptr_t ip, int ninst, rex_t rex)
|
||||
// pop the actual return address for ARM stack
|
||||
LDPx_S7_postindex(xLR, x6, xSP, 16);
|
||||
SUBx_REG(x6, x6, xRIP); // is it the right address?
|
||||
if(dyn->have_purge)
|
||||
if (BOX64DRENV(dynarec_callret) >= 2)
|
||||
doLeaveBlock(dyn, ninst, x4, x5, x3);
|
||||
CBNZx(x6, 2*4);
|
||||
RET(xLR);
|
||||
@@ -454,8 +454,6 @@ void ret_to_next(dynarec_arm_t* dyn, uintptr_t ip, int ninst, rex_t rex)
|
||||
}
|
||||
NOTEST(x2);
|
||||
int dest = indirect_lookup(dyn, ninst, rex.is32bits, x2, x3);
|
||||
if(dyn->have_purge && !BOX64DRENV(dynarec_callret))
|
||||
doLeaveBlock(dyn, ninst, x4, x5, x6);
|
||||
#ifdef HAVE_TRACE
|
||||
BLR(dest);
|
||||
#else
|
||||
@@ -2872,10 +2870,6 @@ void doEnterBlock(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3)
|
||||
STLXRw(s3, s2, s1);
|
||||
CBNZw(s3, -3*4);
|
||||
}
|
||||
// set tick
|
||||
LDRx_U12(s2, xEmu, offsetof(x64emu_t, context));
|
||||
LDRw_U12(s2, s2, offsetof(box64context_t, tick));
|
||||
STRw_U12(s2, s1, offsetof(dynablock_t, tick)-offsetof(dynablock_t, in_used));
|
||||
MESSAGE(LOG_INFO, "-------- doEnter\n");
|
||||
}
|
||||
void doLeaveBlock(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3)
|
||||
|
||||
@@ -214,7 +214,6 @@ typedef struct dynarec_arm_s {
|
||||
uint8_t use_mmx:1;
|
||||
uint8_t use_xmm:1;
|
||||
uint8_t use_ymm:1;
|
||||
uint8_t have_purge:1; // set to 1 if block can be purged
|
||||
uint8_t is_file_mapped:1; // if the memory is a mapped file (probably binary, not a memory)
|
||||
void* gdbjit_block;
|
||||
uint32_t need_x87check; // needs x87 precision control check if non-null, or 0 if not
|
||||
|
||||
@@ -46,7 +46,6 @@ void* create_updateflags()
|
||||
// pass 0
|
||||
updateflags_pass0(&helper, jmp_df);
|
||||
// check if all flags are handled
|
||||
helper.have_purge = 0; // force no purge
|
||||
int ok = 1;
|
||||
for(int i=d_none; i<d_unknown; ++i)
|
||||
if(!jmp_df[i]) {
|
||||
|
||||
+37
-5
@@ -118,13 +118,45 @@ static void DeferFreeDynablockMap(dynablock_t* db)
|
||||
{
|
||||
// enq for a deferred free so any threads still running in this block has a better chance to finish.
|
||||
if (my_context->db_zombie_count == DB_ZOMBIE_SIZE) {
|
||||
if(my_context->db_zombie[my_context->db_zombie_head])
|
||||
FreeDynarecMap((uintptr_t)my_context->db_zombie[my_context->db_zombie_head]->actual_block);
|
||||
// Queue full: free the oldest queued block that no running dynarec chain holds (in_used), compact the queue.
|
||||
int idx = -1; // queue position of the entry to drop, 0 = oldest
|
||||
int idx_in_used = 0; // in_used count of that entry
|
||||
for (int i = 0; i < DB_ZOMBIE_SIZE; ++i) {
|
||||
int slot = (my_context->db_zombie_head - DB_ZOMBIE_SIZE + i + DB_ZOMBIE_SIZE) % DB_ZOMBIE_SIZE;
|
||||
dynablock_t* z = my_context->db_zombie[slot];
|
||||
if (!z)
|
||||
continue;
|
||||
int cnt = native_lock_get_d(&z->in_used);
|
||||
if (cnt <= 0) {
|
||||
idx = i;
|
||||
idx_in_used = cnt;
|
||||
break;
|
||||
}
|
||||
if (idx < 0) {
|
||||
idx = i; // remember the oldest held block, in case all of them are held
|
||||
idx_in_used = cnt;
|
||||
}
|
||||
}
|
||||
if (idx < 0)
|
||||
idx = 0; // queue is full of empty slots: just drop the oldest one
|
||||
// free the picked entry
|
||||
int slot = (my_context->db_zombie_head - DB_ZOMBIE_SIZE + idx + DB_ZOMBIE_SIZE) % DB_ZOMBIE_SIZE;
|
||||
if (idx_in_used > 0)
|
||||
printf_log(LOG_INFO, "Warning, all %d queued dynablocks are still in use, freeing the oldest one anyway (in_used=%d)\n", DB_ZOMBIE_SIZE, idx_in_used);
|
||||
if (my_context->db_zombie[slot])
|
||||
FreeDynarecMap((uintptr_t)my_context->db_zombie[slot]->actual_block);
|
||||
// shift all newer entries over the dropped one, then queue db at the tail
|
||||
for (int i = idx; i < DB_ZOMBIE_SIZE - 1; ++i) {
|
||||
int cur = (my_context->db_zombie_head - DB_ZOMBIE_SIZE + i + DB_ZOMBIE_SIZE) % DB_ZOMBIE_SIZE;
|
||||
int nxt = (my_context->db_zombie_head - DB_ZOMBIE_SIZE + i + 1 + DB_ZOMBIE_SIZE) % DB_ZOMBIE_SIZE;
|
||||
my_context->db_zombie[cur] = my_context->db_zombie[nxt];
|
||||
}
|
||||
my_context->db_zombie[(my_context->db_zombie_head - 1 + DB_ZOMBIE_SIZE) % DB_ZOMBIE_SIZE] = db;
|
||||
} else {
|
||||
my_context->db_zombie[my_context->db_zombie_head] = db;
|
||||
my_context->db_zombie_head = (my_context->db_zombie_head + 1) % DB_ZOMBIE_SIZE;
|
||||
my_context->db_zombie_count++;
|
||||
}
|
||||
my_context->db_zombie[my_context->db_zombie_head] = db;
|
||||
my_context->db_zombie_head = (my_context->db_zombie_head + 1) % DB_ZOMBIE_SIZE;
|
||||
}
|
||||
|
||||
void DeferFreeDynablockClearRange(void* addr, size_t sz)
|
||||
@@ -264,7 +296,7 @@ int FreeRangeDynablock(dynablock_t* db, uintptr_t addr, uintptr_t size)
|
||||
void dynablock_leave_runtime(dynablock_t* db)
|
||||
{
|
||||
if(!db) return;
|
||||
if(!db->tick) return;
|
||||
if(BOX64ENV(dynarec_callret) < 2) return;
|
||||
__atomic_fetch_sub(&db->in_used, 1, __ATOMIC_ACQ_REL);
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,6 @@ typedef struct dynablock_s {
|
||||
void* block; // block-sizeof(void*) == self
|
||||
void* actual_block; // the actual start of the block (so block-sizeof(void*))
|
||||
uint32_t in_used;// will be 0 if not in_used, >0 if used be some code
|
||||
uint32_t tick; // last "tick" when dynablock was run
|
||||
void* x64_addr;
|
||||
uintptr_t x64_size;
|
||||
size_t native_size;
|
||||
|
||||
@@ -302,8 +302,13 @@ void EmuRun(x64emu_t* emu, int use_dynarec, int no_alt)
|
||||
if(!jblock) {
|
||||
printf_log(LOG_NONE, "Warning, cannot find Secondary Entry Point %p in dynablock %p\n", (void*)R_RIP, block);
|
||||
skip = 1;
|
||||
} else
|
||||
} else {
|
||||
#if defined(ARM64) || defined(LA64) || defined(RV64)
|
||||
if (jblock != block->block && BOX64ENV(dynarec_callret) >= 2)
|
||||
__atomic_fetch_add(&block->in_used, 1, __ATOMIC_ACQ_REL);
|
||||
#endif
|
||||
native_prolog(emu, jblock);
|
||||
}
|
||||
}
|
||||
if(emu->fork) {
|
||||
int forktype = emu->fork;
|
||||
|
||||
@@ -116,9 +116,6 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
|
||||
int dynarec_dirty = BOX64ENV(dynarec_dirty);
|
||||
#if STEP == 0
|
||||
memset(&dyn->insts[ninst], 0, sizeof(instruction_native_t));
|
||||
#ifdef ARM64
|
||||
dyn->have_purge = BOX64ENV(dynarec_purge);
|
||||
#endif
|
||||
#endif
|
||||
fpu_reset(dyn);
|
||||
ARCH_INIT();
|
||||
@@ -173,7 +170,7 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
|
||||
ip = addr;
|
||||
#ifdef ARM64
|
||||
if(!ninst) {
|
||||
if(dyn->have_purge)
|
||||
if (BOX64DRENV(dynarec_callret) >= 2)
|
||||
doEnterBlock(dyn, 0, x1, x2, x3);
|
||||
if(dyn->always_test)
|
||||
checkCRC(dyn, 0);
|
||||
@@ -183,6 +180,8 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
|
||||
}
|
||||
#elif defined(LA64)
|
||||
if(!ninst) {
|
||||
if (BOX64DRENV(dynarec_callret) >= 2)
|
||||
doEnterBlock(dyn, 0, x1, x2, x3);
|
||||
if(dyn->always_test)
|
||||
checkCRC(dyn, 0);
|
||||
if(dyn->insts[0].preload_xmmymm) {
|
||||
@@ -190,6 +189,11 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
|
||||
}
|
||||
ENDPREFIX;
|
||||
}
|
||||
#elif defined(RV64)
|
||||
if(!ninst) {
|
||||
if (BOX64DRENV(dynarec_callret) >= 2)
|
||||
doEnterBlock(dyn, 0, x1, x2, x3);
|
||||
}
|
||||
#endif
|
||||
fpu_propagate_stack(dyn, ninst);
|
||||
if (reset_n!=-1) {
|
||||
|
||||
@@ -379,6 +379,8 @@ void jump_to_epilog(dynarec_la64_t* dyn, uintptr_t ip, int reg, int ninst)
|
||||
TABLE64C(x2, const_epilog);
|
||||
SMEND();
|
||||
CHECK_DFNONE(0);
|
||||
if (BOX64DRENV(dynarec_callret) >= 2)
|
||||
doLeaveBlock(dyn, ninst, x4, x5, x6);
|
||||
BR(x2);
|
||||
}
|
||||
|
||||
@@ -399,9 +401,35 @@ void jump_to_epilog_fast(dynarec_la64_t* dyn, uintptr_t ip, int reg, int ninst)
|
||||
TABLE64C(x2, const_epilog_fast);
|
||||
SMEND();
|
||||
CHECK_DFNONE(0);
|
||||
if (BOX64DRENV(dynarec_callret) >= 2)
|
||||
doLeaveBlock(dyn, ninst, x4, x5, x6);
|
||||
BR(x2);
|
||||
}
|
||||
|
||||
void doEnterBlock(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3)
|
||||
{
|
||||
MESSAGE(LOG_DUMP, "doEnter --------\n");
|
||||
int delta = -(dyn->native_size + sizeof(void*));
|
||||
PCADDU12I(s1, SPLIT20(delta));
|
||||
ADDI_D(s1, s1, SPLIT12(delta));
|
||||
LD_D(s1, s1, 0); // load the dynablock pointer
|
||||
ADDI_D(s1, s1, offsetof(dynablock_t, in_used));
|
||||
MOV32w(s3, 1);
|
||||
AMADD_W(s2, s3, s1);
|
||||
}
|
||||
|
||||
void doLeaveBlock(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3)
|
||||
{
|
||||
MESSAGE(LOG_DUMP, "doLeave --------\n");
|
||||
int delta = -(dyn->native_size + sizeof(void*));
|
||||
PCADDU12I(s1, SPLIT20(delta));
|
||||
ADDI_D(s1, s1, SPLIT12(delta));
|
||||
LD_D(s1, s1, 0); // load the dynablock pointer
|
||||
ADDI_D(s1, s1, offsetof(dynablock_t, in_used));
|
||||
MOV32w(s3, -1);
|
||||
AMADD_W(s2, s3, s1);
|
||||
}
|
||||
|
||||
|
||||
static int indirect_lookup(dynarec_la64_t* dyn, int ninst, int is32bits, int s1, int s2)
|
||||
{
|
||||
@@ -461,6 +489,8 @@ void jump_to_next(dynarec_la64_t* dyn, uintptr_t ip, int reg, int ninst, int is3
|
||||
}
|
||||
CLEARIP();
|
||||
SMEND();
|
||||
if (BOX64DRENV(dynarec_callret) >= 2 && !dyn->insts[ninst].x64.has_callret)
|
||||
doLeaveBlock(dyn, ninst, x4, x5, x6);
|
||||
// The JIRL(xRA, ...) form is only for gdb backtraces, but it breaks the
|
||||
// return-address-stack prediction on every block-to-block jump, which is
|
||||
// not worth it. Uncomment temporarily when debugging with gdb.
|
||||
@@ -484,6 +514,8 @@ void ret_to_next(dynarec_la64_t* dyn, uintptr_t ip, int ninst, rex_t rex)
|
||||
LD_D(xRA, xSP, 0); // native addr
|
||||
LD_D(x6, xSP, 8); // x86 addr
|
||||
ADDI_D(xSP, xSP, 16); // pop
|
||||
if (BOX64DRENV(dynarec_callret) >= 2)
|
||||
doLeaveBlock(dyn, ninst, x4, x5, x7);
|
||||
BNE(x6, xRIP, 2 * 4); // is it the right address?
|
||||
BR(xRA);
|
||||
// not the correct return address, regular jump, but purge the stack first, it's unsync now...
|
||||
|
||||
@@ -1799,6 +1799,8 @@ void emit_inline_leaf(dynarec_la64_t* dyn, int ninst);
|
||||
#define jump_to_epilog_fast STEPNAME(jump_to_epilog_fast)
|
||||
#define jump_to_next STEPNAME(jump_to_next)
|
||||
#define ret_to_next STEPNAME(ret_to_next)
|
||||
#define doEnterBlock STEPNAME(doEnterBlock)
|
||||
#define doLeaveBlock STEPNAME(doLeaveBlock)
|
||||
#define iret_to_next STEPNAME(iret_to_next)
|
||||
#define call_c STEPNAME(call_c)
|
||||
#define call_n STEPNAME(call_n)
|
||||
@@ -1974,6 +1976,8 @@ uintptr_t geted16(dynarec_la64_t* dyn, uintptr_t addr, int ninst, uint8_t nextop
|
||||
// generic x64 helper
|
||||
void jump_to_epilog(dynarec_la64_t* dyn, uintptr_t ip, int reg, int ninst);
|
||||
void jump_to_epilog_fast(dynarec_la64_t* dyn, uintptr_t ip, int reg, int ninst);
|
||||
void doEnterBlock(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3);
|
||||
void doLeaveBlock(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3);
|
||||
void jump_to_next(dynarec_la64_t* dyn, uintptr_t ip, int reg, int ninst, int is32bits);
|
||||
void ret_to_next(dynarec_la64_t* dyn, uintptr_t ip, int ninst, rex_t rex);
|
||||
void iret_to_next(dynarec_la64_t* dyn, uintptr_t ip, int ninst, int is32bits, int is64bits);
|
||||
|
||||
@@ -197,7 +197,6 @@ typedef struct dynarec_ppc64le_s {
|
||||
uint8_t use_mmx:1;
|
||||
uint8_t use_xmm:1;
|
||||
uint8_t use_ymm:1;
|
||||
uint8_t have_purge:1; // set to 1 if block can be purged
|
||||
uint8_t is_file_mapped:1; // if the memory is a mapped file (probably binary, not a memory)
|
||||
void* gdbjit_block;
|
||||
uint32_t need_x87check; // needs x87 precision control check if non-null, or 0 if not
|
||||
|
||||
@@ -381,6 +381,8 @@ void jump_to_epilog(dynarec_rv64_t* dyn, uintptr_t ip, int reg, int ninst)
|
||||
TABLE64C(x2, const_epilog);
|
||||
SMEND();
|
||||
CHECK_DFNONE(0);
|
||||
if (BOX64DRENV(dynarec_callret) >= 2)
|
||||
doLeaveBlock(dyn, ninst, x4, x5, x6);
|
||||
BR(x2);
|
||||
}
|
||||
|
||||
@@ -401,8 +403,34 @@ void jump_to_epilog_fast(dynarec_rv64_t* dyn, uintptr_t ip, int reg, int ninst)
|
||||
TABLE64C(x2, const_epilog_fast);
|
||||
SMEND();
|
||||
CHECK_DFNONE(0);
|
||||
if (BOX64DRENV(dynarec_callret) >= 2)
|
||||
doLeaveBlock(dyn, ninst, x4, x5, x6);
|
||||
BR(x2);
|
||||
}
|
||||
|
||||
void doEnterBlock(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3)
|
||||
{
|
||||
MESSAGE(LOG_DUMP, "doEnter --------\n");
|
||||
int delta = -(dyn->native_size + sizeof(void*));
|
||||
AUIPC(s1, SPLIT20(delta));
|
||||
ADDI(s1, s1, SPLIT12(delta));
|
||||
LD(s1, s1, 0); // load the dynablock pointer
|
||||
ADDI(s1, s1, offsetof(dynablock_t, in_used));
|
||||
MOV32w(s3, 1);
|
||||
AMOADD_W(s2, s3, s1, 0, 0);
|
||||
}
|
||||
|
||||
void doLeaveBlock(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3)
|
||||
{
|
||||
MESSAGE(LOG_DUMP, "doLeave --------\n");
|
||||
int delta = -(dyn->native_size + sizeof(void*));
|
||||
AUIPC(s1, SPLIT20(delta));
|
||||
ADDI(s1, s1, SPLIT12(delta));
|
||||
LD(s1, s1, 0); // load the dynablock pointer
|
||||
ADDI(s1, s1, offsetof(dynablock_t, in_used));
|
||||
MOV32w(s3, -1);
|
||||
AMOADD_W(s2, s3, s1, 0, 0);
|
||||
}
|
||||
#ifdef JMPTABLE_SHIFT4
|
||||
#error TODO!
|
||||
#endif
|
||||
@@ -485,6 +513,8 @@ void jump_to_next(dynarec_rv64_t* dyn, uintptr_t ip, int reg, int ninst, int is3
|
||||
}
|
||||
CLEARIP();
|
||||
SMEND();
|
||||
if (BOX64DRENV(dynarec_callret) >= 2 && !dyn->insts[ninst].x64.has_callret)
|
||||
doLeaveBlock(dyn, ninst, x4, x5, x6);
|
||||
// #ifdef HAVE_TRACE
|
||||
// The JALR(xRA, ...) form is only for gdb backtraces, but it breaks the
|
||||
// return-address-stack prediction on every block-to-block jump, which is
|
||||
@@ -508,6 +538,8 @@ void ret_to_next(dynarec_rv64_t* dyn, uintptr_t ip, int ninst, rex_t rex)
|
||||
LD(xRA, xSP, 0); // native addr
|
||||
LD(x6, xSP, 8); // x86 addr
|
||||
ADDI(xSP, xSP, 16); // pop
|
||||
if (BOX64DRENV(dynarec_callret) >= 2)
|
||||
doLeaveBlock(dyn, ninst, x4, x5, x7);
|
||||
BNE(x6, xRIP, 2 * 4); // is it the right address?
|
||||
BR(xRA);
|
||||
// not the correct return address, regular jump, but purge the stack first, it's unsync now...
|
||||
|
||||
@@ -1337,6 +1337,8 @@
|
||||
#define jump_to_epilog_fast STEPNAME(jump_to_epilog_fast)
|
||||
#define jump_to_next STEPNAME(jump_to_next)
|
||||
#define ret_to_next STEPNAME(ret_to_next)
|
||||
#define doEnterBlock STEPNAME(doEnterBlock)
|
||||
#define doLeaveBlock STEPNAME(doLeaveBlock)
|
||||
#define iret_to_next STEPNAME(iret_to_next)
|
||||
#define call_c STEPNAME(call_c)
|
||||
#define call_n STEPNAME(call_n)
|
||||
@@ -1524,6 +1526,8 @@ uintptr_t geted16(dynarec_rv64_t* dyn, uintptr_t addr, int ninst, uint8_t nextop
|
||||
// generic x64 helper
|
||||
void jump_to_epilog(dynarec_rv64_t* dyn, uintptr_t ip, int reg, int ninst);
|
||||
void jump_to_epilog_fast(dynarec_rv64_t* dyn, uintptr_t ip, int reg, int ninst);
|
||||
void doEnterBlock(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3);
|
||||
void doLeaveBlock(dynarec_rv64_t* dyn, int ninst, int s1, int s2, int s3);
|
||||
void jump_to_next(dynarec_rv64_t* dyn, uintptr_t ip, int reg, int ninst, int is32bits);
|
||||
void ret_to_next(dynarec_rv64_t* dyn, uintptr_t ip, int ninst, rex_t rex);
|
||||
void iret_to_next(dynarec_rv64_t* dyn, uintptr_t ip, int ninst, int is32bits, int is64bits);
|
||||
|
||||
@@ -97,7 +97,6 @@ typedef struct base_segment_s {
|
||||
} base_segment_t;
|
||||
|
||||
typedef struct box64context_s {
|
||||
uint32_t tick; // for dynarec age
|
||||
path_collection_t box64_path; // PATH env. variable
|
||||
path_collection_t box64_ld_lib; // LD_LIBRARY_PATH env. variable
|
||||
|
||||
|
||||
@@ -80,8 +80,6 @@ extern char* ftrace_name;
|
||||
INTEGER(BOX64_DYNAREC_WEAKBARRIER, dynarec_weakbarrier, 1, 0, 2, 1, 2) \
|
||||
INTEGER(BOX64_DYNAREC_X87DOUBLE, dynarec_x87double, 0, 0, 2, 1, 2) \
|
||||
BOOLEAN(BOX64_DYNAREC_INTERP_SIGNAL, dynarec_interp_signal, 0, 0, 0) \
|
||||
BOOLEAN(BOX64_DYNAREC_PURGE, dynarec_purge, 0, 0, 0) \
|
||||
INTEGER(BOX64_DYNAREC_PURGE_AGE, dynarec_purge_age, 4096, 10, 65536, 0, 0) \
|
||||
BOOLEAN(BOX64_NODYNAREC_DELAY, nodynarec_delay, 0, 1, 0) \
|
||||
STRING(BOX64_EMULATED_LIBS, emulated_libs, 0, 0) \
|
||||
INTEGER(BOX64_DYNAREC_NOARCH, dynarec_noarch, 0, 0, 2, 1, 2) \
|
||||
|
||||
@@ -441,11 +441,6 @@ void SerializeMmaplist(mapping_t* mapping)
|
||||
return;
|
||||
if((!mapping->env || !mapping->env->is_dynacache_overridden) && box64env.dynacache!=1)
|
||||
return;
|
||||
// don't do serialize for program that needs purge=1
|
||||
if(mapping->env && mapping->env->is_dynarec_purge_overridden && mapping->env->dynarec_purge)
|
||||
return;
|
||||
if((!mapping->env || !mapping->env->is_dynarec_purge_overridden) && box64env.dynarec_purge)
|
||||
return;
|
||||
// don't do serialize for program that needs dirty=1
|
||||
if(mapping->env && mapping->env->is_dynarec_dirty_overridden && mapping->env->dynarec_dirty)
|
||||
return;
|
||||
|
||||
@@ -729,7 +729,6 @@ BOX64_DYNACACHE=0 #something upset this app
|
||||
BOX64_DYNAREC_STRONGMEM=1
|
||||
BOX64_DYNAREC_SAFEFLAGS=2
|
||||
BOX64_DYNAREC_BIGBLOCK=0
|
||||
BOX64_DYNAREC_PURGE=1
|
||||
|
||||
[Link2EA.exe]
|
||||
BOX64_DYNAREC_STRONGMEM=1
|
||||
@@ -804,7 +803,6 @@ BOX64_DYNAREC_STRONGMEM=1
|
||||
BOX64_DYNAREC_BIGBLOCK=0
|
||||
BOX64_DYNAREC_SAFEFLAGS=2
|
||||
BOX64_DYNAREC_CALLRET=0
|
||||
BOX64_DYNAREC_PURGE=1
|
||||
|
||||
[GCU2.exe]
|
||||
BOX64_DYNAREC_BIGBLOCK=3
|
||||
@@ -1170,7 +1168,6 @@ BOX64_DYNAREC_BIGBLOCK=3
|
||||
BOX64_DYNAREC_CALLRET=1
|
||||
BOX64_DYNAREC_SAFEFLAGS=0
|
||||
BOX64_DYNAREC_FASTROUND=0
|
||||
BOX64_DYNAREC_PURGE=1
|
||||
|
||||
# Steam for LA64
|
||||
[steam.exe]
|
||||
@@ -1341,7 +1338,6 @@ BOX64_DYNAREC_FASTNAN=0
|
||||
BOX64_DYNAREC_FASTROUND=0
|
||||
BOX64_SSE_FLUSHTO0=1
|
||||
BOX64_DYNAREC_STRONGMEM=1
|
||||
BOX64_DYNAREC_PURGE=1
|
||||
|
||||
[UplayService.exe]
|
||||
BOX64_DYNAREC_SAFEFLAGS=2
|
||||
|
||||
Reference in new issue
Block a user