diff --git a/core/interfaces/IForwardSys.h b/core/interfaces/IForwardSys.h index 49e2d16a..789b3fc7 100644 --- a/core/interfaces/IForwardSys.h +++ b/core/interfaces/IForwardSys.h @@ -142,7 +142,7 @@ namespace SourceMod virtual int PushArray(cell_t *inarray, unsigned int cells, cell_t **phys_addr, - int flags=SMFUNC_COPYBACK_NONE) =0; + int flags=0) =0; }; @@ -307,48 +307,33 @@ namespace SourceMod * * Note that while #2,3,4 could be added to AMX Mod X, the real binding property is #1, which makes the system * object oriented, rather than AMX Mod X, which hides the objects behind static functions. It is entirely a design - * issue, rather than a usability one. The interesting part is when it gets to implementation, which is when the - * problems for SourceMod arise. Specifically, the implementation is easier in GENERAL -- the tough part is the oddball - * cases. + * issue, rather than a usability one. The interesting part is when it gets to implementation, which has to cache + * parameter pushing until execution. Without this, multiple function calls can be started across one plugin, which + * will result in heap corruption given SourcePawn's implementation. * - * Observe the calling process: - * - Each parameter is pushed using the ICallable interface. For each parameter: - * - For each function in the collection, the parameter is processed and pushed. + * Observe the new calling process: + * - Each parameter is pushed into a local cache using the ICallable interface. * - For each function in the collection: + * - Each parameter is decoded and -pushed into the function. * - The call is made. - * - Copy backs are performed. * - Return * - * Astute readers will note the problems - the parameters are processed individually for each push, - * rather than for each call. This means: + * Astute readers will note the (minor) problems: * 1) More memory is used. Specifically, rather than N params of memory, you now have N params * M plugins. - * This is because, again, parameters are processed per function object, per-push, before the call. + * This is because, again, parameters are cached both per-function and per-forward. * 2) There are slightly more calls going around: one extra call for each parameter, since each push is manual. - * 3) Copybacks won't work as expected. * - * Number 3 is hard to see. For example, say a forward has two functions, and an array is pushed with copyback. - * The array gets pushed and copied into each plugin. When the call is made, each plugin now has separate copies of - * the array. When the copyback is performed, it gets mirrored to the originall address, but not to the next plugin! - - * Implementing this is "difficult." To be re-entrant, an IPluginFunction can't tell you anything - * about its copybacks after it has returned, because its internal states were reset long ago. - * - * In order to implement this feature, IPluginFunction::Execute function now lets you pass a listener in. - * This listener is notified each time an array parameter is about to be copied back. Specifically, the forward - * uses this to detect when it needs to push a new parameter out to the next plugin. When the forward gets the - * call back, it detects whether there is another plugin in the queue. If there is, it grabs the address it will - * be using for the same arrays, and specifies it as the new copy-back point. If no plugins are left, it allows - * the copyback to chain up to the original address. - * - * This wonderful little hack is somewhat reminiscent of how SourceHook parameter rewrite chains work. It seems - * ugly at first, but it is actually the correct design pattern to apply to an otherwise awful problem. - * - * Note that there are other solutions to this that aren't based on a visitor-like pattern. For example, the Function - * class could expose a "set new original address" function. Then after arrays are pushed, the arrays are re-browsed, - * and function #1 gets function #2's original address, function #2 gets function #3's original address, et cetera. - * This extra browse step is a bit less efficient though, since the "visitor" method implies only taking action when - * necessary. Furthermore, it would require exposing such a "set address" function, which should fire a red flag - * that the API is doing something it shouldn't (namely, exposing the direct setting of very internal properties). + * HISTORICAL NOTES: + * There used to be a # about copy backs. + * Note that originally, the Forward implementation was a thin wrapper around IForwards. It did not cache pushes, + * and instead immediately fired them to each internal plugin. This was to allow users to know that pointers would + * be immediately resolved. Unfortunately, this became extremely burdensome on the API and exposed many problems, + * the major (and breaking) one was that two separate Function objects cannot be in a calling process on the same + * plugin at once. (:TODO: perhaps prevent that in the IPlugin object?) This is because heap functions lose their order + * and become impossible to re-arrange without some global heap tracking mechanis. It also made iterative copy backs + * for arrays/references overwhelmingly complex, since each plugin had to have its memory back-patched for each copy. + * Therefore, this was scrapped for cached parameters (current implementation), which is the implementation AMX Mod X + * uses. It is both faster and works better. */ #endif //_INCLUDE_SOURCEMOD_FORWARDINTERFACE_H_ diff --git a/core/interfaces/IPluginFunction.h b/core/interfaces/IPluginFunction.h index 8002cd9e..d75ccc27 100644 --- a/core/interfaces/IPluginFunction.h +++ b/core/interfaces/IPluginFunction.h @@ -5,10 +5,7 @@ namespace SourceMod { - #define SMFUNC_COPYBACK_NONE (0) /* Never copy an array back */ - #define SMFUNC_COPYBACK_ONCE (1<<0) /* Copy an array back after call */ - #define SMFUNC_COPYBACK_ALWAYS (1<<1) /* Copy an array back after subsequent calls (forwards) */ - #define SMFUNC_ARRAY_NOINIT (1<<2) /* The array is not copied at first, but copyback is performed */ + #define SM_FUNCFLAG_COPYBACK (1<<0) /* Copy an array/reference back after call */ /** * @brief Represents what a function needs to implement in order to be callable. @@ -27,6 +24,9 @@ namespace SourceMod /** * @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. @@ -45,6 +45,9 @@ namespace SourceMod /** * @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. @@ -52,21 +55,13 @@ namespace SourceMod */ virtual int PushFloatByRef(float *number, int flags) =0; - /** - * @brief Pushes an array of cells onto the current call, each cell individually. - * NOTE: This is essentially a crippled version of PushArray(). - * - * @param array Array of cells. - * @param numcells Number of cells in array. - * @param each Whether or not to push as an array or individual cells. - * @return Error code, if any. - */ - virtual int PushCells(cell_t array[], unsigned int numcells, bool each) =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 array 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. @@ -77,7 +72,7 @@ namespace SourceMod virtual int PushArray(cell_t *inarray, unsigned int cells, cell_t **phys_addr, - int flags=SMFUNC_COPYBACK_NONE) =0; + int flags=0) =0; /** * @brief Pushes a string onto the current call. @@ -95,7 +90,7 @@ namespace SourceMod * @param flags Copy-back flags. * @return Error code, if any. */ - virtual int PushStringByRef(char *string, int flags) =0; + virtual int PushStringEx(char *string, int flags) =0; /** * @brief Cancels a function call that is being pushed but not yet executed. @@ -104,30 +99,6 @@ namespace SourceMod virtual void Cancel() =0; }; - - /** - * @brief Used for copy-back notification - */ - class IFunctionCopybackReader - { - public: - /** - * @brief Called before an array is copied back. - * - * @param param Parameter index. - * @param cells Number of cells in the array. - * @param source_addr Source address in the plugin that will be copied. - * @param orig_addr Destination addres in plugin that will be overwritten. - * @param flags Copy flags. - * @return True to copy back, false otherwise. - */ - virtual bool OnCopybackArray(unsigned int param, - unsigned int cells, - cell_t *source_addr, - cell_t *orig_addr, - int flags) =0; - }; - /** * @brief Encapsulates a function call in a plugin. * NOTE: Function calls must be atomic to one execution context. @@ -143,7 +114,7 @@ namespace SourceMod * @param reader Copy-back listener. NULL to specify * @return Error code, if any. */ - virtual int Execute(cell_t *result, IFunctionCopybackReader *reader) =0; + virtual int Execute(cell_t *result) =0; /** * @brief Executes the function with the given parameter array. @@ -172,28 +143,6 @@ namespace SourceMod * @return Address, or NULL if invalid parameter specified. */ virtual cell_t *GetAddressOfPushedParam(unsigned int param) =0; - -#if 0 - /** - * @brief Clones the function object. This can be used to maintain a private copy. - * The copy retains no push states and must be freeed with ReleaseCopy(). - */ - virtual IPluginFunction *Copy() =0; - - /** - * @brief If this object is a clone, this function must be called to destroy it. - */ - virtual void ReleaseCopy() =0; - - /** - * @brief Returns original function pointer, if any. - * Note: IsCopyOf() will return the original non-copy, even if used - * from a copy. - * - * @return The original object that this was sourced from. - */ - virtual IPluginFunction *IsCopyOf() =0; -#endif }; }; diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index 536548da..6fe6cae6 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -40,7 +40,7 @@ - - - - - - - - - - @@ -449,10 +429,24 @@ + + + + + + + + diff --git a/core/sourcemod.cpp b/core/sourcemod.cpp index 2d910762..126d805d 100644 --- a/core/sourcemod.cpp +++ b/core/sourcemod.cpp @@ -124,7 +124,7 @@ bool SourceModBase::InitializeSourceMod(char *error, size_t err_max, bool late) fwd->AddFunction(func); fwd->AddFunction(func2); fwd->PushCell(1); - fwd->PushCellByRef(&val, SMFUNC_COPYBACK_ALWAYS); + fwd->PushCellByRef(&val, 0); fwd->Execute(&result, NULL); g_PluginMngr.UnloadPlugin(pPlugin); diff --git a/core/systems/CFunction.cpp b/core/systems/CFunction.cpp index 851f51be..66e487cd 100644 --- a/core/systems/CFunction.cpp +++ b/core/systems/CFunction.cpp @@ -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; iflags = (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; } diff --git a/core/systems/CFunction.h b/core/systems/CFunction.h index f9b50180..58fb0f40 100644 --- a/core/systems/CFunction.h +++ b/core/systems/CFunction.h @@ -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(); diff --git a/core/systems/ForwardSys.cpp b/core/systems/ForwardSys.cpp index 99ecdf51..833d5321 100644 --- a/core/systems/ForwardSys.cpp +++ b/core/systems/ForwardSys.cpp @@ -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; iGetAddressOfPushedParam(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= 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(¶m->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 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; } diff --git a/core/systems/ForwardSys.h b/core/systems/ForwardSys.h index 17b55a61..31a4089d 100644 --- a/core/systems/ForwardSys.h +++ b/core/systems/ForwardSys.h @@ -14,25 +14,30 @@ typedef List::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 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 m_NextStack; - List m_AddQueue; - NextCallInfo m_CopyBacks; }; #endif //_INCLUDE_SOURCEMOD_FORWARDSYSTEM_H_ diff --git a/sourcepawn/include/sp_vm_api.h b/sourcepawn/include/sp_vm_api.h index 796a5a31..e4133cc7 100644 --- a/sourcepawn/include/sp_vm_api.h +++ b/sourcepawn/include/sp_vm_api.h @@ -216,10 +216,10 @@ namespace SourcePawn * Converts a physical string to a local address. * * @param local_addr Local address in plugin. - * @param chars Number of chars to write, including NULL terminator. + * @param bytes Number of chars to write, including NULL terminator. * @param source Source string to copy. */ - virtual int StringToLocal(cell_t local_addr, size_t chars, const char *source) =0; + virtual int StringToLocal(cell_t local_addr, size_t bytes, const char *source) =0; /** * Converts a physical UTF-8 string to a local address. @@ -229,9 +229,12 @@ namespace SourcePawn * @param local_addr Local address in plugin. * @param maxbytes Number of bytes to write, including NULL terminator. * @param source Source string to copy. - * @param wrtnbytes Optionally filled with the number of written bytes. + * @param wrtnbytes Optionally set to the number of actual bytes written. */ - virtual int StringToLocalUTF8(cell_t local_addr, size_t maxbytes, const char *source, size_t *wrtnbytes) =0; + virtual int StringToLocalUTF8(cell_t local_addr, + size_t maxbytes, + const char *source, + size_t *wrtnbytes) =0; /** * Pushes a cell onto the stack. Increases the parameter count by one.