sourcepawn/jit/sp_vm_function.cpp
author David Anderson <dvander@alliedmods.net>
Mon Jul 07 04:56:29 2008 +0000 (2008-07-07)
branchrefac-jit
changeset 2171 0885b66fcf81
parent 2169 d1e225d141fb
child 2188 24b170ea6ce7
permissions -rw-r--r--
refac-jit is almost done i think, next comes getting core compatible.
dvander@2168
     1
/**
dvander@2168
     2
 * vim: set ts=4 :
dvander@2168
     3
 * =============================================================================
dvander@2168
     4
 * SourcePawn
dvander@2168
     5
 * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
dvander@2168
     6
 * =============================================================================
dvander@2168
     7
 *
dvander@2168
     8
 * This program is free software; you can redistribute it and/or modify it under
dvander@2168
     9
 * the terms of the GNU General Public License, version 3.0, as published by the
dvander@2168
    10
 * Free Software Foundation.
dvander@2168
    11
 * 
dvander@2168
    12
 * This program is distributed in the hope that it will be useful, but WITHOUT
dvander@2168
    13
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
dvander@2168
    14
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
dvander@2168
    15
 * details.
dvander@2168
    16
 *
dvander@2168
    17
 * You should have received a copy of the GNU General Public License along with
dvander@2168
    18
 * this program.  If not, see <http://www.gnu.org/licenses/>.
dvander@2168
    19
 *
dvander@2168
    20
 * As a special exception, AlliedModders LLC gives you permission to link the
dvander@2168
    21
 * code of this program (as well as its derivative works) to "Half-Life 2," the
dvander@2168
    22
 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
dvander@2168
    23
 * by the Valve Corporation.  You must obey the GNU General Public License in
dvander@2168
    24
 * all respects for all other code used.  Additionally, AlliedModders LLC grants
dvander@2168
    25
 * this exception to all derivative works.  AlliedModders LLC defines further
dvander@2168
    26
 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
dvander@2168
    27
 * or <http://www.sourcemod.net/license.php>.
dvander@2168
    28
 *
dvander@2168
    29
 * Version: $Id$
dvander@2168
    30
 */
dvander@2168
    31
dvander@2168
    32
#include <stdio.h>
dvander@2168
    33
#include <string.h>
dvander@2168
    34
#include "sp_vm_function.h"
dvander@2171
    35
#include "BaseRuntime.h"
dvander@2168
    36
dvander@2168
    37
/********************
dvander@2168
    38
* FUNCTION CALLING *
dvander@2168
    39
********************/
dvander@2168
    40
dvander@2171
    41
void CFunction::Set(uint32_t code_addr, BaseRuntime *runtime, funcid_t fnid, uint32_t pub_id)
dvander@2168
    42
{
dvander@2168
    43
	m_codeaddr = code_addr;
dvander@2171
    44
	m_pRuntime = runtime;
dvander@2168
    45
	m_curparam = 0;
dvander@2168
    46
	m_errorstate = SP_ERROR_NONE;
dvander@2168
    47
	m_Invalid = false;
dvander@2171
    48
	m_FnId = fnid;
dvander@2168
    49
}
dvander@2168
    50
dvander@2168
    51
bool CFunction::IsRunnable()
dvander@2168
    52
{
dvander@2171
    53
	return m_pRuntime->IsPaused();
dvander@2168
    54
}
dvander@2168
    55
dvander@2168
    56
int CFunction::CallFunction(const cell_t *params, unsigned int num_params, cell_t *result)
dvander@2168
    57
{
dvander@2171
    58
	return CallFunction(m_pRuntime->GetDefaultContext(), params, num_params, result);
dvander@2171
    59
}
dvander@2168
    60
dvander@2171
    61
int CFunction::CallFunction(IPluginContext *pContext, const cell_t *params, unsigned int num_params, cell_t *result)
dvander@2171
    62
{
dvander@2171
    63
	return pContext->Execute(this, params, num_params, result);
dvander@2168
    64
}
dvander@2168
    65
dvander@2168
    66
IPluginContext *CFunction::GetParentContext()
dvander@2168
    67
{
dvander@2171
    68
	return m_pRuntime->GetDefaultContext();
dvander@2168
    69
}
dvander@2168
    70
dvander@2171
    71
CFunction::CFunction(uint32_t code_addr, BaseRuntime *runtime, funcid_t id, uint32_t pub_id) : 
dvander@2171
    72
	m_codeaddr(code_addr), m_curparam(0), m_errorstate(SP_ERROR_NONE), m_FnId(id)
dvander@2168
    73
{
dvander@2168
    74
	m_Invalid = false;
dvander@2171
    75
	m_pRuntime = runtime;
dvander@2168
    76
}
dvander@2168
    77
dvander@2168
    78
int CFunction::PushCell(cell_t cell)
dvander@2168
    79
{
dvander@2168
    80
	if (m_curparam >= SP_MAX_EXEC_PARAMS)
dvander@2168
    81
	{
dvander@2168
    82
		return SetError(SP_ERROR_PARAMS_MAX);
dvander@2168
    83
	}
dvander@2168
    84
dvander@2168
    85
	m_info[m_curparam].marked = false;
dvander@2168
    86
	m_params[m_curparam] = cell;
dvander@2168
    87
	m_curparam++;
dvander@2168
    88
dvander@2168
    89
	return SP_ERROR_NONE;
dvander@2168
    90
}
dvander@2168
    91
dvander@2168
    92
int CFunction::PushCellByRef(cell_t *cell, int flags)
dvander@2168
    93
{
dvander@2168
    94
	return PushArray(cell, 1, flags);
dvander@2168
    95
}
dvander@2168
    96
dvander@2168
    97
int CFunction::PushFloat(float number)
dvander@2168
    98
{
dvander@2168
    99
	cell_t val = *(cell_t *)&number;
dvander@2168
   100
dvander@2168
   101
	return PushCell(val);
dvander@2168
   102
}
dvander@2168
   103
dvander@2168
   104
int CFunction::PushFloatByRef(float *number, int flags)
dvander@2168
   105
{
dvander@2168
   106
	return PushCellByRef((cell_t *)number, flags);
dvander@2168
   107
}
dvander@2168
   108
dvander@2168
   109
int CFunction::PushArray(cell_t *inarray, unsigned int cells, int copyback)
dvander@2168
   110
{
dvander@2168
   111
	if (m_curparam >= SP_MAX_EXEC_PARAMS)
dvander@2168
   112
	{
dvander@2168
   113
		return SetError(SP_ERROR_PARAMS_MAX);
dvander@2168
   114
	}
dvander@2168
   115
dvander@2168
   116
	ParamInfo *info = &m_info[m_curparam];
dvander@2168
   117
dvander@2168
   118
	info->flags = inarray ? copyback : 0;
dvander@2168
   119
	info->marked = true;
dvander@2168
   120
	info->size = cells;
dvander@2168
   121
	info->str.is_sz = false;
dvander@2168
   122
	info->orig_addr = inarray;
dvander@2168
   123
dvander@2168
   124
	m_curparam++;
dvander@2168
   125
dvander@2168
   126
	return SP_ERROR_NONE;
dvander@2168
   127
}
dvander@2168
   128
dvander@2168
   129
int CFunction::PushString(const char *string)
dvander@2168
   130
{
dvander@2168
   131
	return _PushString(string, SM_PARAM_STRING_COPY, 0, strlen(string)+1);
dvander@2168
   132
}
dvander@2168
   133
dvander@2168
   134
int CFunction::PushStringEx(char *buffer, size_t length, int sz_flags, int cp_flags)
dvander@2168
   135
{
dvander@2168
   136
	return _PushString(buffer, sz_flags, cp_flags, length);
dvander@2168
   137
}
dvander@2168
   138
dvander@2168
   139
int CFunction::_PushString(const char *string, int sz_flags, int cp_flags, size_t len)
dvander@2168
   140
{
dvander@2168
   141
	if (m_curparam >= SP_MAX_EXEC_PARAMS)
dvander@2168
   142
	{
dvander@2168
   143
		return SetError(SP_ERROR_PARAMS_MAX);
dvander@2168
   144
	}
dvander@2168
   145
dvander@2168
   146
	ParamInfo *info = &m_info[m_curparam];
dvander@2168
   147
dvander@2168
   148
	info->marked = true;
dvander@2168
   149
	info->orig_addr = (cell_t *)string;
dvander@2168
   150
	info->flags = cp_flags;
dvander@2168
   151
	info->size = len;
dvander@2168
   152
	info->str.sz_flags = sz_flags;
dvander@2168
   153
	info->str.is_sz = true;
dvander@2168
   154
dvander@2168
   155
	m_curparam++;
dvander@2168
   156
dvander@2168
   157
	return SP_ERROR_NONE;
dvander@2168
   158
}
dvander@2168
   159
dvander@2168
   160
void CFunction::Cancel()
dvander@2168
   161
{
dvander@2168
   162
	if (!m_curparam)
dvander@2168
   163
	{
dvander@2168
   164
		return;
dvander@2168
   165
	}
dvander@2168
   166
dvander@2168
   167
	m_errorstate = SP_ERROR_NONE;
dvander@2168
   168
	m_curparam = 0;
dvander@2168
   169
}
dvander@2168
   170
dvander@2168
   171
int CFunction::Execute(cell_t *result)
dvander@2168
   172
{
dvander@2171
   173
	return Execute(m_pRuntime->GetDefaultContext(), result);
dvander@2171
   174
}
dvander@2171
   175
dvander@2171
   176
int CFunction::Execute(IPluginContext *ctx, cell_t *result)
dvander@2171
   177
{
dvander@2168
   178
	int err = SP_ERROR_NONE;
dvander@2168
   179
dvander@2168
   180
	if (!IsRunnable())
dvander@2168
   181
	{
dvander@2168
   182
		m_errorstate = SP_ERROR_NOT_RUNNABLE;
dvander@2168
   183
	}
dvander@2168
   184
dvander@2168
   185
	if (m_errorstate != SP_ERROR_NONE)
dvander@2168
   186
	{
dvander@2168
   187
		err = m_errorstate;
dvander@2168
   188
		Cancel();
dvander@2168
   189
		return err;
dvander@2168
   190
	}
dvander@2168
   191
dvander@2168
   192
	//This is for re-entrancy!
dvander@2168
   193
	cell_t temp_params[SP_MAX_EXEC_PARAMS];
dvander@2168
   194
	ParamInfo temp_info[SP_MAX_EXEC_PARAMS];
dvander@2168
   195
	unsigned int numparams = m_curparam;
dvander@2168
   196
	unsigned int i;
dvander@2168
   197
	bool docopies = true;
dvander@2168
   198
dvander@2168
   199
	if (numparams)
dvander@2168
   200
	{
dvander@2168
   201
		//Save the info locally, then reset it for re-entrant calls.
dvander@2168
   202
		memcpy(temp_info, m_info, numparams * sizeof(ParamInfo));
dvander@2168
   203
	}
dvander@2168
   204
	m_curparam = 0;
dvander@2168
   205
dvander@2168
   206
	/* Browse the parameters and build arrays */
dvander@2168
   207
	for (i=0; i<numparams; i++)
dvander@2168
   208
	{
dvander@2168
   209
		/* Is this marked as an array? */
dvander@2168
   210
		if (temp_info[i].marked)
dvander@2168
   211
		{
dvander@2168
   212
			if (!temp_info[i].str.is_sz)
dvander@2168
   213
			{
dvander@2168
   214
				/* Allocate a normal/generic array */
dvander@2171
   215
				if ((err=ctx->HeapAlloc(temp_info[i].size, 
dvander@2171
   216
										   &(temp_info[i].local_addr),
dvander@2171
   217
										   &(temp_info[i].phys_addr)))
dvander@2168
   218
					!= SP_ERROR_NONE)
dvander@2168
   219
				{
dvander@2168
   220
					break;
dvander@2168
   221
				}
dvander@2168
   222
				if (temp_info[i].orig_addr)
dvander@2168
   223
				{
dvander@2168
   224
					memcpy(temp_info[i].phys_addr, temp_info[i].orig_addr, sizeof(cell_t) * temp_info[i].size);
dvander@2168
   225
				}
dvander@2168
   226
			}
dvander@2168
   227
			else
dvander@2168
   228
			{
dvander@2168
   229
				/* Calculate cells required for the string */
dvander@2168
   230
				size_t cells = (temp_info[i].size + sizeof(cell_t) - 1) / sizeof(cell_t);
dvander@2168
   231
dvander@2168
   232
				/* Allocate the buffer */
dvander@2171
   233
				if ((err=ctx->HeapAlloc(cells,
dvander@2171
   234
										&(temp_info[i].local_addr),
dvander@2171
   235
										&(temp_info[i].phys_addr)))
dvander@2168
   236
					!= SP_ERROR_NONE)
dvander@2168
   237
				{
dvander@2168
   238
					break;
dvander@2168
   239
				}
dvander@2168
   240
				/* Copy original string if necessary */
dvander@2168
   241
				if ((temp_info[i].str.sz_flags & SM_PARAM_STRING_COPY) && (temp_info[i].orig_addr != NULL))
dvander@2168
   242
				{
dvander@2168
   243
					/* Cut off UTF-8 properly */
dvander@2168
   244
					if (temp_info[i].str.sz_flags & SM_PARAM_STRING_UTF8)
dvander@2168
   245
					{
dvander@2171
   246
						if ((err=ctx->StringToLocalUTF8(temp_info[i].local_addr, 
dvander@2171
   247
															temp_info[i].size, 
dvander@2171
   248
															(const char *)temp_info[i].orig_addr,
dvander@2171
   249
															NULL))
dvander@2168
   250
							!= SP_ERROR_NONE)
dvander@2168
   251
						{
dvander@2168
   252
							break;
dvander@2168
   253
						}
dvander@2168
   254
					}
dvander@2168
   255
					/* Copy a binary blob */
dvander@2168
   256
					else if (temp_info[i].str.sz_flags & SM_PARAM_STRING_BINARY)
dvander@2168
   257
					{
dvander@2168
   258
						memmove(temp_info[i].phys_addr, temp_info[i].orig_addr, temp_info[i].size);
dvander@2168
   259
					}
dvander@2168
   260
					/* Copy ASCII characters */
dvander@2168
   261
					else
dvander@2168
   262
					{
dvander@2171
   263
						if ((err=ctx->StringToLocal(temp_info[i].local_addr,
dvander@2171
   264
														temp_info[i].size,
dvander@2171
   265
														(const char *)temp_info[i].orig_addr))
dvander@2168
   266
							!= SP_ERROR_NONE)
dvander@2168
   267
						{
dvander@2168
   268
							break;
dvander@2168
   269
						}
dvander@2168
   270
					}
dvander@2168
   271
				}
dvander@2168
   272
			} /* End array/string calculation */
dvander@2168
   273
			/* Update the pushed parameter with the byref local address */
dvander@2168
   274
			temp_params[i] = temp_info[i].local_addr;
dvander@2168
   275
		}
dvander@2168
   276
		else
dvander@2168
   277
		{
dvander@2168
   278
			/* Just copy the value normally */
dvander@2168
   279
			temp_params[i] = m_params[i];
dvander@2168
   280
		}
dvander@2168
   281
	}
dvander@2168
   282
dvander@2168
   283
	/* Make the call if we can */
dvander@2168
   284
	if (err == SP_ERROR_NONE)
dvander@2168
   285
	{
dvander@2171
   286
		if ((err = CallFunction(ctx, temp_params, numparams, result)) != SP_ERROR_NONE)
dvander@2168
   287
		{
dvander@2168
   288
			docopies = false;
dvander@2168
   289
		}
dvander@2168
   290
	}
dvander@2168
   291
	else
dvander@2168
   292
	{
dvander@2168
   293
		docopies = false;
dvander@2168
   294
	}
dvander@2168
   295
dvander@2168
   296
	/* i should be equal to the last valid parameter + 1 */
dvander@2168
   297
	while (i--)
dvander@2168
   298
	{
dvander@2168
   299
		if (!temp_info[i].marked)
dvander@2168
   300
		{
dvander@2168
   301
			continue;
dvander@2168
   302
		}
dvander@2168
   303
dvander@2168
   304
		if (docopies && (temp_info[i].flags & SM_PARAM_COPYBACK))
dvander@2168
   305
		{
dvander@2168
   306
			if (temp_info[i].orig_addr)
dvander@2168
   307
			{
dvander@2168
   308
				if (temp_info[i].str.is_sz)
dvander@2168
   309
				{
dvander@2168
   310
					memcpy(temp_info[i].orig_addr, temp_info[i].phys_addr, temp_info[i].size);
dvander@2168
   311
				
dvander@2168
   312
				}
dvander@2168
   313
				else
dvander@2168
   314
				{
dvander@2168
   315
					if (temp_info[i].size == 1)
dvander@2168
   316
					{
dvander@2168
   317
						*temp_info[i].orig_addr = *(temp_info[i].phys_addr);
dvander@2168
   318
					}
dvander@2168
   319
					else
dvander@2168
   320
					{
dvander@2168
   321
						memcpy(temp_info[i].orig_addr, 
dvander@2168
   322
								temp_info[i].phys_addr, 
dvander@2168
   323
								temp_info[i].size * sizeof(cell_t));
dvander@2168
   324
					}
dvander@2168
   325
				}
dvander@2168
   326
			}
dvander@2168
   327
		}
dvander@2168
   328
dvander@2171
   329
		if ((err=ctx->HeapPop(temp_info[i].local_addr)) != SP_ERROR_NONE)
dvander@2168
   330
		{
dvander@2168
   331
			return err;
dvander@2168
   332
		}
dvander@2168
   333
	}
dvander@2168
   334
dvander@2168
   335
	return err;
dvander@2168
   336
}
dvander@2168
   337
dvander@2168
   338
funcid_t CFunction::GetFunctionID()
dvander@2168
   339
{
dvander@2168
   340
	return m_FnId;
dvander@2168
   341
}
dvander@2168
   342
dvander@2171
   343
int CFunction::SetError(int err)
dvander@2171
   344
{
dvander@2171
   345
	m_errorstate = err;
dvander@2171
   346
dvander@2171
   347
	return err;
dvander@2171
   348
}
dvander@2171
   349
dvander@2171
   350
bool CFunction::IsInvalidated()
dvander@2171
   351
{
dvander@2171
   352
	return m_Invalid;
dvander@2171
   353
}
dvander@2171
   354
dvander@2171
   355