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