core/systems/CFunction.cpp
author Borja Ferrer <faluco@alliedmods.net>
Wed Dec 06 14:52:11 2006 +0000 (2006-12-06)
changeset 192 dee91851dcd4
parent 188 8951baf7cb3c
child 209 fae1894d884c
permissions -rw-r--r--
rewritten PushStringEx in Forward and Function systems
fixed PushCellByRef and PushFloatByRef in the varargs case where it wouldn't set the pushed type
fixed the BindNatives functions not setting the BOUND flag thus making the JIT not exec the natives
done the rest of tests with forwards, only left to do string varargs
dvander@177
     1
#include <stdio.h>
dvander@177
     2
#include "PluginSys.h"
dvander@177
     3
dvander@177
     4
/********************
dvander@177
     5
* FUNCTION CALLING *
dvander@177
     6
********************/
dvander@177
     7
dvander@177
     8
void CFunction::Set(funcid_t funcid, CPlugin *plugin)
dvander@177
     9
{
dvander@177
    10
	m_funcid = funcid;
dvander@177
    11
	m_pPlugin = plugin;
dvander@177
    12
	m_curparam = 0;
dvander@177
    13
	m_errorstate = SP_ERROR_NONE;
dvander@177
    14
}
dvander@177
    15
dvander@177
    16
int CFunction::CallFunction(const cell_t *params, unsigned int num_params, cell_t *result)
dvander@177
    17
{
dvander@177
    18
	IPluginContext *ctx = m_pPlugin->m_ctx_current.base;
dvander@177
    19
dvander@177
    20
	while (num_params--)
dvander@177
    21
	{
dvander@177
    22
		ctx->PushCell(params[num_params]);
dvander@177
    23
	}
dvander@177
    24
dvander@177
    25
	return ctx->Execute(m_funcid, result);
dvander@177
    26
}
dvander@177
    27
dvander@177
    28
IPlugin *CFunction::GetParentPlugin()
dvander@177
    29
{
dvander@177
    30
	return m_pPlugin;
dvander@177
    31
}
dvander@177
    32
dvander@177
    33
CFunction::CFunction(funcid_t funcid, CPlugin *plugin) : 
dvander@177
    34
	m_funcid(funcid), m_pPlugin(plugin), m_curparam(0), 
dvander@177
    35
	m_errorstate(SP_ERROR_NONE)
dvander@177
    36
{
dvander@177
    37
}
dvander@177
    38
dvander@177
    39
int CFunction::PushCell(cell_t cell)
dvander@177
    40
{
dvander@177
    41
	if (m_curparam >= SP_MAX_EXEC_PARAMS)
dvander@177
    42
	{
dvander@177
    43
		return SetError(SP_ERROR_PARAMS_MAX);
dvander@177
    44
	}
dvander@177
    45
dvander@177
    46
	m_info[m_curparam].marked = false;
dvander@177
    47
	m_params[m_curparam] = cell;
dvander@177
    48
	m_curparam++;
dvander@177
    49
dvander@177
    50
	return SP_ERROR_NONE;
dvander@177
    51
}
dvander@177
    52
dvander@177
    53
int CFunction::PushCellByRef(cell_t *cell, int flags)
dvander@177
    54
{
dvander@177
    55
	if (m_curparam >= SP_MAX_EXEC_PARAMS)
dvander@177
    56
	{
dvander@177
    57
		return SetError(SP_ERROR_PARAMS_MAX);
dvander@177
    58
	}
dvander@177
    59
dvander@177
    60
	return PushArray(cell, 1, NULL, flags);
dvander@177
    61
}
dvander@177
    62
dvander@177
    63
int CFunction::PushFloat(float number)
dvander@177
    64
{
dvander@177
    65
	cell_t val = *(cell_t *)&number;
dvander@177
    66
dvander@177
    67
	return PushCell(val);
dvander@177
    68
}
dvander@177
    69
dvander@177
    70
int CFunction::PushFloatByRef(float *number, int flags)
dvander@177
    71
{
dvander@177
    72
	return PushCellByRef((cell_t *)number, flags);
dvander@177
    73
}
dvander@177
    74
dvander@177
    75
int CFunction::PushArray(cell_t *inarray, unsigned int cells, cell_t **phys_addr, int copyback)
dvander@177
    76
{
dvander@177
    77
	if (m_curparam >= SP_MAX_EXEC_PARAMS)
dvander@177
    78
	{
dvander@177
    79
		return SetError(SP_ERROR_PARAMS_MAX);
dvander@177
    80
	}
dvander@177
    81
dvander@177
    82
	IPluginContext *ctx = m_pPlugin->m_ctx_current.base;
dvander@177
    83
	ParamInfo *info = &m_info[m_curparam];
dvander@177
    84
	int err;
dvander@177
    85
dvander@177
    86
	if ((err=ctx->HeapAlloc(cells, &info->local_addr, &info->phys_addr)) != SP_ERROR_NONE)
dvander@177
    87
	{
dvander@177
    88
		return SetError(err);
dvander@177
    89
	}
dvander@177
    90
dvander@183
    91
	info->flags = inarray ? copyback : 0;
dvander@177
    92
	info->marked = true;
dvander@177
    93
	info->size = cells;
dvander@177
    94
	m_params[m_curparam] = info->local_addr;
dvander@177
    95
	m_curparam++;
dvander@177
    96
dvander@177
    97
	if (inarray)
dvander@177
    98
	{
dvander@183
    99
		memcpy(info->phys_addr, inarray, sizeof(cell_t) * cells);
dvander@177
   100
		info->orig_addr = inarray;
dvander@177
   101
	} else {
dvander@177
   102
		info->orig_addr = info->phys_addr;
dvander@177
   103
	}
dvander@177
   104
dvander@177
   105
	if (phys_addr)
dvander@177
   106
	{
dvander@177
   107
		*phys_addr = info->phys_addr;
dvander@177
   108
	}
dvander@177
   109
dvander@177
   110
	return true;
dvander@177
   111
}
dvander@177
   112
dvander@177
   113
int CFunction::PushString(const char *string)
dvander@177
   114
{
faluco@192
   115
	return _PushString(string, SP_STRING_COPY, 0, strlen(string)+1);
dvander@177
   116
}
dvander@177
   117
faluco@192
   118
int CFunction::PushStringEx(char *buffer, size_t length, int sz_flags, int cp_flags)
dvander@177
   119
{
faluco@192
   120
	return _PushString(buffer, sz_flags, cp_flags, length);
dvander@177
   121
}
dvander@177
   122
faluco@192
   123
int CFunction::_PushString(const char *string, int sz_flags, int cp_flags, size_t len)
dvander@177
   124
{
dvander@177
   125
	if (m_curparam >= SP_MAX_EXEC_PARAMS)
dvander@177
   126
	{
dvander@177
   127
		return SetError(SP_ERROR_PARAMS_MAX);
dvander@177
   128
	}
dvander@177
   129
dvander@177
   130
	IPluginContext *base = m_pPlugin->m_ctx_current.base;
dvander@177
   131
	ParamInfo *info = &m_info[m_curparam];
faluco@192
   132
	size_t cells = (len + sizeof(cell_t) - 1) / sizeof(cell_t);
dvander@177
   133
	int err;
dvander@177
   134
dvander@177
   135
	if ((err=base->HeapAlloc(cells, &info->local_addr, &info->phys_addr)) != SP_ERROR_NONE)
dvander@177
   136
	{
dvander@177
   137
		return SetError(err);
dvander@177
   138
	}
dvander@177
   139
dvander@177
   140
	info->marked = true;
dvander@177
   141
	m_params[m_curparam] = info->local_addr;
dvander@177
   142
	m_curparam++;	/* Prevent a leak */
dvander@177
   143
faluco@192
   144
	if (!(sz_flags & SP_STRING_COPY))
dvander@177
   145
	{
faluco@192
   146
		goto skip_localtostr;
dvander@177
   147
	}
dvander@177
   148
faluco@192
   149
	if (sz_flags & SP_STRING_UTF8)
faluco@192
   150
	{
faluco@192
   151
		if ((err=base->StringToLocalUTF8(info->local_addr, len, string, NULL)) != SP_ERROR_NONE)
faluco@192
   152
		{
faluco@192
   153
			return SetError(err);
faluco@192
   154
		}
faluco@192
   155
	} else {
faluco@192
   156
		if ((err=base->StringToLocal(info->local_addr, len, string)) != SP_ERROR_NONE)
faluco@192
   157
		{
faluco@192
   158
			return SetError(err);
faluco@192
   159
		}
faluco@192
   160
	}
faluco@192
   161
faluco@192
   162
skip_localtostr:
faluco@192
   163
	info->flags = cp_flags;
dvander@177
   164
	info->orig_addr = (cell_t *)string;
dvander@177
   165
	info->size = cells;
dvander@177
   166
dvander@177
   167
	return SP_ERROR_NONE;
dvander@177
   168
}
dvander@177
   169
dvander@177
   170
void CFunction::Cancel()
dvander@177
   171
{
dvander@177
   172
	if (!m_curparam)
dvander@177
   173
	{
dvander@177
   174
		return;
dvander@177
   175
	}
dvander@177
   176
dvander@177
   177
	IPluginContext *base = m_pPlugin->m_ctx_current.base;
dvander@177
   178
dvander@177
   179
	while (m_curparam--)
dvander@177
   180
	{
dvander@177
   181
		if (m_info[m_curparam].marked)
dvander@177
   182
		{
dvander@177
   183
			base->HeapRelease(m_info[m_curparam].local_addr);
dvander@177
   184
			m_info[m_curparam].marked = false;
dvander@177
   185
		}
dvander@177
   186
	}
dvander@177
   187
dvander@177
   188
	m_errorstate = SP_ERROR_NONE;
dvander@177
   189
}
dvander@177
   190
dvander@183
   191
int CFunction::Execute(cell_t *result)
dvander@177
   192
{
dvander@177
   193
	int err;
dvander@177
   194
	if (m_errorstate != SP_ERROR_NONE)
dvander@177
   195
	{
dvander@177
   196
		err = m_errorstate;
dvander@177
   197
		Cancel();
dvander@177
   198
		return err;
dvander@177
   199
	}
dvander@177
   200
dvander@177
   201
	//This is for re-entrancy!
dvander@177
   202
	cell_t temp_params[SP_MAX_EXEC_PARAMS];
dvander@177
   203
	ParamInfo temp_info[SP_MAX_EXEC_PARAMS];
dvander@177
   204
	unsigned int numparams = m_curparam;
dvander@177
   205
	bool docopies = true;
dvander@177
   206
dvander@177
   207
	if (numparams)
dvander@177
   208
	{
dvander@177
   209
		//Save the info locally, then reset it for re-entrant calls.
dvander@177
   210
		memcpy(temp_params, m_params, numparams * sizeof(cell_t));
dvander@177
   211
		memcpy(temp_info, m_info, numparams * sizeof(ParamInfo));
dvander@177
   212
	}
dvander@177
   213
	m_curparam = 0;
dvander@177
   214
dvander@177
   215
	if ((err = CallFunction(temp_params, numparams, result)) != SP_ERROR_NONE)
dvander@177
   216
	{
dvander@177
   217
		docopies = false;
dvander@177
   218
	}
dvander@177
   219
dvander@177
   220
	IPluginContext *base = m_pPlugin->m_ctx_current.base;
dvander@177
   221
dvander@177
   222
	while (numparams--)
dvander@177
   223
	{
dvander@177
   224
		if (!temp_info[numparams].marked)
dvander@177
   225
		{
dvander@177
   226
			continue;
dvander@177
   227
		}
dvander@177
   228
		if (docopies && temp_info[numparams].flags)
dvander@177
   229
		{
dvander@177
   230
			if (temp_info[numparams].orig_addr)
dvander@177
   231
			{
dvander@180
   232
				if (temp_info[numparams].size == 1)
dvander@180
   233
				{
dvander@180
   234
					*temp_info[numparams].orig_addr = *temp_info[numparams].phys_addr;
dvander@180
   235
				} else {
dvander@180
   236
					memcpy(temp_info[numparams].orig_addr, 
dvander@180
   237
							temp_info[numparams].phys_addr, 
dvander@180
   238
							temp_info[numparams].size * sizeof(cell_t));
dvander@180
   239
				}
dvander@177
   240
			}
dvander@177
   241
		}
dvander@181
   242
		base->HeapPop(temp_info[numparams].local_addr);
dvander@177
   243
		temp_info[numparams].marked = false;
dvander@177
   244
	}
dvander@177
   245
dvander@177
   246
	return err;
dvander@177
   247
}
dvander@177
   248
dvander@177
   249
cell_t *CFunction::GetAddressOfPushedParam(unsigned int param)
dvander@177
   250
{
dvander@177
   251
	if (m_errorstate != SP_ERROR_NONE
dvander@177
   252
		|| param >= m_curparam
dvander@177
   253
		|| !m_info[param].marked)
dvander@177
   254
	{
dvander@177
   255
		return NULL;
dvander@177
   256
	}
dvander@177
   257
dvander@177
   258
	return m_info[param].phys_addr;
dvander@177
   259
}