initial import of dynamic native code for both the JIT and plugins
authorDavid Anderson <dvander@alliedmods.net>
Mon Mar 12 07:08:05 2007 +0000 (2007-03-12)
changeset 601fe5b368fcedc
parent 600 f6d811158ad3
child 602 dcc958866d37
initial import of dynamic native code for both the JIT and plugins
note: dependency resolution is not done yet!
core/msvc8/sourcemod_mm.vcproj
core/smn_fakenatives.cpp
core/systems/PluginSys.cpp
core/systems/PluginSys.h
plugins/include/functions.inc
plugins/include/sourcemod.inc
plugins/testsuite/fakenative1.sp
plugins/testsuite/fakenative2.sp
public/sourcepawn/sp_vm_api.h
public/sourcepawn/sp_vm_types.h
sourcepawn/jit/x86/dll_exports.cpp
sourcepawn/jit/x86/jit_x86.cpp
sourcepawn/jit/x86/jit_x86.h
sourcepawn/jit/x86/msvc8/jit-x86.vcproj
     1.1 --- a/core/msvc8/sourcemod_mm.vcproj	Mon Mar 12 00:07:54 2007 +0000
     1.2 +++ b/core/msvc8/sourcemod_mm.vcproj	Mon Mar 12 07:08:05 2007 +0000
     1.3 @@ -1,7 +1,7 @@
     1.4  <?xml version="1.0" encoding="Windows-1252"?>
     1.5  <VisualStudioProject
     1.6  	ProjectType="Visual C++"
     1.7 -	Version="8,00"
     1.8 +	Version="8.00"
     1.9  	Name="sourcemod_mm"
    1.10  	ProjectGUID="{E39527CD-7CAB-4420-97CC-DA1B93B260BC}"
    1.11  	RootNamespace="sourcemod_mm"
    1.12 @@ -714,6 +714,10 @@
    1.13  				>
    1.14  			</File>
    1.15  			<File
    1.16 +				RelativePath="..\smn_fakenatives.cpp"
    1.17 +				>
    1.18 +			</File>
    1.19 +			<File
    1.20  				RelativePath="..\smn_filesystem.cpp"
    1.21  				>
    1.22  			</File>
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/core/smn_fakenatives.cpp	Mon Mar 12 07:08:05 2007 +0000
     2.3 @@ -0,0 +1,430 @@
     2.4 +/**
     2.5 + * ===============================================================
     2.6 + * SourceMod (C)2004-2007 AlliedModders LLC.  All rights reserved.
     2.7 + * ===============================================================
     2.8 + *
     2.9 + * This file is not open source and may not be copied without explicit
    2.10 + * written permission of AlliedModders LLC.  This file may not be redistributed 
    2.11 + * in whole or significant part.
    2.12 + * For information, see LICENSE.txt or http://www.sourcemod.net/license.php
    2.13 + *
    2.14 + * Version: $Id$
    2.15 + */
    2.16 +
    2.17 +#include <sh_list.h>
    2.18 +#include <sh_string.h>
    2.19 +#include "sm_trie.h"
    2.20 +#include "sm_globals.h"
    2.21 +#include "PluginSys.h"
    2.22 +#include "sourcemod.h"
    2.23 +#include "sm_stringutil.h"
    2.24 +
    2.25 +using namespace SourceHook;
    2.26 +
    2.27 +static cell_t s_curparams[SP_MAX_EXEC_PARAMS+1];
    2.28 +static FakeNative *s_curnative = NULL;
    2.29 +static IPluginContext *s_curcaller = NULL;
    2.30 +
    2.31 +cell_t FakeNativeRouter(IPluginContext *pContext, const cell_t *params, void *pData)
    2.32 +{
    2.33 +	FakeNative *native = (FakeNative *)pData;
    2.34 +
    2.35 +	/* Check if too many parameters were passed */
    2.36 +	if (params[0] > SP_MAX_EXEC_PARAMS)
    2.37 +	{
    2.38 +		return pContext->ThrowNativeError("Called native with too many parameters (%d>%d)", params[9], SP_MAX_EXEC_PARAMS);
    2.39 +	}
    2.40 +
    2.41 +	/* Check if the native is paused */
    2.42 +	sp_context_t *pNativeCtx = native->ctx->GetContext();
    2.43 +	if ((pNativeCtx->flags & SPFLAG_PLUGIN_PAUSED) == SPFLAG_PLUGIN_PAUSED)
    2.44 +	{
    2.45 +		return pContext->ThrowNativeError("Plugin owning this native is currently paused.");
    2.46 +	}
    2.47 +
    2.48 +	CPlugin *pCaller = g_PluginSys.GetPluginByCtx(pContext->GetContext());
    2.49 +
    2.50 +	/* Save any old data on the stack */
    2.51 +	FakeNative *pSaveNative = s_curnative;
    2.52 +	IPluginContext *pSaveCaller = s_curcaller;
    2.53 +	cell_t save_params[SP_MAX_EXEC_PARAMS+1];
    2.54 +	if (pSaveNative != NULL)
    2.55 +	{
    2.56 +		/* Copy all old parameters */
    2.57 +		for (cell_t i=0; i<=s_curparams[0]; i++)
    2.58 +		{
    2.59 +			save_params[i] = s_curparams[i];
    2.60 +		}
    2.61 +	}
    2.62 +
    2.63 +	/* Save the current parameters */
    2.64 +	s_curnative = native;
    2.65 +	s_curcaller = pContext;
    2.66 +	for (cell_t i=0; i<=params[0]; i++)
    2.67 +	{
    2.68 +		s_curparams[i] = params[i];
    2.69 +	}
    2.70 +
    2.71 +	/* Push info and execute. */
    2.72 +	cell_t result = 0;
    2.73 +	native->call->PushCell(pCaller->GetMyHandle());
    2.74 +	native->call->PushCell(params[0]);
    2.75 +	if (native->call->Execute(&result) != SP_ERROR_NONE)
    2.76 +	{
    2.77 +		if (pContext->GetContext()->n_err == SP_ERROR_NONE)
    2.78 +		{
    2.79 +			pContext->ThrowNativeError("Error encountered while processing a dynamic native");
    2.80 +		}
    2.81 +	}
    2.82 +
    2.83 +	/* Restore everything from the stack if necessary */
    2.84 +	if (pSaveNative != NULL)
    2.85 +	{
    2.86 +		s_curnative = pSaveNative;
    2.87 +		s_curcaller = pSaveCaller;
    2.88 +		for (cell_t i=0; i<=save_params[0]; i++)
    2.89 +		{
    2.90 +			s_curparams[i] = save_params[i];
    2.91 +		}
    2.92 +	}
    2.93 +
    2.94 +	return result;
    2.95 +}
    2.96 +
    2.97 +static cell_t CreateNative(IPluginContext *pContext, const cell_t *params)
    2.98 +{
    2.99 +	char *name;
   2.100 +	pContext->LocalToString(params[1], &name);
   2.101 +
   2.102 +	IPluginFunction *pFunction = pContext->GetFunctionById(params[2]);
   2.103 +	if (!pFunction)
   2.104 +	{
   2.105 +		return pContext->ThrowNativeError("Function %x is not a valid function", params[2]);
   2.106 +	}
   2.107 +
   2.108 +	if (!g_PluginSys.AddFakeNative(pFunction, name, FakeNativeRouter))
   2.109 +	{
   2.110 +		return pContext->ThrowNativeError("Fatal error creating dynamic native!");
   2.111 +	}
   2.112 +
   2.113 +	return 1;
   2.114 +}
   2.115 +
   2.116 +static cell_t ThrowNativeError(IPluginContext *pContext, const cell_t *params)
   2.117 +{
   2.118 +	if (!s_curnative || (s_curnative->ctx != pContext))
   2.119 +	{
   2.120 +		return pContext->ThrowNativeError("Not called from inside a native function");
   2.121 +	}
   2.122 +
   2.123 +	char buffer[512];
   2.124 +
   2.125 +	g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
   2.126 +
   2.127 +	if (pContext->GetContext()->n_err != SP_ERROR_NONE)
   2.128 +	{
   2.129 +		s_curcaller->ThrowNativeError("Error encountered while processing a dynamic native");
   2.130 +	} else {
   2.131 +		s_curcaller->ThrowNativeErrorEx(params[1], "%s", buffer);
   2.132 +	}
   2.133 +
   2.134 +	return 0;
   2.135 +}
   2.136 +
   2.137 +static cell_t GetNativeStringLength(IPluginContext *pContext, const cell_t *params)
   2.138 +{
   2.139 +	if (!s_curnative || (s_curnative->ctx != pContext))
   2.140 +	{
   2.141 +		return pContext->ThrowNativeError("Not called from inside a native function");
   2.142 +	}
   2.143 +
   2.144 +	cell_t param = params[1];
   2.145 +	if (param < 1 || param > s_curparams[0])
   2.146 +	{
   2.147 +		return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
   2.148 +	}
   2.149 +
   2.150 +	int err;
   2.151 +	char *str;
   2.152 +	if ((err=s_curcaller->LocalToString(s_curparams[param], &str)) != SP_ERROR_NONE)
   2.153 +	{
   2.154 +		return err;
   2.155 +	}
   2.156 +
   2.157 +	cell_t *addr;
   2.158 +	pContext->LocalToPhysAddr(params[2], &addr);
   2.159 +	*addr = (cell_t)strlen(str);
   2.160 +
   2.161 +	return SP_ERROR_NONE;
   2.162 +}
   2.163 +
   2.164 +static cell_t GetNativeString(IPluginContext *pContext, const cell_t *params)
   2.165 +{
   2.166 +	if (!s_curnative || (s_curnative->ctx != pContext))
   2.167 +	{
   2.168 +		return pContext->ThrowNativeError("Not called from inside a native function");
   2.169 +	}
   2.170 +
   2.171 +	cell_t param = params[1];
   2.172 +	if (param < 1 || param > s_curparams[0])
   2.173 +	{
   2.174 +		return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
   2.175 +	}
   2.176 +
   2.177 +	int err;
   2.178 +	char *str;
   2.179 +	if ((err=s_curcaller->LocalToString(s_curparams[param], &str)) != SP_ERROR_NONE)
   2.180 +	{
   2.181 +		return err;
   2.182 +	}
   2.183 +
   2.184 +	size_t bytes = 0;
   2.185 +	pContext->StringToLocalUTF8(params[2], params[3], str, &bytes);
   2.186 +
   2.187 +	cell_t *addr;
   2.188 +	pContext->LocalToPhysAddr(params[4], &addr);
   2.189 +	*addr = (cell_t)bytes;
   2.190 +
   2.191 +	return SP_ERROR_NONE;
   2.192 +}
   2.193 +
   2.194 +static cell_t SetNativeString(IPluginContext *pContext, const cell_t *params)
   2.195 +{
   2.196 +	if (!s_curnative || (s_curnative->ctx != pContext))
   2.197 +	{
   2.198 +		return pContext->ThrowNativeError("Not called from inside a native function");
   2.199 +	}
   2.200 +
   2.201 +	cell_t param = params[1];
   2.202 +	if (param < 1 || param > s_curparams[0])
   2.203 +	{
   2.204 +		return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
   2.205 +	}
   2.206 +
   2.207 +	char *str;
   2.208 +	pContext->LocalToString(params[2], &str);
   2.209 +
   2.210 +	int err;
   2.211 +	size_t bytes = 0;
   2.212 +	if (params[4])
   2.213 +	{
   2.214 +		err = s_curcaller->StringToLocalUTF8(s_curparams[param], params[3], str, &bytes);
   2.215 +	} else {
   2.216 +		err = s_curcaller->StringToLocal(s_curparams[param], params[3], str);
   2.217 +		/* Eww */
   2.218 +		bytes = strlen(str);
   2.219 +		if (bytes >= (size_t)params[3])
   2.220 +		{
   2.221 +			bytes = params[3] - 1;
   2.222 +		}
   2.223 +	}
   2.224 +
   2.225 +	if (err != SP_ERROR_NONE)
   2.226 +	{
   2.227 +		return err;
   2.228 +	}
   2.229 +
   2.230 +	cell_t *addr;
   2.231 +	pContext->LocalToPhysAddr(params[5], &addr);
   2.232 +	*addr = (cell_t)bytes;
   2.233 +
   2.234 +	return SP_ERROR_NONE;
   2.235 +}
   2.236 +
   2.237 +static cell_t GetNativeCell(IPluginContext *pContext, const cell_t *params)
   2.238 +{
   2.239 +	if (!s_curnative || (s_curnative->ctx != pContext))
   2.240 +	{
   2.241 +		return pContext->ThrowNativeError("Not called from inside a native function");
   2.242 +	}
   2.243 +
   2.244 +	cell_t param = params[1];
   2.245 +	if (param < 1 || param > s_curparams[0])
   2.246 +	{
   2.247 +		return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
   2.248 +	}
   2.249 +
   2.250 +	return s_curparams[param];
   2.251 +}
   2.252 +
   2.253 +static cell_t GetNativeCellRef(IPluginContext *pContext, const cell_t *params)
   2.254 +{
   2.255 +	if (!s_curnative || (s_curnative->ctx != pContext))
   2.256 +	{
   2.257 +		return pContext->ThrowNativeError("Not called from inside a native function");
   2.258 +	}
   2.259 +
   2.260 +	cell_t param = params[1];
   2.261 +	if (param < 1 || param > s_curparams[0])
   2.262 +	{
   2.263 +		return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
   2.264 +	}
   2.265 +
   2.266 +	cell_t *addr;
   2.267 +	if (s_curcaller->LocalToPhysAddr(s_curparams[param], &addr) != SP_ERROR_NONE)
   2.268 +	{
   2.269 +		return s_curcaller->ThrowNativeErrorEx(SP_ERROR_INVALID_ADDRESS, "Invalid address value");
   2.270 +	}
   2.271 +
   2.272 +	return *addr;
   2.273 +}
   2.274 +
   2.275 +static cell_t SetNativeCellRef(IPluginContext *pContext, const cell_t *params)
   2.276 +{
   2.277 +	if (!s_curnative || (s_curnative->ctx != pContext))
   2.278 +	{
   2.279 +		return pContext->ThrowNativeError("Not called from inside a native function");
   2.280 +	}
   2.281 +
   2.282 +	cell_t param = params[1];
   2.283 +	if (param < 1 || param > s_curparams[0])
   2.284 +	{
   2.285 +		return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
   2.286 +	}
   2.287 +
   2.288 +	cell_t *addr;
   2.289 +	if (s_curcaller->LocalToPhysAddr(s_curparams[param], &addr) != SP_ERROR_NONE)
   2.290 +	{
   2.291 +		return s_curcaller->ThrowNativeErrorEx(SP_ERROR_INVALID_ADDRESS, "Invalid address value");
   2.292 +	}
   2.293 +
   2.294 +	*addr = params[2];
   2.295 +
   2.296 +	return 1;
   2.297 +}
   2.298 +
   2.299 +static cell_t GetNativeArray(IPluginContext *pContext, const cell_t *params)
   2.300 +{
   2.301 +	if (!s_curnative || (s_curnative->ctx != pContext))
   2.302 +	{
   2.303 +		return pContext->ThrowNativeError("Not called from inside a native function");
   2.304 +	}
   2.305 +
   2.306 +	cell_t param = params[1];
   2.307 +	if (param < 1 || param > s_curparams[0])
   2.308 +	{
   2.309 +		return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
   2.310 +	}
   2.311 +
   2.312 +	int err;
   2.313 +	cell_t *addr;
   2.314 +	if ((err=s_curcaller->LocalToPhysAddr(s_curparams[param], &addr)) != SP_ERROR_NONE)
   2.315 +	{
   2.316 +		return err;
   2.317 +	}
   2.318 +
   2.319 +	cell_t *src;
   2.320 +	pContext->LocalToPhysAddr(params[2], &src);
   2.321 +
   2.322 +	memcpy(src, addr, sizeof(cell_t) * params[3]);
   2.323 +
   2.324 +	return SP_ERROR_NONE;
   2.325 +}
   2.326 +
   2.327 +static cell_t SetNativeArray(IPluginContext *pContext, const cell_t *params)
   2.328 +{
   2.329 +	if (!s_curnative || (s_curnative->ctx != pContext))
   2.330 +	{
   2.331 +		return pContext->ThrowNativeError("Not called from inside a native function");
   2.332 +	}
   2.333 +
   2.334 +	cell_t param = params[1];
   2.335 +	if (param < 1 || param > s_curparams[0])
   2.336 +	{
   2.337 +		return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
   2.338 +	}
   2.339 +
   2.340 +	int err;
   2.341 +	cell_t *addr;
   2.342 +	if ((err=s_curcaller->LocalToPhysAddr(s_curparams[param], &addr)) != SP_ERROR_NONE)
   2.343 +	{
   2.344 +		return err;
   2.345 +	}
   2.346 +
   2.347 +	cell_t *src;
   2.348 +	pContext->LocalToPhysAddr(params[2], &src);
   2.349 +
   2.350 +	memcpy(addr, src, sizeof(cell_t) * params[3]);
   2.351 +
   2.352 +	return SP_ERROR_NONE;
   2.353 +}
   2.354 +
   2.355 +static cell_t FormatNativeString(IPluginContext *pContext, const cell_t *params)
   2.356 +{
   2.357 +	if (!s_curnative || (s_curnative->ctx != pContext))
   2.358 +	{
   2.359 +		return pContext->ThrowNativeError("Not called from inside a native function");
   2.360 +	}
   2.361 +
   2.362 +	int out_param = params[1];
   2.363 +	int fmt_param = params[2];
   2.364 +	int var_param = params[3];
   2.365 +
   2.366 +	/* Validate input */
   2.367 +	if (out_param && (out_param < 1 || out_param > s_curparams[0]))
   2.368 +	{
   2.369 +		return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", out_param);
   2.370 +	}
   2.371 +	if (fmt_param && (fmt_param < 1 || fmt_param > s_curparams[0]))
   2.372 +	{
   2.373 +		return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", fmt_param);
   2.374 +	}
   2.375 +	if (var_param && (var_param < 1 || var_param > s_curparams[0] + 1))
   2.376 +	{
   2.377 +		return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", fmt_param);
   2.378 +	}
   2.379 +
   2.380 +	/* Get buffer information */
   2.381 +	int err;
   2.382 +	char *output_buffer;
   2.383 +	char *format_buffer;
   2.384 +
   2.385 +	if (out_param)
   2.386 +	{
   2.387 +		if ((err=s_curcaller->LocalToString(s_curparams[out_param], &output_buffer)) != SP_ERROR_NONE)
   2.388 +		{
   2.389 +			return err;
   2.390 +		}
   2.391 +	} else {
   2.392 +		pContext->LocalToString(params[6], &output_buffer);
   2.393 +	}
   2.394 +
   2.395 +	if (fmt_param)
   2.396 +	{
   2.397 +		if ((err=s_curcaller->LocalToString(s_curparams[fmt_param], &format_buffer)) != SP_ERROR_NONE)
   2.398 +		{
   2.399 +			return err;
   2.400 +		}
   2.401 +	} else {
   2.402 +		pContext->LocalToString(params[7], &format_buffer);
   2.403 +	}
   2.404 +
   2.405 +	/* Get maximum length */
   2.406 +	size_t maxlen = (size_t)params[4];
   2.407 +
   2.408 +	/* Do the format */
   2.409 +	size_t written = atcprintf(output_buffer, maxlen, format_buffer, s_curcaller, s_curparams, &var_param);
   2.410 +
   2.411 +	cell_t *addr;
   2.412 +	pContext->LocalToPhysAddr(params[5], &addr);
   2.413 +	*addr = (cell_t)written;
   2.414 +
   2.415 +	return s_curcaller->GetContext()->n_err;
   2.416 +}
   2.417 +
   2.418 +//tee hee
   2.419 +REGISTER_NATIVES(nativeNatives)
   2.420 +{
   2.421 +	{"CreateNative",			CreateNative},
   2.422 +	{"GetNativeArray",			GetNativeArray},
   2.423 +	{"GetNativeCell",			GetNativeCell},
   2.424 +	{"GetNativeCellRef",		GetNativeCellRef},
   2.425 +	{"GetNativeString",			GetNativeString},
   2.426 +	{"GetNativeStringLength",	GetNativeStringLength},
   2.427 +	{"FormatNativeString",		FormatNativeString},
   2.428 +	{"ThrowNativeError",		ThrowNativeError},
   2.429 +	{"SetNativeArray",			SetNativeArray},
   2.430 +	{"SetNativeCellRef",		SetNativeCellRef},
   2.431 +	{"SetNativeString",			SetNativeString},
   2.432 +	{NULL,						NULL},
   2.433 +};
     3.1 --- a/core/systems/PluginSys.cpp	Mon Mar 12 00:07:54 2007 +0000
     3.2 +++ b/core/systems/PluginSys.cpp	Mon Mar 12 07:08:05 2007 +0000
     3.3 @@ -588,6 +588,7 @@
     3.4  	m_LoadLookup = sm_trie_create();
     3.5  	m_AllPluginsLoaded = false;
     3.6  	m_MyIdent = NULL;
     3.7 +	m_pNativeLookup = sm_trie_create();
     3.8  }
     3.9  
    3.10  CPluginManager::~CPluginManager()
    3.11 @@ -598,9 +599,9 @@
    3.12  	 * will crash anyway.  YAY
    3.13  	 */
    3.14  	sm_trie_destroy(m_LoadLookup);
    3.15 +	sm_trie_destroy(m_pNativeLookup);
    3.16  }
    3.17  
    3.18 -
    3.19  void CPluginManager::LoadAll_FirstPass(const char *config, const char *basedir)
    3.20  {
    3.21  	/* First read in the database of plugin settings */
    3.22 @@ -958,6 +959,7 @@
    3.23  
    3.24  	/* Bind all extra natives */
    3.25  	g_Extensions.BindAllNativesToPlugin(pPlugin);
    3.26 +	AddFakeNativesToPlugin(pPlugin);
    3.27  
    3.28  	/* Find any unbound natives
    3.29  	 * Right now, these are not allowed
    3.30 @@ -1013,6 +1015,32 @@
    3.31  	}
    3.32  }
    3.33  
    3.34 +void CPluginManager::AddFakeNativesToPlugin(CPlugin *pPlugin)
    3.35 +{
    3.36 +	IPluginContext *pContext = pPlugin->GetBaseContext();
    3.37 +	sp_nativeinfo_t native;
    3.38 +
    3.39 +	List<FakeNative *>::iterator iter;
    3.40 +	FakeNative *pNative;
    3.41 +	sp_context_t *ctx;
    3.42 +	for (iter = m_Natives.begin(); iter != m_Natives.end(); iter++)
    3.43 +	{
    3.44 +		pNative = (*iter);
    3.45 +		ctx = pNative->ctx->GetContext();
    3.46 +		if ((ctx->flags & SPFLAG_PLUGIN_PAUSED) == SPFLAG_PLUGIN_PAUSED)
    3.47 +		{
    3.48 +			/* Ignore natives in paused plugins */
    3.49 +			continue;
    3.50 +		}
    3.51 +		native.name = pNative->name.c_str();
    3.52 +		native.func = pNative->func;
    3.53 +		if (pContext->BindNative(&native) == SP_ERROR_NONE)
    3.54 +		{
    3.55 +			/* :TODO: add to dependency list */
    3.56 +		}
    3.57 +	}
    3.58 +}
    3.59 +
    3.60  bool CPluginManager::UnloadPlugin(IPlugin *plugin)
    3.61  {
    3.62  	CPlugin *pPlugin = (CPlugin *)plugin;
    3.63 @@ -1675,3 +1703,28 @@
    3.64  	}	
    3.65  }
    3.66  
    3.67 +bool CPluginManager::AddFakeNative(IPluginFunction *pFunction, const char *name, SPVM_FAKENATIVE_FUNC func)
    3.68 +{
    3.69 +	if (sm_trie_retrieve(m_pNativeLookup, name, NULL))
    3.70 +	{
    3.71 +		return false;
    3.72 +	}
    3.73 +
    3.74 +	FakeNative *pNative = new FakeNative;
    3.75 +
    3.76 +	pNative->func = g_pVM->CreateFakeNative(func, pNative);
    3.77 +	if (!pNative->func)
    3.78 +	{
    3.79 +		delete pNative;
    3.80 +		return false;
    3.81 +	}
    3.82 +
    3.83 +	pNative->call = pFunction;
    3.84 +	pNative->name.assign(name);
    3.85 +	pNative->ctx = pFunction->GetParentContext();
    3.86 +
    3.87 +	m_Natives.push_back(pNative);
    3.88 +	sm_trie_insert(m_pNativeLookup, name,pNative);
    3.89 +
    3.90 +	return true;
    3.91 +}
     4.1 --- a/core/systems/PluginSys.h	Mon Mar 12 00:07:54 2007 +0000
     4.2 +++ b/core/systems/PluginSys.h	Mon Mar 12 07:08:05 2007 +0000
     4.3 @@ -22,6 +22,7 @@
     4.4  #include <sh_list.h>
     4.5  #include <sh_stack.h>
     4.6  #include <sh_vector.h>
     4.7 +#include <sh_string.h>
     4.8  #include "sm_globals.h"
     4.9  #include "vm/sp_vm_basecontext.h"
    4.10  #include "PluginInfoDatabase.h"
    4.11 @@ -232,6 +233,14 @@
    4.12  	Trie *m_pProps;
    4.13  };
    4.14  
    4.15 +struct FakeNative
    4.16 +{
    4.17 +	IPluginContext *ctx;
    4.18 +	IPluginFunction *call;
    4.19 +	String name;
    4.20 +	SPVM_NATIVE_FUNC func;
    4.21 +};
    4.22 +
    4.23  class CPluginManager : 
    4.24  	public IPluginManager,
    4.25  	public SMGlobalClass,
    4.26 @@ -380,6 +389,10 @@
    4.27  	{
    4.28  		return m_MyIdent;
    4.29  	}
    4.30 +public:
    4.31 +	bool AddFakeNative(IPluginFunction *pFunction, const char *name, SPVM_FAKENATIVE_FUNC func);
    4.32 +private:
    4.33 +	void AddFakeNativesToPlugin(CPlugin *pPlugin);
    4.34  private:
    4.35  	List<IPluginsListener *> m_listeners;
    4.36  	List<CPlugin *> m_plugins;
    4.37 @@ -389,6 +402,11 @@
    4.38  	Trie *m_LoadLookup;
    4.39  	bool m_AllPluginsLoaded;
    4.40  	IdentityToken_t *m_MyIdent;
    4.41 +
    4.42 +	/* Dynamic native stuff */
    4.43 +	List<FakeNative *> m_Natives;
    4.44 +	Trie *m_pNativeLookup;
    4.45 +
    4.46  };
    4.47  
    4.48  extern CPluginManager g_PluginSys;
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/plugins/include/functions.inc	Mon Mar 12 07:08:05 2007 +0000
     5.3 @@ -0,0 +1,205 @@
     5.4 +/**
     5.5 + * vim: set ts=4 :
     5.6 + * ===============================================================
     5.7 + * SourceMod (C)2004-2007 AlliedModders LLC.  All rights reserved.
     5.8 + * ===============================================================
     5.9 + *
    5.10 + *  This file is part of the SourceMod/SourcePawn SDK.  This file may only be used 
    5.11 + * or modified under the Terms and Conditions of its License Agreement, which is found 
    5.12 + * in LICENSE.txt.  The Terms and Conditions for making SourceMod extensions/plugins 
    5.13 + * may change at any time.  To view the latest information, see:
    5.14 + *   http://www.sourcemod.net/license.php
    5.15 + *
    5.16 + * Version: $Id$
    5.17 + */
    5.18 + 
    5.19 +#define SP_ERROR_NONE					0	/**< No error occurred */
    5.20 +#define SP_ERROR_FILE_FORMAT			1	/**< File format unrecognized */
    5.21 +#define SP_ERROR_DECOMPRESSOR			2	/**< A decompressor was not found */
    5.22 +#define SP_ERROR_HEAPLOW				3	/**< Not enough space left on the heap */
    5.23 +#define SP_ERROR_PARAM					4	/**< Invalid parameter or parameter type */
    5.24 +#define SP_ERROR_INVALID_ADDRESS		5	/**< A memory address was not valid */
    5.25 +#define SP_ERROR_NOT_FOUND				6	/**< The object in question was not found */
    5.26 +#define SP_ERROR_INDEX					7	/**< Invalid index parameter */
    5.27 +#define SP_ERROR_STACKLOW				8	/**< Nnot enough space left on the stack */
    5.28 +#define SP_ERROR_NOTDEBUGGING			9	/**< Debug mode was not on or debug section not found */
    5.29 +#define SP_ERROR_INVALID_INSTRUCTION	10	/**< Invalid instruction was encountered */
    5.30 +#define SP_ERROR_MEMACCESS				11	/**< Invalid memory access */
    5.31 +#define SP_ERROR_STACKMIN				12	/**< Stack went beyond its minimum value */
    5.32 +#define SP_ERROR_HEAPMIN				13  /**< Heap went beyond its minimum value */
    5.33 +#define SP_ERROR_DIVIDE_BY_ZERO			14	/**< Division by zero */
    5.34 +#define SP_ERROR_ARRAY_BOUNDS			15	/**< Array index is out of bounds */
    5.35 +#define SP_ERROR_INSTRUCTION_PARAM		16	/**< Instruction had an invalid parameter */
    5.36 +#define SP_ERROR_STACKLEAK				17  /**< A native leaked an item on the stack */
    5.37 +#define SP_ERROR_HEAPLEAK				18  /**< A native leaked an item on the heap */
    5.38 +#define SP_ERROR_ARRAY_TOO_BIG			19	/**< A dynamic array is too big */
    5.39 +#define SP_ERROR_TRACKER_BOUNDS			20	/**< Tracker stack is out of bounds */
    5.40 +#define SP_ERROR_INVALID_NATIVE			21	/**< Native was pending or invalid */
    5.41 +#define SP_ERROR_PARAMS_MAX				22	/**< Maximum number of parameters reached */
    5.42 +#define SP_ERROR_NATIVE					23	/**< Error originates from a native */
    5.43 +#define SP_ERROR_NOT_RUNNABLE			24	/**< Function or plugin is not runnable */
    5.44 +#define SP_ERROR_ABORTED				25	/**< Function call was aborted */
    5.45 +
    5.46 +/**
    5.47 + * Defines a native function.
    5.48 + *
    5.49 + * It is not necessary to validate the parameter count 
    5.50 + *
    5.51 + * @param plugin			Handle of the calling plugin.
    5.52 + * @param numParams			Number of parameters passed to the native.
    5.53 + * @return 					Value for the native call to return.
    5.54 + */
    5.55 +functag NativeCall public(Handle:plugin, numParams);
    5.56 +
    5.57 +/**
    5.58 + * Creates a dynamic native.  This should only be called in AskPluginLoad(), or 
    5.59 + * else you risk not having your native shared with other plugins.
    5.60 + *
    5.61 + * @param name				Name of the dynamic native; must be unique amongst
    5.62 + *							all other registered dynamic native.s
    5.63 + * @param func				Function to use as the dynamic native.
    5.64 + * @noreturn
    5.65 + */
    5.66 +native CreateNative(const String:name[], NativeCall:func);
    5.67 +
    5.68 +/**
    5.69 + * Throws an error in the calling plugin of a native, instead of your own plugin.
    5.70 + *
    5.71 + * @param error				Error code to use.
    5.72 + * @param fmt				Error message format.
    5.73 + * @param ...				Format arguments.
    5.74 + */
    5.75 +native ThrowNativeError(error, const String:fmt[], {Handle,Float,String,_}:...);
    5.76 +
    5.77 +/**
    5.78 + * Retrieves the string length from a native parameter string.  This is useful 
    5.79 + * fetching the entire string using dynamic arrays.
    5.80 + * @note If this function succeeds, Get/SetNativeString will also succeed.
    5.81 + *
    5.82 + * @param param				Parameter number, starting from 1.
    5.83 + * @param length			Stores the length of the string.
    5.84 + * @return					SP_ERROR_NONE on sucecss, any other integer on failure.
    5.85 + * @error					Invalid parameter number or calling from a non-native function.
    5.86 + */
    5.87 +native GetNativeStringLength(param, &length);
    5.88 +
    5.89 +/**
    5.90 + * Retrieves a string from a native parameter.
    5.91 + * @note Output conditions are undefined on failure.
    5.92 + *
    5.93 + * @param param				Parameter number, starting from 1.
    5.94 + * @param buffer			Buffer to store the string in.
    5.95 + * @param maxlength			Maximum length of the buffer.
    5.96 + * @param bytes				Optionally store the number of bytes written.
    5.97 + * @return					SP_ERROR_NONE on success, any other integer on failure.
    5.98 + * @error					Invalid parameter number or calling from a non-native function.
    5.99 + */
   5.100 +native GetNativeString(param, String:buffer[], maxlength, &bytes=0);
   5.101 +
   5.102 +/**
   5.103 + * Sets a string in a native parameter.
   5.104 + * @note Output conditions are undefined on failure.
   5.105 + *
   5.106 + * @param param				Parameter number, starting from 1.
   5.107 + * @param source			Source string to use.
   5.108 + * @param maxlength			Maximum number of bytes to write.
   5.109 + * @param utf8				If false, string will not be written
   5.110 + *							with UTF8 safety.
   5.111 + * @param bytes				Optionally store the number of bytes written.
   5.112 + * @return					SP_ERROR_NONE on success, any other integer on failure.
   5.113 + * @error					Invalid parameter number or calling from a non-native function.
   5.114 + */
   5.115 +native SetNativeString(param, const String:source[], maxlength, bool:utf8=true, &bytes=0);
   5.116 +
   5.117 +/**
   5.118 + * Gets a cell from a native parameter.
   5.119 + *
   5.120 + * @param param				Parameter number, starting from 1.
   5.121 + * @return					Cell value at the parameter number.
   5.122 + * @error					Invalid parameter number or calling from a non-native function.
   5.123 + */
   5.124 +native GetNativeCell(param);
   5.125 +
   5.126 +/**
   5.127 + * Gets a cell from a native parameter, by reference.
   5.128 + *
   5.129 + * @param param				Parameter number, starting from 1.
   5.130 + * @return					Cell value at the parameter number.
   5.131 + * @error					Invalid parameter number or calling from a non-native function.
   5.132 + */
   5.133 +native GetNativeCellRef(param);
   5.134 +
   5.135 +/**
   5.136 + * Sets a cell from a native parameter, by reference.
   5.137 + *
   5.138 + * @param param				Parameter number, starting from 1.
   5.139 + * @param value				Cell value at the parameter number to set by reference.
   5.140 + * @noreturn
   5.141 + * @error					Invalid parameter number or calling from a non-native function.
   5.142 + */
   5.143 +native SetNativeCellRef(param, {Float,Handle,_}:value);
   5.144 +
   5.145 +/**
   5.146 + * Gets an array from a native parameter (always by reference).
   5.147 + *
   5.148 + * @param param				Parameter number, starting from 1.
   5.149 + * @param local				Local array to copy into.
   5.150 + * @param size				Maximum size of local array.
   5.151 + * @return					SP_ERROR_NONE on success, anything else on failure.
   5.152 + * @error					Invalid parameter number or calling from a non-native function.
   5.153 + */
   5.154 +native GetNativeArray(param, {Float,Handle,_}:local[], size);
   5.155 +
   5.156 +/**
   5.157 + * Copies a local array into a native parameter array (always by reference).
   5.158 + * 
   5.159 + * @param param				Parameter number, starting from 1.
   5.160 + * @param local				Local array to copy from.
   5.161 + * @param size				Size of the local array to copy.
   5.162 + * @return					SP_ERROR_NONE on success, anything else on failure.
   5.163 + * @error					Invalid parameter number or calling from a non-native function.
   5.164 + */
   5.165 +native SetNativeArray(param, const {Float,Handle,_}:local[], size);
   5.166 +
   5.167 +/**
   5.168 + * Formats a string using parameters from a native.
   5.169 + *
   5.170 + * @note All parameter indexes start at 1.
   5.171 + * @note If the input and output buffers overlap, the contents
   5.172 + *  of the output buffer at the end is undefined.
   5.173 + *
   5.174 + * @param out_param			Output parameter number to write to.  If 0, out_string is used.
   5.175 + * @param fmt_param			Format parameter number.  If 0, fmt_string is used.
   5.176 + * @param vararg_param		First variable parameter number.
   5.177 + * @param out_len			Output string buffer maximum length (always required).
   5.178 + * @param written			Optionally stores the number of bytes written.
   5.179 + * @param out_string		Output string buffer to use if out_param is not used.
   5.180 + * @param fmt_string		Format string to use if fmt_param is not used.
   5.181 + * @return					SP_ERROR_NONE on success, anything else on failure.
   5.182 + */
   5.183 +native FormatNativeString(out_param, 
   5.184 +						  fmt_param, 
   5.185 +						  vararg_param, 
   5.186 +						  out_len,
   5.187 +						  &written=0,
   5.188 +						  String:out_string[]="",
   5.189 +						  const String:fmt_string[]="");
   5.190 +
   5.191 +stock Float:GetNativeFloat(param, bool:byref)
   5.192 +{
   5.193 +	if (!byref)
   5.194 +	{
   5.195 +		return Float:GetNativeCell(param);
   5.196 +	} else {
   5.197 +		return Float:GetNativeCellRef(param);
   5.198 +	}
   5.199 +}
   5.200 +stock Handle:GetNativeHandle(param, bool:byref)
   5.201 +{
   5.202 +	if (!byref)
   5.203 +	{
   5.204 +		return Handle:GetNativeCell(param);
   5.205 +	} else {
   5.206 +		return Handle:GetNativeCellRef(param);
   5.207 +	}
   5.208 +}
     6.1 --- a/plugins/include/sourcemod.inc	Mon Mar 12 00:07:54 2007 +0000
     6.2 +++ b/plugins/include/sourcemod.inc	Mon Mar 12 07:08:05 2007 +0000
     6.3 @@ -39,6 +39,7 @@
     6.4  #include <clients>
     6.5  #include <usermessages>
     6.6  #include <events>
     6.7 +#include <functions>
     6.8  
     6.9  /**
    6.10   * Declare this as a struct in your plugin to expose its information.
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/plugins/testsuite/fakenative1.sp	Mon Mar 12 07:08:05 2007 +0000
     7.3 @@ -0,0 +1,85 @@
     7.4 +#include <sourcemod>
     7.5 +
     7.6 +public Plugin:myinfo = 
     7.7 +{
     7.8 +	name = "FakeNative Testing Lab #1",
     7.9 +	author = "AlliedModders LLC",
    7.10 +	description = "Test suite #1 for dynamic natives",
    7.11 +	version = "1.0.0.0",
    7.12 +	url = "http://www.sourcemod.net/"
    7.13 +};
    7.14 +
    7.15 +public bool:AskPluginLoad(Handle:myself, bool:late, String:error[], err_max)
    7.16 +{
    7.17 +	CreateNative("TestNative1", __TestNative1);
    7.18 +	CreateNative("TestNative2", __TestNative2);
    7.19 +	CreateNative("TestNative3", __TestNative3);
    7.20 +	CreateNative("TestNative4", __TestNative4);
    7.21 +	CreateNative("TestNative5", __TestNative5);
    7.22 +	return true;
    7.23 +}
    7.24 +
    7.25 +public __TestNative1(Handle:plugin, numParams)
    7.26 +{
    7.27 +	PrintToServer("TestNative1: Plugin: %x params: %d", plugin, numParams);
    7.28 +	if (numParams == 4)
    7.29 +	{
    7.30 +		ThrowNativeError(SP_ERROR_NATIVE, "Four parameters ARE NOT ALLOWED lol");
    7.31 +	}
    7.32 +	return 5;
    7.33 +}
    7.34 +
    7.35 +public __TestNative2(Handle:plugin, numParams)
    7.36 +{
    7.37 +	new String:buffer[512];
    7.38 +	new bytes;
    7.39 +	
    7.40 +	GetNativeString(1, buffer, sizeof(buffer), bytes);
    7.41 +	
    7.42 +	for (new i=0; i<bytes; i++)
    7.43 +	{
    7.44 +		buffer[i] = buffer[i] + 1;
    7.45 +	}
    7.46 +	
    7.47 +	SetNativeString(1, buffer, bytes+1);
    7.48 +}
    7.49 +
    7.50 +public __TestNative3(Handle:plugin, numParams)
    7.51 +{
    7.52 +	new val1 = GetNativeCell(1);
    7.53 +	new val2 = GetNativeCellRef(2);
    7.54 +	
    7.55 +	SetNativeCellRef(2, val1+val2);
    7.56 +}
    7.57 +
    7.58 +public __TestNative4(Handle:plugin, numParams)
    7.59 +{
    7.60 +	new size = GetNativeCell(3);
    7.61 +	new local[size];
    7.62 +	
    7.63 +	GetNativeArray(1, local, size);
    7.64 +	SetNativeArray(2, local, size);
    7.65 +}
    7.66 +
    7.67 +public __TestNative5(Handle:plugin, numParams)
    7.68 +{
    7.69 +	new local = GetNativeCell(1);
    7.70 +	
    7.71 +	if (local)
    7.72 +	{
    7.73 +		FormatNativeString(2, 4, 5, GetNativeCell(3));
    7.74 +	} else {
    7.75 +		new len = GetNativeCell(3);
    7.76 +		new fmt_len;
    7.77 +		new String:buffer[len];
    7.78 +			
    7.79 +		GetNativeStringLength(4, fmt_len);
    7.80 +		
    7.81 +		new String:format[fmt_len];
    7.82 +		
    7.83 +		GetNativeString(2, buffer, len);
    7.84 +		GetNativeString(4, format, fmt_len);
    7.85 +		
    7.86 +		FormatNativeString(0, 0, 5, len, _, buffer, format);
    7.87 +	}
    7.88 +}
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/plugins/testsuite/fakenative2.sp	Mon Mar 12 07:08:05 2007 +0000
     8.3 @@ -0,0 +1,87 @@
     8.4 +#include <sourcemod>
     8.5 +
     8.6 +native TestNative1(gaben, ...);
     8.7 +native TestNative2(String:buffer[]);
     8.8 +native TestNative3(value1, &value2);
     8.9 +native TestNative4(const input[], output[], size);
    8.10 +native TestNative5(bool:local, String:buffer[], maxlength, const String:fmt[], {Handle,Float,String,_}:...);
    8.11 +
    8.12 +public Plugin:myinfo = 
    8.13 +{
    8.14 +	name = "FakeNative Testing Lab #2",
    8.15 +	author = "AlliedModders LLC",
    8.16 +	description = "Test suite #2 for dynamic natives",
    8.17 +	version = "1.0.0.0",
    8.18 +	url = "http://www.sourcemod.net/"
    8.19 +};
    8.20 +
    8.21 +public OnPluginStart()
    8.22 +{
    8.23 +	RegServerCmd("test_native1", Test_Native1);
    8.24 +	RegServerCmd("test_native2", Test_Native2);
    8.25 +	RegServerCmd("test_native3", Test_Native3);
    8.26 +	RegServerCmd("test_native4", Test_Native4);
    8.27 +	RegServerCmd("test_native5", Test_Native5);
    8.28 +}
    8.29 +
    8.30 +public Action:Test_Native1(args)
    8.31 +{
    8.32 +	PrintToServer("Returned: %d", TestNative1(1));
    8.33 +	PrintToServer("Returned: %d", TestNative1(1,2));
    8.34 +	PrintToServer("Returned: %d", TestNative1(1,2,3,4));
    8.35 +	
    8.36 +	return Plugin_Handled;
    8.37 +}
    8.38 +
    8.39 +public Action:Test_Native2(args)
    8.40 +{
    8.41 +	new String:buffer[] = "IBM";
    8.42 +	
    8.43 +	PrintToServer("Before: %s", buffer);
    8.44 +	
    8.45 +	TestNative2(buffer);
    8.46 +	
    8.47 +	PrintToServer("AfteR: %s", buffer);
    8.48 +	
    8.49 +	return Plugin_Handled;
    8.50 +}
    8.51 +
    8.52 +public Action:Test_Native3(args)
    8.53 +{
    8.54 +	new value1 = 5, value2 = 6
    8.55 +	
    8.56 +	PrintToServer("Before: %d, %d", value1, value2);
    8.57 +	
    8.58 +	TestNative3(value1, value2);
    8.59 +	
    8.60 +	PrintToServer("After: %d, %d", value1, value2);
    8.61 +	
    8.62 +	return Plugin_Handled;
    8.63 +}
    8.64 +
    8.65 +public Action:Test_Native4(args)
    8.66 +{
    8.67 +	new input[5] = {0, 1, 2, 3, 4};
    8.68 +	new output[5];
    8.69 +	
    8.70 +	TestNative4(input, output, 5);
    8.71 +	
    8.72 +	PrintToServer("[0=%d] [1=%d] [2=%d] [3=%d] [4=%d]", input[0], input[1], input[2], input[3], input[4]);
    8.73 +	PrintToServer("[0=%d] [1=%d] [2=%d] [3=%d] [4=%d]", output[0], output[1], output[2], output[3], output[4]);
    8.74 +	
    8.75 +	return Plugin_Handled;
    8.76 +}
    8.77 +
    8.78 +public Action:Test_Native5(args)
    8.79 +{
    8.80 +	new String:buffer1[512];
    8.81 +	new String:buffer2[512];
    8.82 +	
    8.83 +	TestNative5(true, buffer1, sizeof(buffer1), "%d gabens in the %s", 50, "gabpark");
    8.84 +	TestNative5(true, buffer2, sizeof(buffer2), "%d gabens in the %s", 50, "gabpark");
    8.85 +	
    8.86 +	PrintToServer("Test 1: %s", buffer1);
    8.87 +	PrintToServer("Test 2: %s", buffer2);
    8.88 +	
    8.89 +	return Plugin_Handled;
    8.90 +}
     9.1 --- a/public/sourcepawn/sp_vm_api.h	Mon Mar 12 00:07:54 2007 +0000
     9.2 +++ b/public/sourcepawn/sp_vm_api.h	Mon Mar 12 07:08:05 2007 +0000
     9.3 @@ -28,7 +28,7 @@
     9.4  #include "sp_vm_types.h"
     9.5  
     9.6  /** SourcePawn VM API Version */
     9.7 -#define SOURCEPAWN_VM_API_VERSION		1
     9.8 +#define SOURCEPAWN_VM_API_VERSION		2
     9.9  
    9.10  #if defined SOURCEMOD_BUILD
    9.11  namespace SourceMod
    9.12 @@ -820,6 +820,23 @@
    9.13  		 * @return			True if code index is valid, false otherwise.
    9.14  		 */
    9.15  		virtual bool FunctionPLookup(const sp_context_t *ctx, uint32_t code_addr, unsigned int *result) =0;
    9.16 +
    9.17 +		/**
    9.18 +		 * @brief Creates a fake native and binds it to a general callback function.
    9.19 +		 *
    9.20 +		 * @param callback	Callback function to bind the native to.
    9.21 +		 * @param pData		Private data to pass to the callback when the native is invoked.
    9.22 +		 * @return			A new fake native function as a wrapper around the callback.
    9.23 +		 */
    9.24 +		virtual SPVM_NATIVE_FUNC CreateFakeNative(SPVM_FAKENATIVE_FUNC callback, void *pData) =0;
    9.25 +
    9.26 +		/**
    9.27 +		 * @brief Destroys a fake native function wrapper.  
    9.28 +		 *
    9.29 +		 * @param function	Pointer to the fake native created by CreateFakeNative.
    9.30 +		 * @noreturn
    9.31 +		 */
    9.32 +		virtual void DestroyFakenative(SPVM_NATIVE_FUNC func) =0;
    9.33  	};
    9.34  };
    9.35  
    10.1 --- a/public/sourcepawn/sp_vm_types.h	Mon Mar 12 00:07:54 2007 +0000
    10.2 +++ b/public/sourcepawn/sp_vm_types.h	Mon Mar 12 07:08:05 2007 +0000
    10.3 @@ -136,6 +136,12 @@
    10.4   */
    10.5  typedef cell_t (*SPVM_NATIVE_FUNC)(SourcePawn::IPluginContext *, const cell_t *);
    10.6  
    10.7 +/**
    10.8 + * @brief Fake native callback prototype, passed a context, parameter stack, and private data.
    10.9 + * A cell must be returned.
   10.10 + */
   10.11 +typedef cell_t (*SPVM_FAKENATIVE_FUNC)(SourcePawn::IPluginContext *, const cell_t *, void *);
   10.12 +
   10.13  /**********************************************
   10.14   *** The following structures are bound to the VM/JIT.
   10.15   *** Changing them will result in necessary recompilation.
    11.1 --- a/sourcepawn/jit/x86/dll_exports.cpp	Mon Mar 12 00:07:54 2007 +0000
    11.2 +++ b/sourcepawn/jit/x86/dll_exports.cpp	Mon Mar 12 07:08:05 2007 +0000
    11.3 @@ -17,7 +17,7 @@
    11.4  #include "dll_exports.h"
    11.5  
    11.6  SourcePawn::ISourcePawnEngine *engine = NULL;
    11.7 -JITX86 jit;
    11.8 +JITX86 g_jit;
    11.9  
   11.10  EXPORTFUNC int GiveEnginePointer(SourcePawn::ISourcePawnEngine *engine_p)
   11.11  {
   11.12 @@ -45,7 +45,7 @@
   11.13  		return NULL;
   11.14  	}
   11.15  
   11.16 -	return &jit;
   11.17 +	return &g_jit;
   11.18  }
   11.19  
   11.20  #if defined __linux__
    12.1 --- a/sourcepawn/jit/x86/jit_x86.cpp	Mon Mar 12 00:07:54 2007 +0000
    12.2 +++ b/sourcepawn/jit/x86/jit_x86.cpp	Mon Mar 12 07:08:05 2007 +0000
    12.3 @@ -2188,6 +2188,52 @@
    12.4  	return ctx;
    12.5  }
    12.6  
    12.7 +SPVM_NATIVE_FUNC JITX86::CreateFakeNative(SPVM_FAKENATIVE_FUNC callback, void *pData)
    12.8 +{
    12.9 +	JitWriter jw;
   12.10 +	JitWriter *jit = &jw;
   12.11 +
   12.12 +	jw.outbase = NULL;
   12.13 +	jw.outptr = NULL;
   12.14 +	jw.data = NULL;
   12.15 +
   12.16 +	/* First pass, calculate size */
   12.17 +rewind:
   12.18 +	//push pData		;push pData
   12.19 +	//push [esp+12]		;push params
   12.20 +	//push [esp+12]		;push ctx
   12.21 +	//call [callback]	;invoke the meta-callback
   12.22 +	//add esp, 12		;restore the stack
   12.23 +	//ret				;return
   12.24 +	IA32_Push_Imm32(jit, (jit_int32_t)pData);
   12.25 +	IA32_Push_Rm_Disp8_ESP(jit, 12);
   12.26 +	IA32_Push_Rm_Disp8_ESP(jit, 12);
   12.27 +	uint32_t call = IA32_Call_Imm32(jit, 0);
   12.28 +	IA32_Write_Jump32_Abs(jit, call, (void *)callback);
   12.29 +	IA32_Add_Rm_Imm8(jit, REG_ESP, 12, MOD_REG);
   12.30 +	IA32_Return(jit);
   12.31 +
   12.32 +	if (jw.outbase == NULL)
   12.33 +	{
   12.34 +		/* Second pass: Actually write */
   12.35 +		jw.outbase = (jitcode_t)engine->ExecAlloc(jw.get_outputpos());
   12.36 +		if (!jw.outbase)
   12.37 +		{
   12.38 +			return NULL;
   12.39 +		}
   12.40 +		jw.outptr = jw.outbase;
   12.41 +	
   12.42 +		goto rewind;
   12.43 +	}
   12.44 +	
   12.45 +	return (SPVM_NATIVE_FUNC)jw.outbase;
   12.46 +}
   12.47 +
   12.48 +void JITX86::DestroyFakenative(SPVM_NATIVE_FUNC func)
   12.49 +{
   12.50 +	engine->ExecFree(func);
   12.51 +}
   12.52 +
   12.53  const char *JITX86::GetVMName()
   12.54  {
   12.55  	return "JIT (x86)";
    13.1 --- a/sourcepawn/jit/x86/jit_x86.h	Mon Mar 12 00:07:54 2007 +0000
    13.2 +++ b/sourcepawn/jit/x86/jit_x86.h	Mon Mar 12 07:08:05 2007 +0000
    13.3 @@ -98,6 +98,8 @@
    13.4  	unsigned int FunctionCount(const sp_context_t *ctx);
    13.5  	const char *GetVersionString();
    13.6  	const char *GetCPUOptimizations();
    13.7 +	SPVM_NATIVE_FUNC CreateFakeNative(SPVM_FAKENATIVE_FUNC callback, void *pData);
    13.8 +	void DestroyFakenative(SPVM_NATIVE_FUNC func);
    13.9  };
   13.10  
   13.11  cell_t NativeCallback(sp_context_t *ctx, ucell_t native_idx, cell_t *params);
    14.1 --- a/sourcepawn/jit/x86/msvc8/jit-x86.vcproj	Mon Mar 12 00:07:54 2007 +0000
    14.2 +++ b/sourcepawn/jit/x86/msvc8/jit-x86.vcproj	Mon Mar 12 07:08:05 2007 +0000
    14.3 @@ -235,6 +235,10 @@
    14.4  			UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
    14.5  			>
    14.6  			<File
    14.7 +				RelativePath="..\jit_version.tpl"
    14.8 +				>
    14.9 +			</File>
   14.10 +			<File
   14.11  				RelativePath="..\opcode_switch.inc"
   14.12  				>
   14.13  			</File>