[Debugger] JS API: Improve callback checks (fix #2123) (#2125)

* [Debugger] JS API: Fix project64#2122

* [Debugger] JS API: Improve callback checks (fix #2123)

* [Debugger] JS API: Improve callback checks (fix #2123)
This commit is contained in:
shyguyhex 2021-10-10 22:08:48 -05:00 committed by GitHub
parent 921c12e4d0
commit 9a287a53ee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 345 additions and 123 deletions

View File

@ -579,34 +579,55 @@ void CDebuggerUI::HandleCartToRamDMA(void)
// Called from the interpreter core at the beginning of every CPU step
void CDebuggerUI::CPUStepStarted()
{
uint32_t pc = g_Reg->m_PROGRAM_COUNTER;
COpInfo opInfo(R4300iOp::m_Opcode);
bool bStoreOp = opInfo.IsStoreCommand();
uint32_t storeAddress = bStoreOp ? opInfo.GetLoadStoreAddress() : 0;
if (isStepping() && bCPULoggingEnabled())
{
Debug_RefreshCPULogWindow();
}
if(bStoreOp && m_Breakpoints->NumMemLocks() > 0)
if(m_Breakpoints->NumMemLocks() > 0)
{
if (m_Breakpoints->MemLockExists(storeAddress, opInfo.NumBytesToStore()))
COpInfo opInfo(R4300iOp::m_Opcode);
bool bStoreOp = opInfo.IsStoreCommand();
if (bStoreOp)
{
// Memory is locked, skip op
g_Settings->SaveBool(Debugger_SkipOp, true);
return;
uint32_t storeAddress = bStoreOp ? opInfo.GetLoadStoreAddress() : 0;
if (m_Breakpoints->MemLockExists(storeAddress, opInfo.NumBytesToStore()))
{
// Memory is locked, skip op
g_Settings->SaveBool(Debugger_SkipOp, true);
return;
}
}
}
JSHookCpuStepEnv hookEnv = { 0 };
hookEnv.pc = pc;
hookEnv.opInfo = opInfo;
if (m_ScriptSystem->HaveAppCallbacks())
{
JSHookCpuStepEnv hookEnv;
hookEnv.pc = g_Reg->m_PROGRAM_COUNTER;
hookEnv.opInfo = COpInfo(R4300iOp::m_Opcode);
m_ScriptSystem->InvokeAppCallbacks(JS_HOOK_CPUSTEP, (void*)&hookEnv);
if(m_ScriptSystem->HaveCpuExecCallbacks(hookEnv.pc))
{
m_ScriptSystem->InvokeAppCallbacks(JS_HOOK_CPU_EXEC, (void*)&hookEnv);
}
if (hookEnv.opInfo.IsLoadCommand() &&
m_ScriptSystem->HaveCpuReadCallbacks(hookEnv.opInfo.GetLoadStoreAddress()))
{
m_ScriptSystem->InvokeAppCallbacks(JS_HOOK_CPU_READ, (void*)&hookEnv);
}
else if (hookEnv.opInfo.IsStoreCommand() &&
m_ScriptSystem->HaveCpuWriteCallbacks(hookEnv.opInfo.GetLoadStoreAddress()))
{
m_ScriptSystem->InvokeAppCallbacks(JS_HOOK_CPU_WRITE, (void*)&hookEnv);
}
}
if (CDebugSettings::ExceptionBreakpoints() != 0)
{
uint32_t pc = g_Reg->m_PROGRAM_COUNTER;
if (pc == 0x80000000 || pc == 0x80000080 ||
pc == 0xA0000100 || pc == 0x80000180)
{
@ -619,6 +640,8 @@ void CDebuggerUI::CPUStepStarted()
if (m_Breakpoints->HaveRegBP())
{
COpInfo opInfo(R4300iOp::m_Opcode);
if (m_Breakpoints->HaveAnyGPRWriteBP())
{
int nReg = 0;

View File

@ -375,7 +375,7 @@ JSAppCallbackID ScriptAPI::AddAppCallback(duk_context* ctx, duk_idx_t callbackId
JSAppCallbackID ScriptAPI::AddAppCallback(duk_context* ctx, JSAppHookID hookId, JSAppCallback& callback)
{
CScriptInstance* inst = GetInstance(ctx);
JSAppCallbackID callbackId = inst->System()->RawAddAppCallback(hookId, callback);
JSAppCallbackID callbackId = inst->System()->QueueAddAppCallback(hookId, callback);
if(callbackId == JS_INVALID_CALLBACK)
{
@ -400,8 +400,6 @@ JSAppCallbackID ScriptAPI::AddAppCallback(duk_context* ctx, JSAppHookID hookId,
duk_pop(ctx);
inst->IncRefCount();
return callbackId;
}
@ -431,12 +429,7 @@ duk_ret_t ScriptAPI::js__AppCallbackFinalizer(duk_context* ctx)
JSAppCallbackID callbackId = (JSAppCallbackID)duk_get_uint(ctx, -1);
duk_pop_n(ctx, 2);
bool bRemoved = inst->System()->RawRemoveAppCallback(hookId, callbackId);
if(bRemoved)
{
inst->DecRefCount();
}
inst->System()->QueueRemoveAppCallback(hookId, callbackId);
return 0;
}

View File

@ -92,7 +92,7 @@ duk_ret_t ScriptAPI::js_events_onexec(duk_context* ctx)
cb.m_Params.addrStart = addrStart;
cb.m_Params.addrEnd = addrEnd;
JSAppCallbackID callbackId = AddAppCallback(ctx, JS_HOOK_CPUSTEP, cb);
JSAppCallbackID callbackId = AddAppCallback(ctx, JS_HOOK_CPU_EXEC, cb);
duk_push_uint(ctx, callbackId);
return 1;
@ -112,7 +112,7 @@ duk_ret_t ScriptAPI::js_events_onread(duk_context* ctx)
cb.m_Params.addrStart = addrStart;
cb.m_Params.addrEnd = addrEnd;
JSAppCallbackID callbackId = AddAppCallback(ctx, JS_HOOK_CPUSTEP, cb);
JSAppCallbackID callbackId = AddAppCallback(ctx, JS_HOOK_CPU_READ, cb);
duk_push_uint(ctx, callbackId);
return 1;
@ -132,7 +132,7 @@ duk_ret_t ScriptAPI::js_events_onwrite(duk_context* ctx)
cb.m_Params.addrStart = addrStart;
cb.m_Params.addrEnd = addrEnd;
JSAppCallbackID callbackId = AddAppCallback(ctx, JS_HOOK_CPUSTEP, cb);
JSAppCallbackID callbackId = AddAppCallback(ctx, JS_HOOK_CPU_WRITE, cb);
duk_push_uint(ctx, callbackId);
return 1;
@ -157,7 +157,7 @@ duk_ret_t ScriptAPI::js_events_onopcode(duk_context* ctx)
cb.m_Params.opcode = opcode;
cb.m_Params.opcodeMask = mask;
JSAppCallbackID callbackId = AddAppCallback(ctx, JS_HOOK_CPUSTEP, cb);
JSAppCallbackID callbackId = AddAppCallback(ctx, JS_HOOK_CPU_EXEC, cb);
duk_push_uint(ctx, callbackId);
return 1;
@ -179,7 +179,7 @@ duk_ret_t ScriptAPI::js_events_ongprvalue(duk_context* ctx)
cb.m_Params.regIndices = duk_get_uint(ctx, 1);
cb.m_Params.regValue = duk_get_uint(ctx, 2);
JSAppCallbackID callbackId = AddAppCallback(ctx, JS_HOOK_CPUSTEP, cb);
JSAppCallbackID callbackId = AddAppCallback(ctx, JS_HOOK_CPU_EXEC, cb);
duk_push_uint(ctx, callbackId);
return 1;
@ -258,7 +258,7 @@ bool CbCond_ReadAddrBetween(JSAppCallback* cb, void* _env)
{
JSHookCpuStepEnv* env = (JSHookCpuStepEnv*)_env;
if(!env->opInfo.IsLoadCommand())
if (!env->opInfo.IsLoadCommand())
{
return false;
}
@ -273,7 +273,7 @@ bool CbCond_WriteAddrBetween(JSAppCallback* cb, void* _env)
{
JSHookCpuStepEnv* env = (JSHookCpuStepEnv*)_env;
if(!env->opInfo.IsStoreCommand())
if (!env->opInfo.IsStoreCommand())
{
return false;
}

View File

@ -112,11 +112,6 @@ error_cleanup:
return false;
}
size_t CScriptInstance::GetRefCount()
{
return m_RefCount;
}
void CScriptInstance::IncRefCount()
{
m_RefCount++;
@ -135,27 +130,6 @@ void CScriptInstance::SetStopping(bool bStopping)
m_bStopping = bStopping;
}
bool CScriptInstance::IsStopping()
{
return m_bStopping;
}
void CScriptInstance::RawCall(void *dukFuncHeapPtr, JSDukArgSetupFunc argSetupFunc, void *param)
{
m_ExecStartTime = Timestamp();
duk_push_heapptr(m_Ctx, dukFuncHeapPtr);
duk_idx_t nargs = argSetupFunc ? argSetupFunc(m_Ctx, param) : 0;
if(duk_pcall(m_Ctx, nargs) == DUK_EXEC_ERROR)
{
duk_get_prop_string(m_Ctx, -1, "stack");
m_System->ConsoleLog("%s", duk_safe_to_string(m_Ctx, -1));
duk_pop(m_Ctx);
}
duk_pop(m_Ctx);
}
void CScriptInstance::RawCMethodCall(void* dukThisHeapPtr, duk_c_function func, JSDukArgSetupFunc argSetupFunc, void *argSetupParam)
{
m_ExecStartTime = Timestamp();
@ -179,25 +153,6 @@ void CScriptInstance::PostCMethodCall(void* dukThisHeapPtr, duk_c_function func,
m_System->PostCMethodCall(m_InstanceName.c_str(), dukThisHeapPtr, func, argSetupFunc, argSetupParam, argSetupParamSize);
}
void CScriptInstance::RawInvokeAppCallback(JSAppCallback& cb, void* _hookEnv)
{
if (cb.m_ConditionFunc != nullptr && !cb.m_ConditionFunc(&cb, _hookEnv))
{
return;
}
m_CurExecCallbackId = cb.m_CallbackId;
RawCall(cb.m_DukFuncHeapPtr, cb.m_DukArgSetupFunc, _hookEnv);
if (cb.m_CleanupFunc != nullptr)
{
cb.m_CleanupFunc(m_Ctx, _hookEnv);
}
m_CurExecCallbackId = JS_INVALID_CALLBACK;
}
void CScriptInstance::RawConsoleInput(const char* code)
{
m_System->ConsoleLog("> %s", code);

View File

@ -32,21 +32,45 @@ public:
void SetExecTimeout(uint64_t timeout);
bool IsTimedOut();
size_t GetRefCount();
inline size_t GetRefCount() { return m_RefCount; }
void IncRefCount();
void DecRefCount();
void SetStopping(bool bStopping);
bool IsStopping();
inline bool IsStopping() { return m_bStopping; }
bool RegisterWorker(CScriptWorker* worker);
void UnregisterWorker(CScriptWorker* worker);
void StopRegisteredWorkers();
void RawInvokeAppCallback(JSAppCallback& cb, void *_hookEnv);
inline void RawInvokeAppCallback(JSAppCallback& cb, void* _hookEnv)
{
m_CurExecCallbackId = cb.m_CallbackId;
void RawConsoleInput(const char* code);
RawCall(cb.m_DukFuncHeapPtr, cb.m_DukArgSetupFunc, _hookEnv);
void RawCall(void* dukFuncHeapPtr, JSDukArgSetupFunc argSetupFunc, void* param = nullptr);
if (cb.m_CleanupFunc != nullptr)
{
cb.m_CleanupFunc(m_Ctx, _hookEnv);
}
m_CurExecCallbackId = JS_INVALID_CALLBACK;
}
inline void RawCall(void *dukFuncHeapPtr, JSDukArgSetupFunc argSetupFunc, void *param = nullptr)
{
m_ExecStartTime = Timestamp();
duk_push_heapptr(m_Ctx, dukFuncHeapPtr);
duk_idx_t nargs = argSetupFunc ? argSetupFunc(m_Ctx, param) : 0;
if (duk_pcall(m_Ctx, nargs) == DUK_EXEC_ERROR)
{
duk_get_prop_string(m_Ctx, -1, "stack");
m_System->ConsoleLog("%s", duk_safe_to_string(m_Ctx, -1));
duk_pop(m_Ctx);
}
duk_pop(m_Ctx);
}
void RawCMethodCall(void* dukThisHeapPtr, duk_c_function func,
JSDukArgSetupFunc argSetupFunc = nullptr,
@ -56,6 +80,8 @@ public:
JSDukArgSetupFunc argSetupFunc = nullptr,
void* argSetupParam = nullptr, size_t argSetupParamSize = 0);
void RawConsoleInput(const char* code);
private:
static uint64_t Timestamp();
void Cleanup();

View File

@ -11,7 +11,10 @@
CScriptSystem::CScriptSystem(CDebuggerUI *debugger) :
m_Debugger(debugger),
m_NextAppCallbackId(0),
m_AppCallbackCount(0)
m_AppCallbackCount(0),
m_CpuExecCbInfo({}),
m_CpuReadCbInfo({}),
m_CpuWriteCbInfo({})
{
InitDirectories();
@ -158,7 +161,7 @@ bool CScriptSystem::HaveAppCallbacks(JSAppHookID hookId)
{
CGuard guard(m_InstancesCS);
return (m_AppCallbackHooks.count(hookId) > 0 &&
return (hookId < JS_NUM_APP_HOOKS &&
m_AppCallbackHooks[hookId].size() > 0);
}
@ -166,35 +169,27 @@ void CScriptSystem::InvokeAppCallbacks(JSAppHookID hookId, void* env)
{
CGuard guard(m_InstancesCS);
if (m_AppCallbackHooks.count(hookId) == 0 ||
m_AppCallbackHooks[hookId].size() == 0)
{
return;
}
JSAppCallbackList& callbacks = m_AppCallbackHooks[hookId];
bool bNeedSweep = false;
// note: have to copy the map so iterator doesn't break if a callback makes changes
// todo: use reference, queue callback additions/removals?
// JSAppCallbackMap& callbacks = m_AppCallbackHooks[hookId];
JSAppCallbackMap callbacks = m_AppCallbackHooks[hookId];
JSAppCallbackMap::iterator it;
for (it = callbacks.begin(); it != callbacks.end(); it++)
for (JSAppCallback& callback : callbacks)
{
JSAppCallback& callback = it->second;
if (callback.m_Instance->IsStopping())
if (!callback.m_ConditionFunc(&callback, env))
{
continue;
}
callback.m_Instance->RawInvokeAppCallback(callback, env);
CScriptInstance* instance = callback.m_Instance;
if (callback.m_Instance->GetRefCount() == 0)
if (!instance->IsStopping())
{
bNeedSweep = true;
instance->RawInvokeAppCallback(callback, env);
if (instance->GetRefCount() == 0)
{
bNeedSweep = true;
}
}
}
@ -204,6 +199,126 @@ void CScriptSystem::InvokeAppCallbacks(JSAppHookID hookId, void* env)
}
}
void CScriptSystem::UpdateCpuCbListInfo(volatile JSCpuCbListInfo& info, JSAppCallbackList& callbacks)
{
uint32_t minAddrStart = 0;
uint32_t maxAddrEnd = 0;
int numCacheEntries = 0;
bool bCacheExceeded = false;
for (JSAppCallback& callback : callbacks)
{
size_t i;
for (i = 0; i < numCacheEntries; i++)
{
// combine adjacent/overlapping ranges
if ((callback.m_Params.addrStart >= info.rangeCache[i].addrStart &&
callback.m_Params.addrStart <= info.rangeCache[i].addrEnd + 1) ||
(callback.m_Params.addrEnd >= info.rangeCache[i].addrStart - 1 &&
callback.m_Params.addrEnd <= info.rangeCache[i].addrEnd))
{
info.rangeCache[i].addrStart = min(info.rangeCache[i].addrStart, callback.m_Params.addrStart);
info.rangeCache[i].addrEnd = max(info.rangeCache[i].addrEnd, callback.m_Params.addrEnd);
break;
}
}
if (i == numCacheEntries)
{
if (i == JS_CPU_CB_RANGE_CACHE_SIZE)
{
bCacheExceeded = true;
}
else
{
info.rangeCache[i].addrStart = callback.m_Params.addrStart;
info.rangeCache[i].addrEnd = callback.m_Params.addrEnd;
numCacheEntries++;
}
}
if (callback.m_Params.addrStart < minAddrStart)
{
minAddrStart = callback.m_Params.addrStart;
}
if (callback.m_Params.addrEnd > maxAddrEnd)
{
maxAddrEnd = callback.m_Params.addrEnd;
}
}
info.numRangeCacheEntries = numCacheEntries;
info.bRangeCacheExceeded = bCacheExceeded;
info.numCallbacks = callbacks.size();
info.minAddrStart = minAddrStart;
info.maxAddrEnd = maxAddrEnd;
}
void CScriptSystem::RefreshCallbackMaps()
{
for (JSQueuedCallbackRemove& cbRemove : m_CbRemoveQueue)
{
RawRemoveAppCallback(cbRemove.hookId, cbRemove.callbackId);
}
for (JSQueuedCallbackAdd& cbAdd : m_CbAddQueue)
{
RawAddAppCallback(cbAdd.hookId, cbAdd.callback);
}
m_CbRemoveQueue.clear();
m_CbAddQueue.clear();
UpdateCpuCbListInfo(m_CpuExecCbInfo, m_AppCallbackHooks[JS_HOOK_CPU_EXEC]);
UpdateCpuCbListInfo(m_CpuReadCbInfo, m_AppCallbackHooks[JS_HOOK_CPU_READ]);
UpdateCpuCbListInfo(m_CpuWriteCbInfo, m_AppCallbackHooks[JS_HOOK_CPU_WRITE]);
}
JSAppCallbackID CScriptSystem::QueueAddAppCallback(JSAppHookID hookId, JSAppCallback callback)
{
if (hookId >= JS_NUM_APP_HOOKS)
{
return JS_INVALID_CALLBACK;
}
callback.m_CallbackId = m_NextAppCallbackId++;
m_CbAddQueue.push_back({ hookId, callback });
callback.m_Instance->IncRefCount();
return callback.m_CallbackId;
}
void CScriptSystem::QueueRemoveAppCallback(JSAppHookID hookId, JSAppCallbackID callbackId)
{
// todo also remove from addqueue
for (size_t i = 0; i < m_CbRemoveQueue.size(); i++)
{
if (m_CbRemoveQueue[i].hookId == hookId &&
m_CbRemoveQueue[i].callbackId == callbackId)
{
return;
}
}
JSAppCallbackList::iterator it;
for (it = m_AppCallbackHooks[hookId].begin(); it != m_AppCallbackHooks[hookId].end(); it++)
{
if (it->m_CallbackId == callbackId)
{
break;
}
}
if (it == m_AppCallbackHooks[hookId].end())
{
return;
}
m_CbRemoveQueue.push_back({ hookId, callbackId });
it->m_Instance->DecRefCount();
}
void CScriptSystem::DoMouseEvent(JSAppHookID hookId, int x, int y, DWORD uMsg)
{
int button = -1;
@ -394,29 +509,29 @@ bool CScriptSystem::RawRemoveInstance(const char *name)
return true;
}
JSAppCallbackID CScriptSystem::RawAddAppCallback(JSAppHookID hookId, JSAppCallback& callback)
void CScriptSystem::RawAddAppCallback(JSAppHookID hookId, JSAppCallback& callback)
{
if(hookId >= JS_NUM_APP_HOOKS)
{
return JS_INVALID_CALLBACK;
return;
}
callback.m_CallbackId = m_NextAppCallbackId;
m_AppCallbackHooks[hookId][m_NextAppCallbackId] = callback;
m_AppCallbackHooks[hookId].push_back(callback);
m_AppCallbackCount++;
return m_NextAppCallbackId++;
}
bool CScriptSystem::RawRemoveAppCallback(JSAppHookID hookId, JSAppCallbackID callbackId)
void CScriptSystem::RawRemoveAppCallback(JSAppHookID hookId, JSAppCallbackID callbackId)
{
if(m_AppCallbackHooks[hookId].count(callbackId) == 0)
JSAppCallbackList::iterator it;
for (it = m_AppCallbackHooks[hookId].begin(); it != m_AppCallbackHooks[hookId].end(); it++)
{
return false;
if (it->m_CallbackId == callbackId)
{
m_AppCallbackHooks[hookId].erase(it);
m_AppCallbackCount--;
return;
}
}
m_AppCallbackHooks[hookId].erase(callbackId);
m_AppCallbackCount--;
return true;
}
void CScriptSystem::ExecAutorunList()
@ -529,6 +644,7 @@ bool CScriptSystem::ProcessCommand(JSSysCommand& cmd)
return false;
}
RefreshCallbackMaps();
return true;
}

View File

@ -13,11 +13,37 @@
class CScriptSystem
{
typedef std::map<JSInstanceName, CScriptInstance*> JSInstanceMap;
typedef std::map<JSAppCallbackID, JSAppCallback> JSAppCallbackMap;
typedef std::map<JSAppHookID, JSAppCallbackMap> JSAppHookMap;
typedef std::vector<JSAppCallback> JSAppCallbackList;
typedef std::map<JSInstanceName, JSInstanceStatus> JSInstanceStatusMap;
typedef std::vector<JSSysCommand> JSSysCommandQueue;
struct JSQueuedCallbackAdd
{
JSAppHookID hookId;
JSAppCallback callback;
};
struct JSQueuedCallbackRemove
{
JSAppHookID hookId;
JSAppCallbackID callbackId;
};
enum { JS_CPU_CB_RANGE_CACHE_SIZE = 256 };
struct JSCpuCbListInfo
{
size_t numCallbacks;
uint32_t minAddrStart;
uint32_t maxAddrEnd;
size_t numRangeCacheEntries;
bool bRangeCacheExceeded;
struct {
uint32_t addrStart;
uint32_t addrEnd;
} rangeCache[JS_CPU_CB_RANGE_CACHE_SIZE];
};
HANDLE m_hThread;
CriticalSection m_CmdQueueCS;
@ -26,9 +52,17 @@ class CScriptSystem
CriticalSection m_InstancesCS;
JSInstanceMap m_Instances;
JSAppHookMap m_AppCallbackHooks;
JSAppCallbackList m_AppCallbackHooks[JS_NUM_APP_HOOKS];
JSAppCallbackID m_NextAppCallbackId;
size_t m_AppCallbackCount;
std::vector<JSQueuedCallbackRemove> m_CbRemoveQueue;
std::vector<JSQueuedCallbackAdd> m_CbAddQueue;
volatile size_t m_AppCallbackCount;
volatile JSCpuCbListInfo m_CpuExecCbInfo;
volatile JSCpuCbListInfo m_CpuReadCbInfo;
volatile JSCpuCbListInfo m_CpuWriteCbInfo;
CriticalSection m_UIStateCS;
JSInstanceStatusMap m_UIInstanceStatus;
@ -69,10 +103,32 @@ public:
size_t argSetupParamSize = 0);
bool HaveAppCallbacks(JSAppHookID hookId);
void InvokeAppCallbacks(JSAppHookID hookId, void* env = nullptr);
// Note: Unguarded for speed, shouldn't matter
inline bool HaveAppCallbacks() { return m_AppCallbackCount != 0; }
inline bool HaveCpuExecCallbacks(uint32_t address)
{
return HaveCpuCallbacks(m_CpuExecCbInfo, m_AppCallbackHooks[JS_HOOK_CPU_EXEC], address);
}
inline bool HaveCpuReadCallbacks(uint32_t address)
{
return HaveCpuCallbacks(m_CpuReadCbInfo, m_AppCallbackHooks[JS_HOOK_CPU_READ], address);
}
inline bool HaveCpuWriteCallbacks(uint32_t address)
{
return HaveCpuCallbacks(m_CpuWriteCbInfo, m_AppCallbackHooks[JS_HOOK_CPU_WRITE], address);
}
static void UpdateCpuCbListInfo(volatile JSCpuCbListInfo& info, JSAppCallbackList& callbacks);
void DoMouseEvent(JSAppHookID hookId, int x, int y, DWORD uMsg = (DWORD)-1);
JSAppCallbackID RawAddAppCallback(JSAppHookID hookId, JSAppCallback& callback);
bool RawRemoveAppCallback(JSAppHookID hookId, JSAppCallbackID callbackId);
JSAppCallbackID QueueAddAppCallback(JSAppHookID hookId, JSAppCallback callback);
void QueueRemoveAppCallback(JSAppHookID hookId, JSAppCallbackID callbackId);
void InvokeAppCallbacks(JSAppHookID hookId, void* env = nullptr);
void ExecAutorunList();
std::set<std::string>& AutorunList();
@ -80,6 +136,41 @@ public:
void SaveAutorunList();
private:
inline bool HaveCpuCallbacks(volatile JSCpuCbListInfo& info, JSAppCallbackList& callbacks, uint32_t address)
{
if (info.numCallbacks == 0 || address < info.minAddrStart || address > info.maxAddrEnd)
{
return false;
}
if (!info.bRangeCacheExceeded)
{
for (size_t i = 0; i < info.numRangeCacheEntries; i++)
{
if (address >= info.rangeCache[i].addrStart &&
address <= info.rangeCache[i].addrEnd)
{
return true;
}
}
return false;
}
CGuard guard(m_InstancesCS);
for (JSAppCallback& callback : callbacks)
{
if (address >= callback.m_Params.addrStart &&
address <= callback.m_Params.addrEnd)
{
return true;
}
}
return false;
}
void InitDirectories();
void PostCommand(JSSysCommandID id, stdstr paramA = "", stdstr paramB = "", void* paramC = nullptr);
@ -99,5 +190,9 @@ private:
bool RawRemoveInstance(const char* key);
void RawAddAppCallback(JSAppHookID hookId, JSAppCallback& callback);
void RawRemoveAppCallback(JSAppHookID hookId, JSAppCallbackID callbackId);
void RefreshCallbackMaps();
static stdstr FixStringReturns(const char* str);
};

View File

@ -14,7 +14,9 @@ enum
enum JSAppHookID
{
JS_HOOK_CPUSTEP,
JS_HOOK_CPU_EXEC,
JS_HOOK_CPU_READ,
JS_HOOK_CPU_WRITE,
JS_HOOK_PIFREAD,
JS_HOOK_PIDMA,
JS_HOOK_GFXUPDATE,
@ -90,6 +92,8 @@ struct JSAppCallback
};
} m_Params;
static bool CbCondTrue(JSAppCallback*, void*) { return true; }
JSAppCallback(CScriptInstance* instance, void* dukFuncHeapPtr,
JSAppCallbackCondFunc condFunc = nullptr,
JSDukArgSetupFunc argSetupFunc = nullptr,
@ -101,6 +105,11 @@ struct JSAppCallback
m_CleanupFunc(cleanupFunc),
m_CallbackId(JS_INVALID_CALLBACK)
{
if (m_ConditionFunc == nullptr)
{
m_ConditionFunc = CbCondTrue;
}
m_Params = {};
}
@ -112,6 +121,11 @@ struct JSAppCallback
m_CleanupFunc(nullptr),
m_CallbackId(JS_INVALID_CALLBACK)
{
if (m_ConditionFunc == nullptr)
{
m_ConditionFunc = CbCondTrue;
}
m_Params = {};
}
};