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
This commit is contained in:
@@ -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; i<ctx->plugin->info.publics_num; i++)
|
||||
{
|
||||
delete m_pub_funcs[i];
|
||||
m_pub_funcs[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_priv_funcs)
|
||||
{
|
||||
for (unsigned int i=0; i<m_funcsnum; i++)
|
||||
{
|
||||
delete m_priv_funcs[i];
|
||||
m_priv_funcs[i] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BaseContext::~BaseContext()
|
||||
{
|
||||
FlushFunctionCache();
|
||||
delete [] m_pub_funcs;
|
||||
m_pub_funcs = NULL;
|
||||
delete [] m_priv_funcs;
|
||||
m_priv_funcs = NULL;
|
||||
}
|
||||
|
||||
void BaseContext::SetContext(sp_context_t *_ctx)
|
||||
@@ -36,6 +90,9 @@ void BaseContext::SetContext(sp_context_t *_ctx)
|
||||
return;
|
||||
}
|
||||
ctx = _ctx;
|
||||
ctx->context = 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
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
+71
-69
@@ -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_
|
||||
|
||||
@@ -0,0 +1,251 @@
|
||||
#include <stdio.h>
|
||||
#include "PluginSys.h"
|
||||
|
||||
/********************
|
||||
* FUNCTION CALLING *
|
||||
********************/
|
||||
|
||||
void CFunction::Set(funcid_t funcid, IPluginContext *plugin)
|
||||
{
|
||||
m_funcid = funcid;
|
||||
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)
|
||||
{
|
||||
while (num_params--)
|
||||
{
|
||||
m_pContext->PushCell(params[num_params]);
|
||||
}
|
||||
|
||||
return m_pContext->Execute(m_funcid, result);
|
||||
}
|
||||
|
||||
IPluginContext *CFunction::GetParentContext()
|
||||
{
|
||||
return m_pContext;
|
||||
}
|
||||
|
||||
CFunction::CFunction(funcid_t funcid, IPluginContext *plugin) :
|
||||
m_funcid(funcid), m_pContext(plugin), m_curparam(0),
|
||||
m_errorstate(SP_ERROR_NONE)
|
||||
{
|
||||
}
|
||||
|
||||
int CFunction::PushCell(cell_t cell)
|
||||
{
|
||||
if (m_curparam >= SP_MAX_EXEC_PARAMS)
|
||||
{
|
||||
return SetError(SP_ERROR_PARAMS_MAX);
|
||||
}
|
||||
|
||||
m_info[m_curparam].marked = false;
|
||||
m_params[m_curparam] = cell;
|
||||
m_curparam++;
|
||||
|
||||
return SP_ERROR_NONE;
|
||||
}
|
||||
|
||||
int CFunction::PushCellByRef(cell_t *cell, int flags)
|
||||
{
|
||||
if (m_curparam >= SP_MAX_EXEC_PARAMS)
|
||||
{
|
||||
return SetError(SP_ERROR_PARAMS_MAX);
|
||||
}
|
||||
|
||||
return PushArray(cell, 1, NULL, flags);
|
||||
}
|
||||
|
||||
int CFunction::PushFloat(float number)
|
||||
{
|
||||
cell_t val = *(cell_t *)&number;
|
||||
|
||||
return PushCell(val);
|
||||
}
|
||||
|
||||
int CFunction::PushFloatByRef(float *number, int flags)
|
||||
{
|
||||
return PushCellByRef((cell_t *)number, flags);
|
||||
}
|
||||
|
||||
int CFunction::PushArray(cell_t *inarray, unsigned int cells, cell_t **phys_addr, int copyback)
|
||||
{
|
||||
if (m_curparam >= SP_MAX_EXEC_PARAMS)
|
||||
{
|
||||
return SetError(SP_ERROR_PARAMS_MAX);
|
||||
}
|
||||
|
||||
ParamInfo *info = &m_info[m_curparam];
|
||||
int err;
|
||||
|
||||
if ((err=m_pContext->HeapAlloc(cells, &info->local_addr, &info->phys_addr)) != SP_ERROR_NONE)
|
||||
{
|
||||
return SetError(err);
|
||||
}
|
||||
|
||||
info->flags = inarray ? copyback : 0;
|
||||
info->marked = true;
|
||||
info->size = cells * sizeof(cell_t);
|
||||
m_params[m_curparam] = info->local_addr;
|
||||
m_curparam++;
|
||||
|
||||
if (inarray)
|
||||
{
|
||||
memcpy(info->phys_addr, inarray, sizeof(cell_t) * cells);
|
||||
info->orig_addr = inarray;
|
||||
} else {
|
||||
info->orig_addr = info->phys_addr;
|
||||
}
|
||||
|
||||
if (phys_addr)
|
||||
{
|
||||
*phys_addr = info->phys_addr;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int CFunction::PushString(const char *string)
|
||||
{
|
||||
return _PushString(string, SM_PARAM_STRING_COPY, 0, strlen(string)+1);
|
||||
}
|
||||
|
||||
int CFunction::PushStringEx(char *buffer, size_t length, int sz_flags, int cp_flags)
|
||||
{
|
||||
return _PushString(buffer, sz_flags, cp_flags, length);
|
||||
}
|
||||
|
||||
int CFunction::_PushString(const char *string, int sz_flags, int cp_flags, size_t len)
|
||||
{
|
||||
if (m_curparam >= SP_MAX_EXEC_PARAMS)
|
||||
{
|
||||
return SetError(SP_ERROR_PARAMS_MAX);
|
||||
}
|
||||
|
||||
ParamInfo *info = &m_info[m_curparam];
|
||||
size_t cells = (len + sizeof(cell_t) - 1) / sizeof(cell_t);
|
||||
int err;
|
||||
|
||||
if ((err=m_pContext->HeapAlloc(cells, &info->local_addr, &info->phys_addr)) != SP_ERROR_NONE)
|
||||
{
|
||||
return SetError(err);
|
||||
}
|
||||
|
||||
info->marked = true;
|
||||
m_params[m_curparam] = info->local_addr;
|
||||
m_curparam++; /* Prevent a leak */
|
||||
|
||||
if (!(sz_flags & SM_PARAM_STRING_COPY))
|
||||
{
|
||||
goto skip_localtostr;
|
||||
}
|
||||
|
||||
if (sz_flags & SM_PARAM_STRING_UTF8)
|
||||
{
|
||||
if ((err=m_pContext->StringToLocalUTF8(info->local_addr, len, string, NULL)) != SP_ERROR_NONE)
|
||||
{
|
||||
return SetError(err);
|
||||
}
|
||||
} else {
|
||||
if ((err=m_pContext->StringToLocal(info->local_addr, len, string)) != SP_ERROR_NONE)
|
||||
{
|
||||
return SetError(err);
|
||||
}
|
||||
}
|
||||
|
||||
skip_localtostr:
|
||||
info->flags = cp_flags;
|
||||
info->orig_addr = (cell_t *)string;
|
||||
info->size = len;
|
||||
|
||||
return SP_ERROR_NONE;
|
||||
}
|
||||
|
||||
void CFunction::Cancel()
|
||||
{
|
||||
if (!m_curparam)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
while (m_curparam--)
|
||||
{
|
||||
if (m_info[m_curparam].marked)
|
||||
{
|
||||
m_pContext->HeapRelease(m_info[m_curparam].local_addr);
|
||||
m_info[m_curparam].marked = false;
|
||||
}
|
||||
}
|
||||
|
||||
m_errorstate = SP_ERROR_NONE;
|
||||
}
|
||||
|
||||
int CFunction::Execute(cell_t *result)
|
||||
{
|
||||
int err;
|
||||
if (m_errorstate != SP_ERROR_NONE)
|
||||
{
|
||||
err = m_errorstate;
|
||||
Cancel();
|
||||
return err;
|
||||
}
|
||||
|
||||
//This is for re-entrancy!
|
||||
cell_t temp_params[SP_MAX_EXEC_PARAMS];
|
||||
ParamInfo temp_info[SP_MAX_EXEC_PARAMS];
|
||||
unsigned int numparams = m_curparam;
|
||||
bool docopies = true;
|
||||
|
||||
if (numparams)
|
||||
{
|
||||
//Save the info locally, then reset it for re-entrant calls.
|
||||
memcpy(temp_params, m_params, numparams * sizeof(cell_t));
|
||||
memcpy(temp_info, m_info, numparams * sizeof(ParamInfo));
|
||||
}
|
||||
m_curparam = 0;
|
||||
|
||||
if ((err = CallFunction(temp_params, numparams, result)) != SP_ERROR_NONE)
|
||||
{
|
||||
docopies = false;
|
||||
}
|
||||
|
||||
while (numparams--)
|
||||
{
|
||||
if (!temp_info[numparams].marked)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (docopies && temp_info[numparams].flags)
|
||||
{
|
||||
if (temp_info[numparams].orig_addr)
|
||||
{
|
||||
if (temp_info[numparams].size == sizeof(cell_t))
|
||||
{
|
||||
*temp_info[numparams].orig_addr = *temp_info[numparams].phys_addr;
|
||||
} else {
|
||||
memcpy(temp_info[numparams].orig_addr,
|
||||
temp_info[numparams].phys_addr,
|
||||
temp_info[numparams].size);
|
||||
}
|
||||
}
|
||||
}
|
||||
m_pContext->HeapPop(temp_info[numparams].local_addr);
|
||||
temp_info[numparams].marked = false;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
cell_t *CFunction::GetAddressOfPushedParam(unsigned int param)
|
||||
{
|
||||
if (m_errorstate != SP_ERROR_NONE
|
||||
|| param >= m_curparam
|
||||
|| !m_info[param].marked)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return m_info[param].phys_addr;
|
||||
}
|
||||
@@ -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_
|
||||
Reference in New Issue
Block a user