rewrote forward API to use cached parameter pushing instead of immediate pushing

removed copy back cruft since it's no longer needed
removed PushCells() from API requirements, not needed
adjusted documentation and added TODO list to ForwardSys.cpp
various internal improvements

--HG--
extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40188
This commit is contained in:
David Anderson
2006-11-12 09:51:39 +00:00
parent 442806dd45
commit bad69571b6
9 changed files with 181 additions and 433 deletions
+7 -23
View File
@@ -76,7 +76,7 @@ int CFunction::PushCells(cell_t array[], unsigned int numcells, bool each)
{
if (!each)
{
return PushArray(array, numcells, NULL, SMFUNC_COPYBACK_NONE);
return PushArray(array, numcells, NULL, 0);
} else {
int err;
for (unsigned int i=0; i<numcells; i++)
@@ -106,7 +106,7 @@ int CFunction::PushArray(cell_t *inarray, unsigned int cells, cell_t **phys_addr
return SetError(err);
}
info->flags = (inarray || (copyback & SMFUNC_COPYBACK_ALWAYS)) ? copyback : SMFUNC_COPYBACK_NONE;
info->flags = inarray ? copyback : 0;
info->marked = true;
info->size = cells;
m_params[m_curparam] = info->local_addr;
@@ -114,10 +114,7 @@ int CFunction::PushArray(cell_t *inarray, unsigned int cells, cell_t **phys_addr
if (inarray)
{
if (!(copyback & SMFUNC_ARRAY_NOINIT))
{
memcpy(info->phys_addr, inarray, sizeof(cell_t) * cells);
}
memcpy(info->phys_addr, inarray, sizeof(cell_t) * cells);
info->orig_addr = inarray;
} else {
info->orig_addr = info->phys_addr;
@@ -133,10 +130,10 @@ int CFunction::PushArray(cell_t *inarray, unsigned int cells, cell_t **phys_addr
int CFunction::PushString(const char *string)
{
return _PushString(string, SMFUNC_COPYBACK_NONE);
return _PushString(string, 0);
}
int CFunction::PushStringByRef(char *string, int flags)
int CFunction::PushStringEx(char *string, int flags)
{
return _PushString(string, flags);
}
@@ -163,8 +160,7 @@ int CFunction::_PushString(const char *string, int flags)
m_params[m_curparam] = info->local_addr;
m_curparam++; /* Prevent a leak */
//:TODO: Use UTF-8 version
if ((err=base->StringToLocal(info->local_addr, len, string)) != SP_ERROR_NONE)
if ((err=base->StringToLocalUTF8(info->local_addr, len, string, NULL)) != SP_ERROR_NONE)
{
return SetError(err);
}
@@ -197,7 +193,7 @@ void CFunction::Cancel()
m_errorstate = SP_ERROR_NONE;
}
int CFunction::Execute(cell_t *result, IFunctionCopybackReader *reader)
int CFunction::Execute(cell_t *result)
{
int err;
if (m_errorstate != SP_ERROR_NONE)
@@ -236,17 +232,6 @@ int CFunction::Execute(cell_t *result, IFunctionCopybackReader *reader)
}
if (docopies && temp_info[numparams].flags)
{
if (reader)
{
if (!reader->OnCopybackArray(numparams,
temp_info[numparams].size,
temp_info[numparams].phys_addr,
temp_info[numparams].orig_addr,
temp_info[numparams].flags))
{
goto _skipcopy;
}
}
if (temp_info[numparams].orig_addr)
{
if (temp_info[numparams].size == 1)
@@ -259,7 +244,6 @@ int CFunction::Execute(cell_t *result, IFunctionCopybackReader *reader)
}
}
}
_skipcopy:
base->HeapPop(temp_info[numparams].local_addr);
temp_info[numparams].marked = false;
}
+2 -2
View File
@@ -28,9 +28,9 @@ public:
virtual int PushCells(cell_t array[], unsigned int numcells, bool each);
virtual int PushArray(cell_t *inarray, unsigned int cells, cell_t **phys_addr, int copyback);
virtual int PushString(const char *string);
virtual int PushStringByRef(char *string, int flags);
virtual int PushStringEx(char *string, int flags);
virtual cell_t *GetAddressOfPushedParam(unsigned int param);
virtual int Execute(cell_t *result, IFunctionCopybackReader *reader);
virtual int Execute(cell_t *result);
virtual void Cancel();
virtual int CallFunction(const cell_t *params, unsigned int num_params, cell_t *result);
virtual IPlugin *GetParentPlugin();
+98 -261
View File
@@ -2,6 +2,30 @@
#include "ForwardSys.h"
#include "PluginSys.h"
/**
* Gensis turns to its source, reduction occurs stepwise although the essence is all one.
* End of line. FTL system check.
*
* :TODO: Implement the manager. ho ho ho
*
* :TODO: WHAT NEEDS TO BE TESTED IN THIS BEAST (X=done, -=TODO)
* NORMAL FUNCTIONS:
* X Push cells
* X Push cells byref (copyback tested = yes)
* - Push floats (copyback tested = ??)
* - Push floats byref (copyback tested = ??)
* - Push arrays (copyback tested = ??)
* - Push strings (copyback tested = ??)
* VARARG FUNCTIONS:
* - Pushing no varargs
* - Push vararg cells (copyback should be verified to not happen = ??)
* - Push vararg cells byref (copyback tested = ??)
* - Push vararg floats (copyback should be verified to not happen = ??)
* - Push vararg floats byref (copyback tested = ??)
* - Push vararg arrays (copyback tested = ??)
* - Push vararg strings (copyback tested = ??)
*/
CForward *CForward::CreateForward(const char *name, ExecType et, unsigned int num_params, ParamType *types, va_list ap)
{
ParamType _types[SP_MAX_EXEC_PARAMS];
@@ -50,48 +74,17 @@ CForward *CForward::CreateForward(const char *name, ExecType et, unsigned int nu
if (num_params && types[num_params-1] == Param_VarArgs)
{
pForward->m_varargs = true;
pForward->m_varargs = num_params--;
} else {
pForward->m_varargs = false;
}
pForward->m_numparams = num_params;
pForward->m_errstate = SP_ERROR_NONE;
pForward->m_CopyBacks.numrecopy = 0;
return pForward;
}
bool CForward::OnCopybackArray(unsigned int param,
unsigned int cells,
cell_t *source_addr,
cell_t *orig_addr,
int flags)
{
/* Check if the stack is empty, this should be an assertion */
if (m_NextStack.empty())
{
/* This should never happen! */
assert(!m_NextStack.empty());
return true;
}
/* Check if we even want to copy to the next plugin */
if (!(flags & SMFUNC_COPYBACK_ALWAYS))
{
return true;
}
/* Keep track of the copy back and save the info */
NextCallInfo &info = m_NextStack.front();
info.recopy[info.numrecopy++] = param;
info.orig_addrs[param] = orig_addr;
info.sizes[param] = cells;
/* We don't want to override the copy. */
return true;
}
int CForward::Execute(cell_t *result, IForwardFilter *filter)
{
if (m_errstate)
@@ -101,9 +94,6 @@ int CForward::Execute(cell_t *result, IForwardFilter *filter)
return err;
}
/* Reset marker */
m_curparam = 0;
if (filter)
{
filter->OnExecuteBegin();
@@ -116,53 +106,53 @@ int CForward::Execute(cell_t *result, IForwardFilter *filter)
int err;
unsigned int failed=0, success=0;
unsigned int save_numcopy = 0;
unsigned int num_params = m_curparam;
FwdParamInfo temp_info[SP_MAX_EXEC_PARAMS];
FwdParamInfo *param;
ParamType type;
/* Save local, reset */
memcpy(temp_info, m_params, sizeof(m_params));
m_curparam = 0;
/**
* Save copyback into to start the chain,
* then reset it for re-entrancy
*/
m_NextStack.push(m_CopyBacks);
NextCallInfo &info = m_NextStack.front();
m_CopyBacks.numrecopy = 0;
for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
{
func = (*iter);
/**
* Check if we need to copy a new array back into the plugin.
*/
if (info.numrecopy)
{
/* The last plugin has a chained copyback, we must redirect it here. */
unsigned int param;
cell_t *orig_addr, *targ_addr;
for (unsigned int i=0; i<info.numrecopy; i++)
{
/* Get the parameter info to copy */
param = info.recopy[i];
targ_addr = func->GetAddressOfPushedParam(param);
orig_addr = info.orig_addrs[param];
/* Only do the copy for valid targets */
if (targ_addr && orig_addr)
{
if (info.sizes[param] == 1)
{
*targ_addr = *orig_addr;
} else {
memcpy(targ_addr, orig_addr, info.sizes[param] * sizeof(cell_t));
}
}
/* If this failed, the plugin will most likely be failing as well. */
}
save_numcopy = info.numrecopy;
info.numrecopy = 0;
}
for (unsigned int i=0; i<num_params; i++)
{
param = &temp_info[i];
if (i >= m_numparams || m_types[i] == Param_Any)
{
type = param->pushedas;
} else {
type = m_types[i];
}
if ((i >= m_numparams) || (type & SP_PARAMFLAG_BYREF))
{
/* If we're byref or we're vararg, we always push everything by ref.
* Even if they're byval, we must push them byref.
*/
if (type == Param_String)
{
func->PushStringEx((char *)param->byref.orig_addr, param->byref.flags);
} else if (type == Param_Float || type == Param_Cell) {
func->PushCellByRef(&param->val, 0);
} else {
func->PushArray(param->byref.orig_addr, param->byref.cells, NULL, param->byref.flags);
assert(type == Param_Array || type == Param_FloatByRef || type == Param_CellByRef);
}
} else {
/* If we're not byref or not vararg, our job is a bit easier. */
assert(type == Param_Cell || type == Param_Float);
func->PushCell(param->val);
}
}
/* Call the function and deal with the return value.
* :TODO: only pass reader if we know we have an array in the list
*/
if ((err=func->Execute(&cur_result, this)) != SP_ERROR_NONE)
if ((err=func->Execute(&cur_result)) != SP_ERROR_NONE)
{
bool handled = false;
if (filter)
@@ -173,10 +163,6 @@ int CForward::Execute(cell_t *result, IForwardFilter *filter)
{
/* :TODO: invoke global error reporting here */
}
/* If we failed, we're not quite done. The copy chain has been broken.
* We have to restore it so past changes will continue to get mirrored.
*/
info.numrecopy = save_numcopy;
failed++;
} else {
success++;
@@ -218,8 +204,6 @@ int CForward::Execute(cell_t *result, IForwardFilter *filter)
}
}
m_NextStack.pop();
if (m_ExecType == ET_Event || m_ExecType == ET_Hook)
{
cur_result = high_result;
@@ -229,8 +213,6 @@ int CForward::Execute(cell_t *result, IForwardFilter *filter)
*result = cur_result;
DumpAdditionQueue();
if (filter)
{
filter->OnExecuteEnd(&cur_result, success, failed);
@@ -243,8 +225,10 @@ int CForward::PushCell(cell_t cell)
{
if (m_curparam < m_numparams)
{
if (m_types[m_curparam] != Param_Cell && m_types[m_curparam] != Param_Any)
if (m_types[m_curparam] == Param_Any)
{
m_params[m_curparam].pushedas = Param_Cell;
} else if (m_types[m_curparam] != Param_Cell) {
return SetError(SP_ERROR_PARAM);
}
} else {
@@ -252,17 +236,10 @@ int CForward::PushCell(cell_t cell)
{
return SetError(SP_ERROR_PARAMS_MAX);
}
m_params[m_curparam].pushedas = Param_Cell;
}
FuncIter iter;
IPluginFunction *func;
for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
{
func = (*iter);
func->PushCell(cell);
}
m_curparam++;
m_params[m_curparam++].val = cell;
return SP_ERROR_NONE;
}
@@ -271,8 +248,10 @@ int CForward::PushFloat(float number)
{
if (m_curparam < m_numparams)
{
if (m_types[m_curparam] != Param_Float && m_types[m_curparam] != Param_Any)
if (m_types[m_curparam] == Param_Any)
{
m_params[m_curparam].pushedas = Param_Float;
} else if (m_types[m_curparam] != Param_Float) {
return SetError(SP_ERROR_PARAM);
}
} else {
@@ -280,17 +259,10 @@ int CForward::PushFloat(float number)
{
return SetError(SP_ERROR_PARAMS_MAX);
}
m_params[m_curparam].pushedas = Param_Float;
}
FuncIter iter;
IPluginFunction *func;
for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
{
func = (*iter);
func->PushFloat(number);
}
m_curparam++;
m_params[m_curparam++].val = *(cell_t *)&number;
return SP_ERROR_NONE;
}
@@ -310,19 +282,7 @@ int CForward::PushCellByRef(cell_t *cell, int flags)
}
}
if (flags & SMFUNC_COPYBACK_ALWAYS)
{
_Int_PushArray(cell, 1, flags);
} else {
FuncIter iter;
IPluginFunction *func;
for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
{
func = (*iter);
func->PushCellByRef(cell, flags);
}
}
_Int_PushArray(cell, 1, flags);
m_curparam++;
return SP_ERROR_NONE;
@@ -343,93 +303,17 @@ int CForward::PushFloatByRef(float *num, int flags)
}
}
if (flags & SMFUNC_COPYBACK_ALWAYS)
{
_Int_PushArray((cell_t *)num, 1, flags);
} else {
FuncIter iter;
IPluginFunction *func;
for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
{
func = (*iter);
func->PushFloatByRef(num, flags);
}
}
_Int_PushArray((cell_t *)num, 1, flags);
m_curparam++;
return SP_ERROR_NONE;
}
int CForward::PushCells(cell_t array[], unsigned int numcells, bool each)
{
if (each)
{
/* Type check each cell if we need to! */
if (m_curparam + numcells >= m_numparams && !m_varargs)
{
return SetError(SP_ERROR_PARAMS_MAX);
} else {
for (unsigned int i=m_curparam; i<m_numparams; i++)
{
if (m_types[i] != Param_Any || m_types[i] != Param_Cell)
{
return SetError(SP_ERROR_PARAM);
}
}
}
} else {
if (m_curparam < m_numparams)
{
if (m_types[m_curparam] != Param_Any || m_types[m_curparam] == Param_Array)
{
return SetError(SP_ERROR_PARAM);
}
} else {
if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS)
{
return SetError(SP_ERROR_PARAMS_MAX);
}
}
}
FuncIter iter;
IPluginFunction *func;
for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
{
func = (*iter);
func->PushCells(array, numcells, each);
}
m_curparam += each ? numcells : 1;
return SP_ERROR_NONE;
}
void CForward::_Int_PushArray(cell_t *inarray, unsigned int cells, int flags)
{
FuncIter iter;
IPluginFunction *func;
if (flags & SMFUNC_COPYBACK_ALWAYS)
{
/* As a special optimization, we create blank default arrays because they will be
* copied over anyway!
*/
for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
{
func = (*iter);
func->PushArray(inarray, cells, NULL, flags|SMFUNC_ARRAY_NOINIT);
}
m_CopyBacks.recopy[m_CopyBacks.numrecopy++] = m_curparam;
m_CopyBacks.orig_addrs[m_curparam] = inarray;
m_CopyBacks.sizes[m_curparam] = cells;
} else {
for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
{
func = (*iter);
func->PushArray(inarray, cells, NULL, flags);
}
}
m_params[m_curparam].byref.cells = cells;
m_params[m_curparam].byref.flags = flags;
m_params[m_curparam].byref.orig_addr = inarray;
}
int CForward::PushArray(cell_t *inarray, unsigned int cells, cell_t **phys_addr, int flags)
@@ -442,8 +326,10 @@ int CForward::PushArray(cell_t *inarray, unsigned int cells, cell_t **phys_addr,
if (m_curparam < m_numparams)
{
if (m_types[m_curparam] != Param_Any || m_types[m_curparam] == Param_Array)
if (m_types[m_curparam] == Param_Any)
{
m_params[m_curparam].pushedas = Param_Array;
} else if (m_types[m_curparam] != Param_Array) {
return SetError(SP_ERROR_PARAM);
}
} else {
@@ -451,6 +337,7 @@ int CForward::PushArray(cell_t *inarray, unsigned int cells, cell_t **phys_addr,
{
return SetError(SP_ERROR_PARAMS_MAX);
}
m_params[m_curparam].pushedas = Param_Array;
}
if (phys_addr)
@@ -469,8 +356,10 @@ int CForward::PushString(const char *string)
{
if (m_curparam < m_numparams)
{
if (m_types[m_curparam] != Param_Any || m_types[m_curparam] == Param_String)
if (m_types[m_curparam] == Param_Any)
{
m_params[m_curparam].pushedas = Param_String;
} else if (m_types[m_curparam] == Param_String) {
return SetError(SP_ERROR_PARAM);
}
} else {
@@ -478,27 +367,23 @@ int CForward::PushString(const char *string)
{
return SetError(SP_ERROR_PARAMS_MAX);
}
m_params[m_curparam].pushedas = Param_String;
}
FuncIter iter;
IPluginFunction *func;
for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
{
func = (*iter);
func->PushString(string);
}
_Int_PushArray((cell_t *)string, 0, 0);
m_curparam++;
return SP_ERROR_NONE;
}
int CForward::PushStringByRef(char *string, int flags)
int CForward::PushStringEx(char *string, int flags)
{
if (m_curparam < m_numparams)
{
if (m_types[m_curparam] != Param_Any || m_types[m_curparam] == Param_String)
if (m_types[m_curparam] == Param_Any)
{
m_params[m_curparam].pushedas = Param_String;
} else if (m_types[m_curparam] == Param_String) {
return SetError(SP_ERROR_PARAM);
}
} else {
@@ -506,16 +391,10 @@ int CForward::PushStringByRef(char *string, int flags)
{
return SetError(SP_ERROR_PARAMS_MAX);
}
m_params[m_curparam].pushedas = Param_String;
}
FuncIter iter;
IPluginFunction *func;
for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
{
func = (*iter);
func->PushStringByRef(string, flags);
}
_Int_PushArray((cell_t *)string, 0, flags);
m_curparam++;
return SP_ERROR_NONE;
@@ -528,18 +407,7 @@ void CForward::Cancel()
return;
}
FuncIter iter;
IPluginFunction *func;
for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
{
func = (*iter);
func->Cancel();
}
m_CopyBacks.numrecopy = 0;
DumpAdditionQueue();
m_curparam = 0;
m_errstate = SP_ERROR_NONE;
}
@@ -578,11 +446,8 @@ bool CForward::RemoveFunction(IPluginFunction *func)
}
}
/* Just in case */
m_AddQueue.remove(func);
/* Cancel a call, if any */
if (found && (!m_NextStack.empty() || m_curparam))
if (found || m_curparam)
{
func->Cancel();
}
@@ -607,32 +472,9 @@ unsigned int CForward::RemoveFunctionsOfPlugin(IPlugin *plugin)
}
}
for (iter=m_AddQueue.begin(); iter!=m_AddQueue.end();)
{
func = (*iter);
if (func->GetParentPlugin() == plugin)
{
/* Don't count these toward the total */
iter = m_functions.erase(iter);
} else {
iter++;
}
}
return removed;
}
void CForward::DumpAdditionQueue()
{
FuncIter iter = m_AddQueue.begin();
while (iter != m_AddQueue.end())
{
m_functions.push_back((*iter));
//:TODO: eventually we will tell the plugin we're using it
iter = m_AddQueue.erase(iter);
}
}
bool CForward::AddFunction(IPluginFunction *func)
{
if (m_curparam)
@@ -640,13 +482,8 @@ bool CForward::AddFunction(IPluginFunction *func)
return false;
}
if (!m_NextStack.empty())
{
m_AddQueue.push_back(func);
} else {
//:TODO: eventually we will tell the plugin we're using it
m_functions.push_back(func);
}
//:TODO: eventually we will tell the plugin we're using it
m_functions.push_back(func);
return true;
}
+15 -19
View File
@@ -14,25 +14,30 @@ typedef List<IPluginFunction *>::iterator FuncIter;
//:TODO: a global name max define for sourcepawn, should mirror compiler's sNAMEMAX
#define FORWARDS_NAME_MAX 64
struct NextCallInfo
struct ByrefInfo
{
unsigned int recopy[SP_MAX_EXEC_PARAMS];
unsigned int sizes[SP_MAX_EXEC_PARAMS];
cell_t *orig_addrs[SP_MAX_EXEC_PARAMS];
unsigned int numrecopy;
unsigned int cells;
cell_t *orig_addr;
int flags;
};
class CForward : public IChangeableForward, IFunctionCopybackReader
struct FwdParamInfo
{
cell_t val;
ByrefInfo byref;
ParamType pushedas;
};
class CForward : public IChangeableForward
{
public: //ICallable
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 PushCells(cell_t array[], unsigned int numcells, bool each);
virtual int PushArray(cell_t *inarray, unsigned int cells, cell_t **phys_addr, int flags);
virtual int PushString(const char *string);
virtual int PushStringByRef(char *string, int flags);
virtual int PushStringEx(char *string, int flags);
virtual void Cancel();
public: //IForward
virtual const char *GetForwardName();
@@ -44,12 +49,6 @@ public: //IChangeableForward
virtual unsigned int RemoveFunctionsOfPlugin(IPlugin *plugin);
virtual bool AddFunction(IPluginFunction *func);
virtual bool AddFunction(sp_context_t *ctx, funcid_t index);
public: //IFunctionCopybackReader
virtual bool OnCopybackArray(unsigned int param,
unsigned int cells,
cell_t *source_addr,
cell_t *orig_addr,
int flags);
public:
static CForward *CreateForward(const char *name,
ExecType et,
@@ -57,7 +56,6 @@ public:
ParamType *types,
va_list ap);
private:
void DumpAdditionQueue();
void _Int_PushArray(cell_t *inarray, unsigned int cells, int flags);
inline int SetError(int err)
{
@@ -71,18 +69,16 @@ protected:
List<IPluginFunction *> m_functions;
/* Type and name information */
FwdParamInfo m_params[SP_MAX_EXEC_PARAMS];
ParamType m_types[SP_MAX_EXEC_PARAMS];
char m_name[FORWARDS_NAME_MAX+1];
unsigned int m_numparams;
bool m_varargs;
unsigned int m_varargs;
ExecType m_ExecType;
/* State information */
unsigned int m_curparam;
int m_errstate;
CStack<NextCallInfo> m_NextStack;
List<IPluginFunction *> m_AddQueue;
NextCallInfo m_CopyBacks;
};
#endif //_INCLUDE_SOURCEMOD_FORWARDSYSTEM_H_