* [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:
parent
921c12e4d0
commit
9a287a53ee
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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 = {};
|
||||
}
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue