From cd735aec716b93a189eb178408f8213418576b33 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 19 Jan 2007 08:22:44 +0000 Subject: [PATCH] finished massive reorganization - IPluginFunction is now part of the VM, NOT the plugin system! This is how it should have been in the first place... --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40332 --- core/msvc8/sourcemod_mm.vcproj | 30 ++-- core/systems/ForwardSys.cpp | 17 +- core/systems/ForwardSys.h | 2 +- core/systems/PluginSys.cpp | 142 +-------------- core/systems/PluginSys.h | 9 - core/vm/sp_vm_basecontext.cpp | 129 +++++++++++++ core/vm/sp_vm_basecontext.h | 15 ++ core/vm/sp_vm_engine.cpp | 39 ++++ core/vm/sp_vm_engine.h | 140 ++++++++------- .../CFunction.cpp => vm/sp_vm_function.cpp} | 36 ++-- core/vm/sp_vm_function.h | 55 ++++++ public/IForwardSys.h | 6 +- public/IPluginFunction.h | 153 ---------------- public/IPluginSys.h | 18 -- public/sourcepawn/sp_vm_api.h | 169 ++++++++++++++++++ public/sourcepawn/sp_vm_types.h | 1 + 16 files changed, 526 insertions(+), 435 deletions(-) rename core/{systems/CFunction.cpp => vm/sp_vm_function.cpp} (76%) create mode 100644 core/vm/sp_vm_function.h delete mode 100644 public/IPluginFunction.h diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index b40d716c..a1f60a33 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -341,10 +341,6 @@ RelativePath="..\..\public\ILibrarySys.h" > - - @@ -372,10 +368,6 @@ - - @@ -408,10 +400,6 @@ - - @@ -456,6 +444,10 @@ RelativePath="..\vm\sp_vm_engine.h" > + + + + diff --git a/core/systems/ForwardSys.cpp b/core/systems/ForwardSys.cpp index 6011cdcc..9465840a 100644 --- a/core/systems/ForwardSys.cpp +++ b/core/systems/ForwardSys.cpp @@ -71,7 +71,7 @@ void CForwardManager::OnPluginLoaded(IPlugin *plugin) for (iter=m_managed.begin(); iter!=m_managed.end(); iter++) { fwd = (*iter); - IPluginFunction *pFunc = plugin->GetFunctionByName(fwd->GetForwardName()); + IPluginFunction *pFunc = plugin->GetBaseContext()->GetFunctionByName(fwd->GetForwardName()); if (pFunc) { fwd->AddFunction(pFunc); @@ -256,7 +256,8 @@ int CForward::Execute(cell_t *result, IForwardFilter *filter) for (iter=m_functions.begin(); iter!=m_functions.end(); iter++) { func = (*iter); - if (func->GetParentPlugin()->GetStatus() == Plugin_Paused) + /* Ugh... */ + if (!func->GetParentContext()->IsRunnable()) { continue; } @@ -565,15 +566,10 @@ void CForward::Cancel() m_errstate = SP_ERROR_NONE; } -bool CForward::AddFunction(sp_context_t *ctx, funcid_t index) +bool CForward::AddFunction(IPluginContext *pContext, funcid_t index) { - IPlugin *pPlugin = g_PluginSys.FindPluginByContext(ctx); - if (!pPlugin) - { - return false; - } + IPluginFunction *pFunc = pContext->GetFunctionById(index); - IPluginFunction *pFunc = pPlugin->GetFunctionById(index); if (!pFunc) { return false; @@ -614,10 +610,11 @@ unsigned int CForward::RemoveFunctionsOfPlugin(IPlugin *plugin) FuncIter iter; IPluginFunction *func; unsigned int removed = 0; + IPluginContext *pContext = plugin->GetBaseContext(); for (iter=m_functions.begin(); iter!=m_functions.end();) { func = (*iter); - if (func->GetParentPlugin() == plugin) + if (func->GetParentContext() == pContext) { iter = m_functions.erase(iter); removed++; diff --git a/core/systems/ForwardSys.h b/core/systems/ForwardSys.h index 4748e9fb..617aaf03 100644 --- a/core/systems/ForwardSys.h +++ b/core/systems/ForwardSys.h @@ -50,7 +50,7 @@ public: //IChangeableForward virtual bool RemoveFunction(IPluginFunction *func); virtual unsigned int RemoveFunctionsOfPlugin(IPlugin *plugin); virtual bool AddFunction(IPluginFunction *func); - virtual bool AddFunction(sp_context_t *ctx, funcid_t index); + virtual bool AddFunction(IPluginContext *ctx, funcid_t index); public: static CForward *CreateForward(const char *name, ExecType et, diff --git a/core/systems/PluginSys.cpp b/core/systems/PluginSys.cpp index 6528113e..fd82b260 100644 --- a/core/systems/PluginSys.cpp +++ b/core/systems/PluginSys.cpp @@ -23,9 +23,6 @@ CPlugin::CPlugin(const char *file) m_status = Plugin_Uncompiled; m_serial = ++MySerial; m_plugin = NULL; - m_funcsnum = 0; - m_priv_funcs = NULL; - m_pub_funcs = NULL; m_errormsg[256] = '\0'; snprintf(m_filename, sizeof(m_filename), "%s", file); m_handle = 0; @@ -60,26 +57,6 @@ CPlugin::~CPlugin() m_ctx.co = NULL; } - if (m_pub_funcs) - { - for (uint32_t i=0; iinfo.publics_num; i++) - { - g_PluginSys.ReleaseFunctionToPool(m_pub_funcs[i]); - } - delete [] m_pub_funcs; - m_pub_funcs = NULL; - } - - if (m_priv_funcs) - { - for (unsigned int i=0; iFreeFromMemory(m_plugin); @@ -190,30 +167,9 @@ bool CPlugin::FinishMyCompile(char *error, size_t maxlength) } m_ctx.base = new BaseContext(m_ctx.ctx); + m_ctx.base->SetRunnable(false); m_ctx.ctx->user[SM_CONTEXTVAR_MYSELF] = (void *)this; - m_funcsnum = m_ctx.vm->FunctionCount(m_ctx.ctx); - - /** - * Note: Since the m_plugin member will never change, - * it is safe to assume the function count will never change - */ - if (m_funcsnum && m_priv_funcs == NULL) - { - m_priv_funcs = new CFunction *[m_funcsnum]; - memset(m_priv_funcs, 0, sizeof(CFunction *) * m_funcsnum); - } else { - m_priv_funcs = NULL; - } - - if (m_plugin->info.publics_num && m_pub_funcs == NULL) - { - m_pub_funcs = new CFunction *[m_plugin->info.publics_num]; - memset(m_pub_funcs, 0, sizeof(CFunction *) * m_plugin->info.publics_num); - } else { - m_pub_funcs = NULL; - } - m_status = Plugin_Created; m_ctx.co = NULL; @@ -230,67 +186,11 @@ void CPlugin::SetErrorState(PluginStatus status, const char *error_fmt, ...) va_start(ap, error_fmt); vsnprintf(m_errormsg, sizeof(m_errormsg), error_fmt, ap); va_end(ap); -} -IPluginFunction *CPlugin::GetFunctionById(funcid_t func_id) -{ - CFunction *pFunc = NULL; - funcid_t save = func_id; - - if (func_id & 1) + if (m_ctx.base) { - func_id >>= 1; - if (func_id >= m_plugin->info.publics_num) - { - return NULL; - } - pFunc = m_pub_funcs[func_id]; - if (!pFunc) - { - pFunc = g_PluginSys.GetFunctionFromPool(save, this); - m_pub_funcs[func_id] = pFunc; - } - } else { - func_id >>= 1; - unsigned int index; - if (!g_pVM->FunctionLookup(m_ctx.ctx, func_id, &index)) - { - return NULL; - } - pFunc = m_priv_funcs[func_id]; - if (!pFunc) - { - pFunc = g_PluginSys.GetFunctionFromPool(save, this); - m_priv_funcs[func_id] = pFunc; - } + m_ctx.base->SetRunnable(false); } - - return pFunc; -} - -IPluginFunction *CPlugin::GetFunctionByName(const char *public_name) -{ - uint32_t index; - IPluginContext *base = m_ctx.base; - - if (base->FindPublicByName(public_name, &index) != SP_ERROR_NONE) - { - return NULL; - } - - CFunction *pFunc = m_pub_funcs[index]; - if (!pFunc) - { - sp_public_t *pub = NULL; - base->GetPublicByIndex(index, &pub); - if (pub) - { - pFunc = g_PluginSys.GetFunctionFromPool(pub->funcid, this); - m_pub_funcs[index] = pFunc; - } - } - - return pFunc; } void CPlugin::UpdateInfo() @@ -338,7 +238,7 @@ void CPlugin::Call_OnPluginInit() m_status = Plugin_Running; cell_t result; - IPluginFunction *pFunction = GetFunctionByName("OnPluginInit"); + IPluginFunction *pFunction = m_ctx.base->GetFunctionByName("OnPluginInit"); if (!pFunction) { return; @@ -356,7 +256,7 @@ void CPlugin::Call_OnPluginUnload() } cell_t result; - IPluginFunction *pFunction = GetFunctionByName("OnPluginUnload"); + IPluginFunction *pFunction = m_ctx.base->GetFunctionByName("OnPluginUnload"); if (!pFunction) { return; @@ -373,10 +273,11 @@ bool CPlugin::Call_AskPluginLoad(char *error, size_t maxlength) } m_status = Plugin_Loaded; + m_ctx.base->SetRunnable(true); int err; cell_t result; - IPluginFunction *pFunction = GetFunctionByName("AskPluginLoad"); + IPluginFunction *pFunction = m_ctx.base->GetFunctionByName("AskPluginLoad"); if (!pFunction) { @@ -389,13 +290,11 @@ bool CPlugin::Call_AskPluginLoad(char *error, size_t maxlength) pFunction->PushCell(maxlength); if ((err=pFunction->Execute(&result)) != SP_ERROR_NONE) { - m_status = Plugin_Failed; return false; } if (!result || m_status != Plugin_Loaded) { - m_status = Plugin_Failed; return false; } @@ -463,7 +362,7 @@ bool CPlugin::SetPauseState(bool paused) m_status = (paused) ? Plugin_Paused : Plugin_Running; - IPluginFunction *pFunction = GetFunctionByName("OnPluginPauseChange"); + IPluginFunction *pFunction = m_ctx.base->GetFunctionByName("OnPluginPauseChange"); if (pFunction) { cell_t result; @@ -756,7 +655,6 @@ bool CPluginManager::_LoadPlugin(CPlugin **_plugin, const char *path, bool debug snprintf(error, err_max, "Unable to set JIT option (key \"%s\") (value \"%s\")", key, val); } pPlugin->CancelMyCompile(); - pPlugin->m_status = Plugin_Failed; co = NULL; break; } @@ -932,7 +830,6 @@ bool CPluginManager::LoadOrRequireExtensions(CPlugin *pPlugin, unsigned int pass { snprintf(error, maxlength, "Required extension \"%s\" file(\"%s\") not running", name, file); } - pPlugin->m_status = Plugin_Failed; return false; } else { g_Extensions.BindChildPlugin(pExt, pPlugin); @@ -1091,29 +988,6 @@ void CPluginManager::ReleaseIterator(CPluginIterator *iter) m_iters.push(iter); } -void CPluginManager::ReleaseFunctionToPool(CFunction *func) -{ - if (!func) - { - return; - } - func->Cancel(); - m_funcpool.push(func); -} - -CFunction *CPluginManager::GetFunctionFromPool(funcid_t f, CPlugin *plugin) -{ - if (m_funcpool.empty()) - { - return new CFunction(f, plugin); - } else { - CFunction *func = m_funcpool.front(); - m_funcpool.pop(); - func->Set(f, plugin); - return func; - } -} - bool CPluginManager::TestAliasMatch(const char *alias, const char *localpath) { /* As an optimization, we do not call strlen, but compute the length in the first pass */ diff --git a/core/systems/PluginSys.h b/core/systems/PluginSys.h index 5e804503..fa4930eb 100644 --- a/core/systems/PluginSys.h +++ b/core/systems/PluginSys.h @@ -8,7 +8,6 @@ #include #include "sm_globals.h" #include "vm/sp_vm_basecontext.h" -#include "CFunction.h" #include "PluginInfoDatabase.h" #include "sm_trie.h" #include "sourcemod.h" @@ -93,8 +92,6 @@ public: virtual bool SetPauseState(bool paused); virtual unsigned int GetSerial() const; virtual const sp_plugin_t *GetPluginStructure() const; - virtual IPluginFunction *GetFunctionByName(const char *public_name); - virtual IPluginFunction *GetFunctionById(funcid_t func_id); virtual IdentityToken_t *GetIdentity() const; public: /** @@ -174,9 +171,6 @@ private: unsigned int m_serial; sm_plugininfo_t m_info; sp_plugin_t *m_plugin; - unsigned int m_funcsnum; - CFunction **m_priv_funcs; - CFunction **m_pub_funcs; char m_errormsg[256]; time_t m_LastAccess; IdentityToken_t *m_ident; @@ -312,8 +306,6 @@ protected: * Caching internal objects */ void ReleaseIterator(CPluginIterator *iter); - CFunction *GetFunctionFromPool(funcid_t f, CPlugin *plugin); - void ReleaseFunctionToPool(CFunction *func); inline IdentityToken_t *GetIdentity() { return m_MyIdent; @@ -323,7 +315,6 @@ private: List m_plugins; List m_natives; CStack m_iters; - CStack m_funcpool; CPluginInfoDatabase m_PluginInfo; Trie *m_LoadLookup; bool m_AllPluginsLoaded; diff --git a/core/vm/sp_vm_basecontext.cpp b/core/vm/sp_vm_basecontext.cpp index fecfe427..96b6a7fe 100644 --- a/core/vm/sp_vm_basecontext.cpp +++ b/core/vm/sp_vm_basecontext.cpp @@ -27,6 +27,60 @@ BaseContext::BaseContext(sp_context_t *_ctx) ctx->dbreak = GlobalDebugBreak; m_InExec = false; m_CustomMsg = false; + m_Runnable = true; + m_funcsnum = ctx->vmbase->FunctionCount(ctx); + m_priv_funcs = NULL; + m_pub_funcs = NULL; + + /** + * Note: Since the m_plugin member will never change, + * it is safe to assume the function count will never change + */ + if (m_funcsnum && m_priv_funcs == NULL) + { + m_priv_funcs = new CFunction *[m_funcsnum]; + memset(m_priv_funcs, 0, sizeof(CFunction *) * m_funcsnum); + } else { + m_priv_funcs = NULL; + } + + if (ctx->plugin->info.publics_num && m_pub_funcs == NULL) + { + m_pub_funcs = new CFunction *[ctx->plugin->info.publics_num]; + memset(m_pub_funcs, 0, sizeof(CFunction *) * ctx->plugin->info.publics_num); + } else { + m_pub_funcs = NULL; + } +} + +void BaseContext::FlushFunctionCache() +{ + if (m_pub_funcs) + { + for (uint32_t i=0; iplugin->info.publics_num; i++) + { + delete m_pub_funcs[i]; + m_pub_funcs[i] = NULL; + } + } + + if (m_priv_funcs) + { + for (unsigned int i=0; icontext = this; + ctx->dbreak = GlobalDebugBreak; + FlushFunctionCache(); } IVirtualMachine *BaseContext::GetVirtualMachine() @@ -73,6 +130,11 @@ IPluginDebugInfo *BaseContext::GetDebugInfo() int BaseContext::Execute(funcid_t funcid, cell_t *result) { + if (!m_Runnable) + { + return SP_ERROR_NOT_RUNNABLE; + } + IVirtualMachine *vm = (IVirtualMachine *)ctx->vmbase; uint32_t pushcount = ctx->pushcount; @@ -794,6 +856,63 @@ int BaseContext::LookupLine(ucell_t addr, uint32_t *line) return SP_ERROR_NONE; } +IPluginFunction *BaseContext::GetFunctionById(funcid_t func_id) +{ + CFunction *pFunc = NULL; + funcid_t save = func_id; + + if (func_id & 1) + { + func_id >>= 1; + if (func_id >= ctx->plugin->info.publics_num) + { + return NULL; + } + pFunc = m_pub_funcs[func_id]; + if (!pFunc) + { + m_pub_funcs[func_id] = new CFunction(save, this); + } + } else { + func_id >>= 1; + unsigned int index; + if (!g_pVM->FunctionLookup(ctx, func_id, &index)) + { + return NULL; + } + pFunc = m_priv_funcs[func_id]; + if (!pFunc) + { + m_priv_funcs[func_id] = new CFunction(save, this); + } + } + + return pFunc; +} + +IPluginFunction *BaseContext::GetFunctionByName(const char *public_name) +{ + uint32_t index; + + if (FindPublicByName(public_name, &index) != SP_ERROR_NONE) + { + return NULL; + } + + CFunction *pFunc = m_pub_funcs[index]; + if (!pFunc) + { + sp_public_t *pub = NULL; + GetPublicByIndex(index, &pub); + if (pub) + { + m_pub_funcs[index] = new CFunction(pub->funcid, this); + } + } + + return pFunc; +} + #if defined SOURCEMOD_BUILD SourceMod::IdentityToken_t *BaseContext::GetIdentity() { @@ -804,4 +923,14 @@ void BaseContext::SetIdentity(SourceMod::IdentityToken_t *token) { m_pToken = token; } + +bool BaseContext::IsRunnable() +{ + return m_Runnable; +} + +void BaseContext::SetRunnable(bool runnable) +{ + m_Runnable = runnable; +} #endif diff --git a/core/vm/sp_vm_basecontext.h b/core/vm/sp_vm_basecontext.h index f755335e..d2625686 100644 --- a/core/vm/sp_vm_basecontext.h +++ b/core/vm/sp_vm_basecontext.h @@ -2,6 +2,11 @@ #define _INCLUDE_SOURCEPAWN_BASECONTEXT_H_ #include "sp_vm_api.h" +#include "sp_vm_function.h" + +/** + * :TODO: Make functions allocate as a lump instead of individual allocations! + */ namespace SourcePawn { @@ -11,6 +16,7 @@ namespace SourcePawn { public: BaseContext(sp_context_t *ctx); + ~BaseContext(); public: //IPluginContext IVirtualMachine *GetVirtualMachine(); sp_context_t *GetContext(); @@ -44,9 +50,13 @@ namespace SourcePawn virtual int Execute(funcid_t funcid, cell_t *result); virtual void ThrowNativeErrorEx(int error, const char *msg, ...); virtual cell_t ThrowNativeError(const char *msg, ...); + virtual IPluginFunction *GetFunctionByName(const char *public_name); + virtual IPluginFunction *GetFunctionById(funcid_t func_id); #if defined SOURCEMOD_BUILD virtual SourceMod::IdentityToken_t *GetIdentity(); void SetIdentity(SourceMod::IdentityToken_t *token); + bool IsRunnable(); + void SetRunnable(bool runnable); #endif public: //IPluginDebugInfo virtual int LookupFile(ucell_t addr, const char **filename); @@ -56,6 +66,7 @@ namespace SourcePawn void SetContext(sp_context_t *_ctx); private: void SetErrorMessage(const char *msg, va_list ap); + void FlushFunctionCache(); private: sp_context_t *ctx; #if defined SOURCEMOD_BUILD @@ -64,6 +75,10 @@ namespace SourcePawn char m_MsgCache[1024]; bool m_CustomMsg; bool m_InExec; + bool m_Runnable; + unsigned int m_funcsnum; + CFunction **m_priv_funcs; + CFunction **m_pub_funcs; }; }; diff --git a/core/vm/sp_vm_engine.cpp b/core/vm/sp_vm_engine.cpp index cb6cf700..e39e0e52 100644 --- a/core/vm/sp_vm_engine.cpp +++ b/core/vm/sp_vm_engine.cpp @@ -53,6 +53,9 @@ SourcePawnEngine::SourcePawnEngine() m_CallStack = NULL; m_FreedCalls = NULL; m_CurChain = 0; +#if 0 + m_pFreeFuncs = NULL; +#endif } SourcePawnEngine::~SourcePawnEngine() @@ -66,6 +69,16 @@ SourcePawnEngine::~SourcePawnEngine() delete m_FreedCalls; m_FreedCalls = pTemp; } + +#if 0 + CFunction *pNext; + while (m_pFreeFuncs) + { + pNext = m_pFreeFuncs->m_pNext; + delete m_pFreeFuncs; + m_pFreeFuncs = pNext; + } +#endif } void *SourcePawnEngine::ExecAlloc(size_t size) @@ -356,6 +369,32 @@ int SourcePawnEngine::FreeFromMemory(sp_plugin_t *plugin) return SP_ERROR_NONE; } +#if 0 +void SourcePawnEngine::ReleaseFunctionToPool(CFunction *func) +{ + if (!func) + { + return; + } + func->Cancel(); + func->m_pNext = m_pFreeFuncs; + m_pFreeFuncs = func; +} + +CFunction *SourcePawnEngine::GetFunctionFromPool(funcid_t f, IPluginContext *plugin) +{ + if (!m_pFreeFuncs) + { + return new CFunction(f, plugin); + } else { + CFunction *pFunc = m_pFreeFuncs; + m_pFreeFuncs = m_pFreeFuncs->m_pNext; + pFunc->Set(f, plugin); + return pFunc; + } +} +#endif + IDebugListener *SourcePawnEngine::SetDebugListener(IDebugListener *pListener) { IDebugListener *old = m_pDebugHook; diff --git a/core/vm/sp_vm_engine.h b/core/vm/sp_vm_engine.h index ca0ac7f3..4ad0f715 100644 --- a/core/vm/sp_vm_engine.h +++ b/core/vm/sp_vm_engine.h @@ -2,83 +2,85 @@ #define _INCLUDE_SOURCEPAWN_VM_ENGINE_H_ #include "sp_vm_api.h" +#include "sp_vm_function.h" -namespace SourcePawn +struct TracedCall { - struct TracedCall - { - uint32_t cip; - uint32_t frm; - sp_context_t *ctx; - TracedCall *next; - unsigned int chain; - }; + uint32_t cip; + uint32_t frm; + sp_context_t *ctx; + TracedCall *next; + unsigned int chain; +}; - class CContextTrace : public IContextTrace - { - public: - CContextTrace(TracedCall *pStart, int error, const char *msg, uint32_t native); - public: - virtual int GetErrorCode(); - virtual const char *GetErrorString(); - virtual bool DebugInfoAvailable(); - virtual const char *GetCustomErrorString(); - virtual bool GetTraceInfo(CallStackInfo *trace); - virtual void ResetTrace(); - virtual const char *GetLastNative(uint32_t *index); - private: - TracedCall *m_pStart; - TracedCall *m_pIterator; - const char *m_pMsg; - int m_Error; - uint32_t m_Native; - }; +class CContextTrace : public IContextTrace +{ +public: + CContextTrace(TracedCall *pStart, int error, const char *msg, uint32_t native); +public: + virtual int GetErrorCode(); + virtual const char *GetErrorString(); + virtual bool DebugInfoAvailable(); + virtual const char *GetCustomErrorString(); + virtual bool GetTraceInfo(CallStackInfo *trace); + virtual void ResetTrace(); + virtual const char *GetLastNative(uint32_t *index); +private: + TracedCall *m_pStart; + TracedCall *m_pIterator; + const char *m_pMsg; + int m_Error; + uint32_t m_Native; +}; - class SourcePawnEngine : public ISourcePawnEngine - { - public: - SourcePawnEngine(); - ~SourcePawnEngine(); - public: //ISourcePawnEngine - sp_plugin_t *LoadFromFilePointer(FILE *fp, int *err); - sp_plugin_t *LoadFromMemory(void *base, sp_plugin_t *plugin, int *err); - int FreeFromMemory(sp_plugin_t *plugin); - IPluginContext *CreateBaseContext(sp_context_t *ctx); - void FreeBaseContext(IPluginContext *ctx); - void *BaseAlloc(size_t size); - void BaseFree(void *memory); - void *ExecAlloc(size_t size); - void ExecFree(void *address); - IDebugListener *SetDebugListener(IDebugListener *pListener); - unsigned int GetContextCallCount(); - public: //Debugger Stuff - /** - * @brief Pushes a context onto the top of the call tracer. - * - * @param ctx Plugin context. - */ - void PushTracer(sp_context_t *ctx); +class SourcePawnEngine : public ISourcePawnEngine +{ +public: + SourcePawnEngine(); + ~SourcePawnEngine(); +public: //ISourcePawnEngine + sp_plugin_t *LoadFromFilePointer(FILE *fp, int *err); + sp_plugin_t *LoadFromMemory(void *base, sp_plugin_t *plugin, int *err); + int FreeFromMemory(sp_plugin_t *plugin); + IPluginContext *CreateBaseContext(sp_context_t *ctx); + void FreeBaseContext(IPluginContext *ctx); + void *BaseAlloc(size_t size); + void BaseFree(void *memory); + void *ExecAlloc(size_t size); + void ExecFree(void *address); + IDebugListener *SetDebugListener(IDebugListener *pListener); + unsigned int GetContextCallCount(); +public: //Debugger Stuff + /** + * @brief Pushes a context onto the top of the call tracer. + * + * @param ctx Plugin context. + */ + void PushTracer(sp_context_t *ctx); - /** - * @brief Pops a plugin off the call tracer. - */ - void PopTracer(int error, const char *msg); + /** + * @brief Pops a plugin off the call tracer. + */ + void PopTracer(int error, const char *msg); - /** - * @brief Runs tracer from a debug break. - */ - void RunTracer(sp_context_t *ctx, uint32_t frame, uint32_t codeip); - private: - TracedCall *MakeTracedCall(bool new_chain); - void FreeTracedCall(TracedCall *pCall); - private: - IDebugListener *m_pDebugHook; - TracedCall *m_FreedCalls; - TracedCall *m_CallStack; - unsigned int m_CurChain; - }; + /** + * @brief Runs tracer from a debug break. + */ + void RunTracer(sp_context_t *ctx, uint32_t frame, uint32_t codeip); +public: //Plugin function stuff + CFunction *GetFunctionFromPool(funcid_t f, IPluginContext *plugin); + void ReleaseFunctionToPool(CFunction *func); +private: + TracedCall *MakeTracedCall(bool new_chain); + void FreeTracedCall(TracedCall *pCall); +private: + IDebugListener *m_pDebugHook; + TracedCall *m_FreedCalls; + TracedCall *m_CallStack; + unsigned int m_CurChain; + //CFunction *m_pFreeFuncs; }; #endif //_INCLUDE_SOURCEPAWN_VM_ENGINE_H_ diff --git a/core/systems/CFunction.cpp b/core/vm/sp_vm_function.cpp similarity index 76% rename from core/systems/CFunction.cpp rename to core/vm/sp_vm_function.cpp index 6f123518..523a85a3 100644 --- a/core/systems/CFunction.cpp +++ b/core/vm/sp_vm_function.cpp @@ -5,33 +5,31 @@ * FUNCTION CALLING * ********************/ -void CFunction::Set(funcid_t funcid, CPlugin *plugin) +void CFunction::Set(funcid_t funcid, IPluginContext *plugin) { m_funcid = funcid; - m_pPlugin = plugin; + m_pContext = plugin; m_curparam = 0; m_errorstate = SP_ERROR_NONE; } int CFunction::CallFunction(const cell_t *params, unsigned int num_params, cell_t *result) { - IPluginContext *ctx = m_pPlugin->m_ctx.base; - while (num_params--) { - ctx->PushCell(params[num_params]); + m_pContext->PushCell(params[num_params]); } - return ctx->Execute(m_funcid, result); + return m_pContext->Execute(m_funcid, result); } -IPlugin *CFunction::GetParentPlugin() +IPluginContext *CFunction::GetParentContext() { - return m_pPlugin; + return m_pContext; } -CFunction::CFunction(funcid_t funcid, CPlugin *plugin) : - m_funcid(funcid), m_pPlugin(plugin), m_curparam(0), +CFunction::CFunction(funcid_t funcid, IPluginContext *plugin) : + m_funcid(funcid), m_pContext(plugin), m_curparam(0), m_errorstate(SP_ERROR_NONE) { } @@ -79,11 +77,10 @@ int CFunction::PushArray(cell_t *inarray, unsigned int cells, cell_t **phys_addr return SetError(SP_ERROR_PARAMS_MAX); } - IPluginContext *ctx = m_pPlugin->m_ctx.base; ParamInfo *info = &m_info[m_curparam]; int err; - if ((err=ctx->HeapAlloc(cells, &info->local_addr, &info->phys_addr)) != SP_ERROR_NONE) + if ((err=m_pContext->HeapAlloc(cells, &info->local_addr, &info->phys_addr)) != SP_ERROR_NONE) { return SetError(err); } @@ -127,12 +124,11 @@ int CFunction::_PushString(const char *string, int sz_flags, int cp_flags, size_ return SetError(SP_ERROR_PARAMS_MAX); } - IPluginContext *base = m_pPlugin->m_ctx.base; ParamInfo *info = &m_info[m_curparam]; size_t cells = (len + sizeof(cell_t) - 1) / sizeof(cell_t); int err; - if ((err=base->HeapAlloc(cells, &info->local_addr, &info->phys_addr)) != SP_ERROR_NONE) + if ((err=m_pContext->HeapAlloc(cells, &info->local_addr, &info->phys_addr)) != SP_ERROR_NONE) { return SetError(err); } @@ -148,12 +144,12 @@ int CFunction::_PushString(const char *string, int sz_flags, int cp_flags, size_ if (sz_flags & SM_PARAM_STRING_UTF8) { - if ((err=base->StringToLocalUTF8(info->local_addr, len, string, NULL)) != SP_ERROR_NONE) + if ((err=m_pContext->StringToLocalUTF8(info->local_addr, len, string, NULL)) != SP_ERROR_NONE) { return SetError(err); } } else { - if ((err=base->StringToLocal(info->local_addr, len, string)) != SP_ERROR_NONE) + if ((err=m_pContext->StringToLocal(info->local_addr, len, string)) != SP_ERROR_NONE) { return SetError(err); } @@ -174,13 +170,11 @@ void CFunction::Cancel() return; } - IPluginContext *base = m_pPlugin->m_ctx.base; - while (m_curparam--) { if (m_info[m_curparam].marked) { - base->HeapRelease(m_info[m_curparam].local_addr); + m_pContext->HeapRelease(m_info[m_curparam].local_addr); m_info[m_curparam].marked = false; } } @@ -217,8 +211,6 @@ int CFunction::Execute(cell_t *result) docopies = false; } - IPluginContext *base = m_pPlugin->m_ctx.base; - while (numparams--) { if (!temp_info[numparams].marked) @@ -239,7 +231,7 @@ int CFunction::Execute(cell_t *result) } } } - base->HeapPop(temp_info[numparams].local_addr); + m_pContext->HeapPop(temp_info[numparams].local_addr); temp_info[numparams].marked = false; } diff --git a/core/vm/sp_vm_function.h b/core/vm/sp_vm_function.h new file mode 100644 index 00000000..ad688c1c --- /dev/null +++ b/core/vm/sp_vm_function.h @@ -0,0 +1,55 @@ +#ifndef _INCLUDE_SOURCEMOD_BASEFUNCTION_H_ +#define _INCLUDE_SOURCEMOD_BASEFUNCTION_H_ + +#include "sm_globals.h" + +struct ParamInfo +{ + int flags; /* Copy-back flags */ + bool marked; /* Whether this is marked as being used */ + cell_t local_addr; /* Local address to free */ + cell_t *phys_addr; /* Physical address of our copy */ + cell_t *orig_addr; /* Original address to copy back to */ + ucell_t size; /* Size of array in bytes */ +}; + +class CPlugin; + +class CFunction : public IPluginFunction +{ + friend class SourcePawnEngine; +public: + CFunction(funcid_t funcid, IPluginContext *pContext); +public: + virtual int PushCell(cell_t cell); + virtual int PushCellByRef(cell_t *cell, int flags); + virtual int PushFloat(float number); + virtual int PushFloatByRef(float *number, int flags); + virtual int PushArray(cell_t *inarray, unsigned int cells, cell_t **phys_addr, int copyback); + virtual int PushString(const char *string); + virtual int PushStringEx(char *buffer, size_t length, int sz_flags, int cp_flags); + virtual cell_t *GetAddressOfPushedParam(unsigned int param); + virtual int Execute(cell_t *result); + virtual void Cancel(); + virtual int CallFunction(const cell_t *params, unsigned int num_params, cell_t *result); + virtual IPluginContext *GetParentContext(); +public: + void Set(funcid_t funcid, IPluginContext *plugin); +private: + int _PushString(const char *string, int sz_flags, int cp_flags, size_t len); + inline int SetError(int err) + { + m_errorstate = err; + return err; + } +private: + funcid_t m_funcid; + IPluginContext *m_pContext; + cell_t m_params[SP_MAX_EXEC_PARAMS]; + ParamInfo m_info[SP_MAX_EXEC_PARAMS]; + unsigned int m_curparam; + int m_errorstate; + CFunction *m_pNext; +}; + +#endif //_INCLUDE_SOURCEMOD_BASEFUNCTION_H_ diff --git a/public/IForwardSys.h b/public/IForwardSys.h index d4732899..bd023adc 100644 --- a/public/IForwardSys.h +++ b/public/IForwardSys.h @@ -3,7 +3,9 @@ #include #include -#include +#include + +using namespace SourcePawn; #define SMINTERFACE_FORWARDMANAGER_NAME "IForwardManager" #define SMINTERFACE_FORWARDMANAGER_VERSION 1 @@ -190,7 +192,7 @@ namespace SourceMod * @param funcid Function id to add. * @return True on success, otherwise false. */ - virtual bool AddFunction(sp_context_t *ctx, funcid_t index) =0; + virtual bool AddFunction(IPluginContext *ctx, funcid_t index) =0; }; #define SP_PARAMTYPE_ANY 0 diff --git a/public/IPluginFunction.h b/public/IPluginFunction.h deleted file mode 100644 index 7174baf6..00000000 --- a/public/IPluginFunction.h +++ /dev/null @@ -1,153 +0,0 @@ -#ifndef _INCLUDE_SOURCEMOD_PLUGINFUNCTION_INTERFACE_H_ -#define _INCLUDE_SOURCEMOD_PLUGINFUNCTION_INTERFACE_H_ - -#include - -namespace SourceMod -{ - #define SM_PARAM_COPYBACK (1<<0) /* Copy an array/reference back after call */ - - #define SM_PARAM_STRING_UTF8 (1<<0) /* String should be UTF-8 handled */ - #define SM_PARAM_STRING_COPY (1<<1) /* String should be copied into the plugin */ - - /** - * @brief Represents what a function needs to implement in order to be callable. - */ - class ICallable - { - public: - /** - * @brief Pushes a cell onto the current call. - * - * @param cell Parameter value to push. - * @return Error code, if any. - */ - virtual int PushCell(cell_t cell) =0; - - /** - * @brief Pushes a cell by reference onto the current call. - * NOTE: On Execute, the pointer passed will be modified if copyback is enabled. - * NOTE: By reference parameters are cached and thus are not read until execution. - * This means you cannot push a pointer, change it, and push it again and expect - * two different values to come out. - * - * @param cell Address containing parameter value to push. - * @param flags Copy-back flags. - * @return Error code, if any. - */ - virtual int PushCellByRef(cell_t *cell, int flags) =0; - - /** - * @brief Pushes a float onto the current call. - * - * @param float Parameter value to push. - * @return Error code, if any. - */ - virtual int PushFloat(float number) =0; - - /** - * @brief Pushes a float onto the current call by reference. - * NOTE: On Execute, the pointer passed will be modified if copyback is enabled. - * NOTE: By reference parameters are cached and thus are not read until execution. - * This means you cannot push a pointer, change it, and push it again and expect - * two different values to come out. - * - * @param float Parameter value to push. - & @param flags Copy-back flags. - * @return Error code, if any. - */ - virtual int PushFloatByRef(float *number, int flags) =0; - - /** - * @brief Pushes an array of cells onto the current call. - * NOTE: On Execute, the pointer passed will be modified if non-NULL and copy-back - * is enabled. - * NOTE: By reference parameters are cached and thus are not read until execution. - * This means you cannot push a pointer, change it, and push it again and expect - * two different values to come out. - * - * @param inarray Array to copy, NULL if no initial array should be copied. - * @param cells Number of cells to allocate and optionally read from the input array. - * @param phys_addr Optional return address for physical array, if one was made. - * @param flags Whether or not changes should be copied back to the input array. - * @return Error code, if any. - */ - virtual int PushArray(cell_t *inarray, - unsigned int cells, - cell_t **phys_addr, - int flags=0) =0; - - /** - * @brief Pushes a string onto the current call. - * - * @param string String to push. - * @return Error code, if any. - */ - virtual int PushString(const char *string) =0; - - /** - * @brief Pushes a string or string buffer. - * NOTE: On Execute, the pointer passed will be modified if copy-back is enabled. - * - * @param buffer Pointer to string buffer. - * @param length Length of buffer. - * @param sz_flags String flags. - * @param cp_flags Copy-back flags. - * @return Error code, if any. - */ - virtual int PushStringEx(char *buffer, size_t length, int sz_flags, int cp_flags) =0; - - /** - * @brief Cancels a function call that is being pushed but not yet executed. - * This can be used be reset for CallFunction() use. - */ - virtual void Cancel() =0; - }; - - /** - * @brief Encapsulates a function call in a plugin. - * NOTE: Function calls must be atomic to one execution context. - * NOTE: This object should not be deleted. It lives for the lifetime of the plugin. - */ - class IPluginFunction : public ICallable - { - public: - /** - * @brief Executes the forward, resets the pushed parameter list, and performs any copybacks. - * - * @param result Pointer to store return value in. - * @return Error code, if any. - */ - virtual int Execute(cell_t *result) =0; - - /** - * @brief Executes the function with the given parameter array. - * Parameters are read in forward order (i.e. index 0 is parameter #1) - * NOTE: You will get an error if you attempt to use CallFunction() with - * previously pushed parameters. - * - * @param param Array of cell parameters. - * @param num_params Number of parameters to push. - * @param result Pointer to store result of function on return. - * @return SourcePawn error code (if any). - */ - virtual int CallFunction(const cell_t *params, unsigned int num_params, cell_t *result) =0; - - /** - * @brief Returns which plugin this function belongs to. - * - * @return IPlugin pointer to parent plugin. - */ - virtual IPlugin *GetParentPlugin() =0; - - /** - * @brief Returns the physical address of a by-reference parameter. - * - * @param Parameter index to read (beginning at 0). - * @return Address, or NULL if invalid parameter specified. - */ - virtual cell_t *GetAddressOfPushedParam(unsigned int param) =0; - }; -}; - -#endif //_INCLUDE_SOURCEMOD_PLUGINFUNCTION_INTERFACE_H_ diff --git a/public/IPluginSys.h b/public/IPluginSys.h index 45f27065..589b788f 100644 --- a/public/IPluginSys.h +++ b/public/IPluginSys.h @@ -57,8 +57,6 @@ namespace SourceMod PluginType_Global, /* Plugin will never be unloaded or updated */ }; - class IPluginFunction; - /** * @brief Encapsulates a run-time plugin as maintained by SourceMod. */ @@ -129,22 +127,6 @@ namespace SourceMod */ virtual unsigned int GetSerial() const =0; - /** - * @brief Returns a function by name. - * - * @param public_name Name of the function. - * @return A new IPluginFunction pointer, NULL if not found. - */ - virtual IPluginFunction *GetFunctionByName(const char *public_name) =0; - - /** - * @brief Returns a function by its id. - * - * @param func_id Function ID. - * @return A new IPluginFunction pointer, NULL if not found. - */ - virtual IPluginFunction *GetFunctionById(funcid_t func_id) =0; - /** * @brief Returns a plugin's identity token. */ diff --git a/public/sourcepawn/sp_vm_api.h b/public/sourcepawn/sp_vm_api.h index cb904105..21ff120d 100644 --- a/public/sourcepawn/sp_vm_api.h +++ b/public/sourcepawn/sp_vm_api.h @@ -17,6 +17,152 @@ namespace SourcePawn { class IVirtualMachine; + #define SM_PARAM_COPYBACK (1<<0) /* Copy an array/reference back after call */ + + #define SM_PARAM_STRING_UTF8 (1<<0) /* String should be UTF-8 handled */ + #define SM_PARAM_STRING_COPY (1<<1) /* String should be copied into the plugin */ + + /** + * @brief Represents what a function needs to implement in order to be callable. + */ + class ICallable + { + public: + /** + * @brief Pushes a cell onto the current call. + * + * @param cell Parameter value to push. + * @return Error code, if any. + */ + virtual int PushCell(cell_t cell) =0; + + /** + * @brief Pushes a cell by reference onto the current call. + * NOTE: On Execute, the pointer passed will be modified if copyback is enabled. + * NOTE: By reference parameters are cached and thus are not read until execution. + * This means you cannot push a pointer, change it, and push it again and expect + * two different values to come out. + * + * @param cell Address containing parameter value to push. + * @param flags Copy-back flags. + * @return Error code, if any. + */ + virtual int PushCellByRef(cell_t *cell, int flags) =0; + + /** + * @brief Pushes a float onto the current call. + * + * @param float Parameter value to push. + * @return Error code, if any. + */ + virtual int PushFloat(float number) =0; + + /** + * @brief Pushes a float onto the current call by reference. + * NOTE: On Execute, the pointer passed will be modified if copyback is enabled. + * NOTE: By reference parameters are cached and thus are not read until execution. + * This means you cannot push a pointer, change it, and push it again and expect + * two different values to come out. + * + * @param float Parameter value to push. + & @param flags Copy-back flags. + * @return Error code, if any. + */ + virtual int PushFloatByRef(float *number, int flags) =0; + + /** + * @brief Pushes an array of cells onto the current call. + * NOTE: On Execute, the pointer passed will be modified if non-NULL and copy-back + * is enabled. + * NOTE: By reference parameters are cached and thus are not read until execution. + * This means you cannot push a pointer, change it, and push it again and expect + * two different values to come out. + * + * @param inarray Array to copy, NULL if no initial array should be copied. + * @param cells Number of cells to allocate and optionally read from the input array. + * @param phys_addr Optional return address for physical array, if one was made. + * @param flags Whether or not changes should be copied back to the input array. + * @return Error code, if any. + */ + virtual int PushArray(cell_t *inarray, + unsigned int cells, + cell_t **phys_addr, + int flags=0) =0; + + /** + * @brief Pushes a string onto the current call. + * + * @param string String to push. + * @return Error code, if any. + */ + virtual int PushString(const char *string) =0; + + /** + * @brief Pushes a string or string buffer. + * NOTE: On Execute, the pointer passed will be modified if copy-back is enabled. + * + * @param buffer Pointer to string buffer. + * @param length Length of buffer. + * @param sz_flags String flags. + * @param cp_flags Copy-back flags. + * @return Error code, if any. + */ + virtual int PushStringEx(char *buffer, size_t length, int sz_flags, int cp_flags) =0; + + /** + * @brief Cancels a function call that is being pushed but not yet executed. + * This can be used be reset for CallFunction() use. + */ + virtual void Cancel() =0; + }; + + + /** + * @brief Encapsulates a function call in a plugin. + * NOTE: Function calls must be atomic to one execution context. + * NOTE: This object should not be deleted. It lives for the lifetime of the plugin. + */ + class IPluginFunction : public ICallable + { + public: + /** + * @brief Executes the forward, resets the pushed parameter list, and performs any copybacks. + * + * @param result Pointer to store return value in. + * @return Error code, if any. + */ + virtual int Execute(cell_t *result) =0; + + /** + * @brief Executes the function with the given parameter array. + * Parameters are read in forward order (i.e. index 0 is parameter #1) + * NOTE: You will get an error if you attempt to use CallFunction() with + * previously pushed parameters. + * + * @param param Array of cell parameters. + * @param num_params Number of parameters to push. + * @param result Pointer to store result of function on return. + * @return SourcePawn error code (if any). + */ + virtual int CallFunction(const cell_t *params, unsigned int num_params, cell_t *result) =0; + + /** + * @brief Returns which plugin this function belongs to. + * + * @return IPluginContext pointer to parent plugin. + */ + virtual IPluginContext *GetParentContext() =0; + + /** + * @brief Returns the physical address of a by-reference parameter. + * + * @param Parameter index to read (beginning at 0). + * @return Address, or NULL if invalid parameter specified. + */ + virtual cell_t *GetAddressOfPushedParam(unsigned int param) =0; + }; + + /** * @brief Interface to managing a debug context at runtime. */ @@ -340,6 +486,22 @@ namespace SourcePawn */ virtual cell_t ThrowNativeError(const char *msg, ...) =0; + /** + * @brief Returns a function by name. + * + * @param public_name Name of the function. + * @return A new IPluginFunction pointer, NULL if not found. + */ + virtual IPluginFunction *GetFunctionByName(const char *public_name) =0; + + /** + * @brief Returns a function by its id. + * + * @param func_id Function ID. + * @return A new IPluginFunction pointer, NULL if not found. + */ + virtual IPluginFunction *GetFunctionById(funcid_t func_id) =0; + #if defined SOURCEMOD_BUILD /** * @brief Returns the identity token for this context. @@ -348,6 +510,13 @@ namespace SourcePawn * @return Identity token. */ virtual SourceMod::IdentityToken_t *GetIdentity() =0; + + /** + * @brief Returns whether the identity is runnable. + * + * @return True if runnable, false otherwise. + */ + virtual bool IsRunnable() =0; #endif }; diff --git a/public/sourcepawn/sp_vm_types.h b/public/sourcepawn/sp_vm_types.h index 2436144d..74e47434 100644 --- a/public/sourcepawn/sp_vm_types.h +++ b/public/sourcepawn/sp_vm_types.h @@ -39,6 +39,7 @@ typedef uint32_t funcid_t; #define SP_ERROR_INVALID_NATIVE 21 /* Native was pending or invalid */ #define SP_ERROR_PARAMS_MAX 22 /* Maximum number of parameters reached */ #define SP_ERROR_NATIVE 23 /* Error originates from a native */ +#define SP_ERROR_NOT_RUNNABLE 24 /* Function or plugin is not runnable */ /********************************************** *** The following structures are reference structures.