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