core/vm/sp_vm_function.cpp
author Scott Ehlert <ds@alliedmods.net>
Wed Mar 07 18:37:41 2007 +0000 (2007-03-07)
changeset 585 6d3a0ec864fe
parent 584 1b10d3504e9e
child 586 1e73cb333b19
permissions -rw-r--r--
Reverted change where flags param was removed on PushCellByRef and PushFloatByRef. Instead set the param to a default value of SM_PARAM_COPYBACK. (DS, how dare you!)
dvander@371
     1
/**
dvander@371
     2
 * ================================================================
dvander@371
     3
 * SourcePawn (C)2004-2007 AlliedModders LLC.  All rights reserved.
dvander@371
     4
 * ================================================================
dvander@371
     5
 *
dvander@371
     6
 * This file is not open source and may not be copied without explicit
dvander@371
     7
 * written permission of AlliedModders LLC.  This file may not be redistributed 
dvander@371
     8
 * in whole or significant part.
dvander@371
     9
 * For information, see LICENSE.txt or http://www.sourcemod.net/license.php
dvander@371
    10
 *
dvander@371
    11
 * Version: $Id$
dvander@371
    12
 */
dvander@371
    13
dvander@327
    14
#include <stdio.h>
dvander@351
    15
#include <string.h>
dvander@327
    16
#include "PluginSys.h"
dvander@327
    17
dvander@327
    18
/********************
dvander@327
    19
* FUNCTION CALLING *
dvander@327
    20
********************/
dvander@327
    21
dvander@348
    22
void CFunction::Set(uint32_t code_addr, IPluginContext *plugin)
dvander@327
    23
{
dvander@348
    24
	m_codeaddr = code_addr;
dvander@327
    25
	m_pContext = plugin;
dvander@327
    26
	m_curparam = 0;
dvander@327
    27
	m_errorstate = SP_ERROR_NONE;
dvander@502
    28
	m_Invalid = false;
dvander@525
    29
	m_pCtx = plugin ? plugin->GetContext() : NULL;
dvander@525
    30
}
dvander@525
    31
dvander@525
    32
bool CFunction::IsRunnable()
dvander@525
    33
{
dvander@525
    34
	return ((m_pCtx->flags & SPFLAG_PLUGIN_PAUSED) != SPFLAG_PLUGIN_PAUSED);
dvander@327
    35
}
dvander@327
    36
dvander@327
    37
int CFunction::CallFunction(const cell_t *params, unsigned int num_params, cell_t *result)
dvander@327
    38
{
dvander@525
    39
	if (!IsRunnable())
dvander@525
    40
	{
dvander@525
    41
		return SP_ERROR_NOT_RUNNABLE;
dvander@525
    42
	}
dvander@525
    43
dvander@327
    44
	while (num_params--)
dvander@327
    45
	{
dvander@327
    46
		m_pContext->PushCell(params[num_params]);
dvander@327
    47
	}
dvander@327
    48
dvander@348
    49
	return m_pContext->Execute(m_codeaddr, result);
dvander@327
    50
}
dvander@327
    51
dvander@327
    52
IPluginContext *CFunction::GetParentContext()
dvander@327
    53
{
dvander@327
    54
	return m_pContext;
dvander@327
    55
}
dvander@327
    56
dvander@348
    57
CFunction::CFunction(uint32_t code_addr, IPluginContext *plugin) : 
dvander@348
    58
	m_codeaddr(code_addr), m_pContext(plugin), m_curparam(0), 
dvander@327
    59
	m_errorstate(SP_ERROR_NONE)
dvander@327
    60
{
dvander@502
    61
	m_Invalid = false;
dvander@525
    62
	if (plugin)
dvander@525
    63
	{
dvander@525
    64
		m_pCtx = plugin->GetContext();
dvander@525
    65
	}
dvander@327
    66
}
dvander@327
    67
dvander@327
    68
int CFunction::PushCell(cell_t cell)
dvander@327
    69
{
dvander@327
    70
	if (m_curparam >= SP_MAX_EXEC_PARAMS)
dvander@327
    71
	{
dvander@327
    72
		return SetError(SP_ERROR_PARAMS_MAX);
dvander@327
    73
	}
dvander@327
    74
dvander@327
    75
	m_info[m_curparam].marked = false;
dvander@327
    76
	m_params[m_curparam] = cell;
dvander@327
    77
	m_curparam++;
dvander@327
    78
dvander@327
    79
	return SP_ERROR_NONE;
dvander@327
    80
}
dvander@327
    81
ds@585
    82
int CFunction::PushCellByRef(cell_t *cell, int flags)
dvander@327
    83
{
dvander@327
    84
	if (m_curparam >= SP_MAX_EXEC_PARAMS)
dvander@327
    85
	{
dvander@327
    86
		return SetError(SP_ERROR_PARAMS_MAX);
dvander@327
    87
	}
dvander@327
    88
ds@585
    89
	return PushArray(cell, 1, NULL, flags);
dvander@327
    90
}
dvander@327
    91
dvander@327
    92
int CFunction::PushFloat(float number)
dvander@327
    93
{
dvander@327
    94
	cell_t val = *(cell_t *)&number;
dvander@327
    95
dvander@327
    96
	return PushCell(val);
dvander@327
    97
}
dvander@327
    98
ds@585
    99
int CFunction::PushFloatByRef(float *number, int flags)
dvander@327
   100
{
ds@585
   101
	return PushCellByRef((cell_t *)number, flags);
dvander@327
   102
}
dvander@327
   103
dvander@327
   104
int CFunction::PushArray(cell_t *inarray, unsigned int cells, cell_t **phys_addr, int copyback)
dvander@327
   105
{
dvander@327
   106
	if (m_curparam >= SP_MAX_EXEC_PARAMS)
dvander@327
   107
	{
dvander@327
   108
		return SetError(SP_ERROR_PARAMS_MAX);
dvander@327
   109
	}
dvander@327
   110
dvander@327
   111
	ParamInfo *info = &m_info[m_curparam];
dvander@327
   112
	int err;
dvander@327
   113
dvander@327
   114
	if ((err=m_pContext->HeapAlloc(cells, &info->local_addr, &info->phys_addr)) != SP_ERROR_NONE)
dvander@327
   115
	{
dvander@327
   116
		return SetError(err);
dvander@327
   117
	}
dvander@327
   118
dvander@327
   119
	info->flags = inarray ? copyback : 0;
dvander@327
   120
	info->marked = true;
dvander@327
   121
	info->size = cells * sizeof(cell_t);
dvander@327
   122
	m_params[m_curparam] = info->local_addr;
dvander@327
   123
	m_curparam++;
dvander@327
   124
dvander@327
   125
	if (inarray)
dvander@327
   126
	{
dvander@327
   127
		memcpy(info->phys_addr, inarray, sizeof(cell_t) * cells);
dvander@327
   128
		info->orig_addr = inarray;
dvander@327
   129
	} else {
dvander@327
   130
		info->orig_addr = info->phys_addr;
dvander@327
   131
	}
dvander@327
   132
dvander@327
   133
	if (phys_addr)
dvander@327
   134
	{
dvander@327
   135
		*phys_addr = info->phys_addr;
dvander@327
   136
	}
dvander@327
   137
dvander@327
   138
	return true;
dvander@327
   139
}
dvander@327
   140
dvander@327
   141
int CFunction::PushString(const char *string)
dvander@327
   142
{
dvander@327
   143
	return _PushString(string, SM_PARAM_STRING_COPY, 0, strlen(string)+1);
dvander@327
   144
}
dvander@327
   145
dvander@327
   146
int CFunction::PushStringEx(char *buffer, size_t length, int sz_flags, int cp_flags)
dvander@327
   147
{
dvander@327
   148
	return _PushString(buffer, sz_flags, cp_flags, length);
dvander@327
   149
}
dvander@327
   150
dvander@327
   151
int CFunction::_PushString(const char *string, int sz_flags, int cp_flags, size_t len)
dvander@327
   152
{
dvander@327
   153
	if (m_curparam >= SP_MAX_EXEC_PARAMS)
dvander@327
   154
	{
dvander@327
   155
		return SetError(SP_ERROR_PARAMS_MAX);
dvander@327
   156
	}
dvander@327
   157
dvander@327
   158
	ParamInfo *info = &m_info[m_curparam];
dvander@327
   159
	size_t cells = (len + sizeof(cell_t) - 1) / sizeof(cell_t);
dvander@327
   160
	int err;
dvander@327
   161
dvander@327
   162
	if ((err=m_pContext->HeapAlloc(cells, &info->local_addr, &info->phys_addr)) != SP_ERROR_NONE)
dvander@327
   163
	{
dvander@327
   164
		return SetError(err);
dvander@327
   165
	}
dvander@327
   166
dvander@327
   167
	info->marked = true;
dvander@327
   168
	m_params[m_curparam] = info->local_addr;
dvander@327
   169
	m_curparam++;	/* Prevent a leak */
dvander@327
   170
dvander@327
   171
	if (!(sz_flags & SM_PARAM_STRING_COPY))
dvander@327
   172
	{
dvander@327
   173
		goto skip_localtostr;
dvander@327
   174
	}
dvander@327
   175
dvander@327
   176
	if (sz_flags & SM_PARAM_STRING_UTF8)
dvander@327
   177
	{
dvander@327
   178
		if ((err=m_pContext->StringToLocalUTF8(info->local_addr, len, string, NULL)) != SP_ERROR_NONE)
dvander@327
   179
		{
dvander@327
   180
			return SetError(err);
dvander@327
   181
		}
dvander@327
   182
	} else {
dvander@327
   183
		if ((err=m_pContext->StringToLocal(info->local_addr, len, string)) != SP_ERROR_NONE)
dvander@327
   184
		{
dvander@327
   185
			return SetError(err);
dvander@327
   186
		}
dvander@327
   187
	}
dvander@327
   188
dvander@327
   189
skip_localtostr:
dvander@327
   190
	info->flags = cp_flags;
dvander@327
   191
	info->orig_addr = (cell_t *)string;
dvander@327
   192
	info->size = len;
dvander@327
   193
dvander@327
   194
	return SP_ERROR_NONE;
dvander@327
   195
}
dvander@327
   196
dvander@327
   197
void CFunction::Cancel()
dvander@327
   198
{
dvander@327
   199
	if (!m_curparam)
dvander@327
   200
	{
dvander@327
   201
		return;
dvander@327
   202
	}
dvander@327
   203
dvander@327
   204
	while (m_curparam--)
dvander@327
   205
	{
dvander@327
   206
		if (m_info[m_curparam].marked)
dvander@327
   207
		{
dvander@327
   208
			m_pContext->HeapRelease(m_info[m_curparam].local_addr);
dvander@327
   209
			m_info[m_curparam].marked = false;
dvander@327
   210
		}
dvander@327
   211
	}
dvander@327
   212
dvander@327
   213
	m_errorstate = SP_ERROR_NONE;
dvander@327
   214
}
dvander@327
   215
dvander@327
   216
int CFunction::Execute(cell_t *result)
dvander@327
   217
{
dvander@327
   218
	int err;
dvander@525
   219
	if (!IsRunnable())
dvander@525
   220
	{
dvander@525
   221
		m_errorstate = SP_ERROR_NOT_RUNNABLE;
dvander@525
   222
	}
dvander@327
   223
	if (m_errorstate != SP_ERROR_NONE)
dvander@327
   224
	{
dvander@327
   225
		err = m_errorstate;
dvander@327
   226
		Cancel();
dvander@327
   227
		return err;
dvander@327
   228
	}
dvander@327
   229
dvander@327
   230
	//This is for re-entrancy!
dvander@327
   231
	cell_t temp_params[SP_MAX_EXEC_PARAMS];
dvander@327
   232
	ParamInfo temp_info[SP_MAX_EXEC_PARAMS];
dvander@327
   233
	unsigned int numparams = m_curparam;
dvander@327
   234
	bool docopies = true;
dvander@327
   235
dvander@327
   236
	if (numparams)
dvander@327
   237
	{
dvander@327
   238
		//Save the info locally, then reset it for re-entrant calls.
dvander@327
   239
		memcpy(temp_params, m_params, numparams * sizeof(cell_t));
dvander@327
   240
		memcpy(temp_info, m_info, numparams * sizeof(ParamInfo));
dvander@327
   241
	}
dvander@327
   242
	m_curparam = 0;
dvander@327
   243
dvander@327
   244
	if ((err = CallFunction(temp_params, numparams, result)) != SP_ERROR_NONE)
dvander@327
   245
	{
dvander@327
   246
		docopies = false;
dvander@327
   247
	}
dvander@327
   248
dvander@327
   249
	while (numparams--)
dvander@327
   250
	{
dvander@327
   251
		if (!temp_info[numparams].marked)
dvander@327
   252
		{
dvander@327
   253
			continue;
dvander@327
   254
		}
dvander@327
   255
		if (docopies && temp_info[numparams].flags)
dvander@327
   256
		{
dvander@327
   257
			if (temp_info[numparams].orig_addr)
dvander@327
   258
			{
dvander@327
   259
				if (temp_info[numparams].size == sizeof(cell_t))
dvander@327
   260
				{
dvander@327
   261
					*temp_info[numparams].orig_addr = *temp_info[numparams].phys_addr;
dvander@327
   262
				} else {
dvander@327
   263
					memcpy(temp_info[numparams].orig_addr, 
dvander@327
   264
							temp_info[numparams].phys_addr, 
dvander@327
   265
							temp_info[numparams].size);
dvander@327
   266
				}
dvander@327
   267
			}
dvander@327
   268
		}
dvander@327
   269
		m_pContext->HeapPop(temp_info[numparams].local_addr);
dvander@327
   270
		temp_info[numparams].marked = false;
dvander@327
   271
	}
dvander@327
   272
dvander@327
   273
	return err;
dvander@327
   274
}
dvander@327
   275
dvander@327
   276
cell_t *CFunction::GetAddressOfPushedParam(unsigned int param)
dvander@327
   277
{
dvander@327
   278
	if (m_errorstate != SP_ERROR_NONE
dvander@327
   279
		|| param >= m_curparam
dvander@327
   280
		|| !m_info[param].marked)
dvander@327
   281
	{
dvander@327
   282
		return NULL;
dvander@327
   283
	}
dvander@327
   284
dvander@327
   285
	return m_info[param].phys_addr;
dvander@327
   286
}