initial import of dynamic native code for both the JIT and plugins

note: dependency resolution is not done yet!

--HG--
extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40607
This commit is contained in:
David Anderson 2007-03-12 07:08:05 +00:00
parent 7ab8e2027b
commit 7c06d89b00
14 changed files with 963 additions and 5 deletions

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="8,00"
Version="8.00"
Name="sourcemod_mm"
ProjectGUID="{E39527CD-7CAB-4420-97CC-DA1B93B260BC}"
RootNamespace="sourcemod_mm"
@ -713,6 +713,10 @@
RelativePath="..\smn_events.cpp"
>
</File>
<File
RelativePath="..\smn_fakenatives.cpp"
>
</File>
<File
RelativePath="..\smn_filesystem.cpp"
>

430
core/smn_fakenatives.cpp Normal file
View File

@ -0,0 +1,430 @@
/**
* ===============================================================
* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved.
* ===============================================================
*
* This file is not open source and may not be copied without explicit
* written permission of AlliedModders LLC. This file may not be redistributed
* in whole or significant part.
* For information, see LICENSE.txt or http://www.sourcemod.net/license.php
*
* Version: $Id$
*/
#include <sh_list.h>
#include <sh_string.h>
#include "sm_trie.h"
#include "sm_globals.h"
#include "PluginSys.h"
#include "sourcemod.h"
#include "sm_stringutil.h"
using namespace SourceHook;
static cell_t s_curparams[SP_MAX_EXEC_PARAMS+1];
static FakeNative *s_curnative = NULL;
static IPluginContext *s_curcaller = NULL;
cell_t FakeNativeRouter(IPluginContext *pContext, const cell_t *params, void *pData)
{
FakeNative *native = (FakeNative *)pData;
/* Check if too many parameters were passed */
if (params[0] > SP_MAX_EXEC_PARAMS)
{
return pContext->ThrowNativeError("Called native with too many parameters (%d>%d)", params[9], SP_MAX_EXEC_PARAMS);
}
/* Check if the native is paused */
sp_context_t *pNativeCtx = native->ctx->GetContext();
if ((pNativeCtx->flags & SPFLAG_PLUGIN_PAUSED) == SPFLAG_PLUGIN_PAUSED)
{
return pContext->ThrowNativeError("Plugin owning this native is currently paused.");
}
CPlugin *pCaller = g_PluginSys.GetPluginByCtx(pContext->GetContext());
/* Save any old data on the stack */
FakeNative *pSaveNative = s_curnative;
IPluginContext *pSaveCaller = s_curcaller;
cell_t save_params[SP_MAX_EXEC_PARAMS+1];
if (pSaveNative != NULL)
{
/* Copy all old parameters */
for (cell_t i=0; i<=s_curparams[0]; i++)
{
save_params[i] = s_curparams[i];
}
}
/* Save the current parameters */
s_curnative = native;
s_curcaller = pContext;
for (cell_t i=0; i<=params[0]; i++)
{
s_curparams[i] = params[i];
}
/* Push info and execute. */
cell_t result = 0;
native->call->PushCell(pCaller->GetMyHandle());
native->call->PushCell(params[0]);
if (native->call->Execute(&result) != SP_ERROR_NONE)
{
if (pContext->GetContext()->n_err == SP_ERROR_NONE)
{
pContext->ThrowNativeError("Error encountered while processing a dynamic native");
}
}
/* Restore everything from the stack if necessary */
if (pSaveNative != NULL)
{
s_curnative = pSaveNative;
s_curcaller = pSaveCaller;
for (cell_t i=0; i<=save_params[0]; i++)
{
s_curparams[i] = save_params[i];
}
}
return result;
}
static cell_t CreateNative(IPluginContext *pContext, const cell_t *params)
{
char *name;
pContext->LocalToString(params[1], &name);
IPluginFunction *pFunction = pContext->GetFunctionById(params[2]);
if (!pFunction)
{
return pContext->ThrowNativeError("Function %x is not a valid function", params[2]);
}
if (!g_PluginSys.AddFakeNative(pFunction, name, FakeNativeRouter))
{
return pContext->ThrowNativeError("Fatal error creating dynamic native!");
}
return 1;
}
static cell_t ThrowNativeError(IPluginContext *pContext, const cell_t *params)
{
if (!s_curnative || (s_curnative->ctx != pContext))
{
return pContext->ThrowNativeError("Not called from inside a native function");
}
char buffer[512];
g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
if (pContext->GetContext()->n_err != SP_ERROR_NONE)
{
s_curcaller->ThrowNativeError("Error encountered while processing a dynamic native");
} else {
s_curcaller->ThrowNativeErrorEx(params[1], "%s", buffer);
}
return 0;
}
static cell_t GetNativeStringLength(IPluginContext *pContext, const cell_t *params)
{
if (!s_curnative || (s_curnative->ctx != pContext))
{
return pContext->ThrowNativeError("Not called from inside a native function");
}
cell_t param = params[1];
if (param < 1 || param > s_curparams[0])
{
return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
}
int err;
char *str;
if ((err=s_curcaller->LocalToString(s_curparams[param], &str)) != SP_ERROR_NONE)
{
return err;
}
cell_t *addr;
pContext->LocalToPhysAddr(params[2], &addr);
*addr = (cell_t)strlen(str);
return SP_ERROR_NONE;
}
static cell_t GetNativeString(IPluginContext *pContext, const cell_t *params)
{
if (!s_curnative || (s_curnative->ctx != pContext))
{
return pContext->ThrowNativeError("Not called from inside a native function");
}
cell_t param = params[1];
if (param < 1 || param > s_curparams[0])
{
return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
}
int err;
char *str;
if ((err=s_curcaller->LocalToString(s_curparams[param], &str)) != SP_ERROR_NONE)
{
return err;
}
size_t bytes = 0;
pContext->StringToLocalUTF8(params[2], params[3], str, &bytes);
cell_t *addr;
pContext->LocalToPhysAddr(params[4], &addr);
*addr = (cell_t)bytes;
return SP_ERROR_NONE;
}
static cell_t SetNativeString(IPluginContext *pContext, const cell_t *params)
{
if (!s_curnative || (s_curnative->ctx != pContext))
{
return pContext->ThrowNativeError("Not called from inside a native function");
}
cell_t param = params[1];
if (param < 1 || param > s_curparams[0])
{
return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
}
char *str;
pContext->LocalToString(params[2], &str);
int err;
size_t bytes = 0;
if (params[4])
{
err = s_curcaller->StringToLocalUTF8(s_curparams[param], params[3], str, &bytes);
} else {
err = s_curcaller->StringToLocal(s_curparams[param], params[3], str);
/* Eww */
bytes = strlen(str);
if (bytes >= (size_t)params[3])
{
bytes = params[3] - 1;
}
}
if (err != SP_ERROR_NONE)
{
return err;
}
cell_t *addr;
pContext->LocalToPhysAddr(params[5], &addr);
*addr = (cell_t)bytes;
return SP_ERROR_NONE;
}
static cell_t GetNativeCell(IPluginContext *pContext, const cell_t *params)
{
if (!s_curnative || (s_curnative->ctx != pContext))
{
return pContext->ThrowNativeError("Not called from inside a native function");
}
cell_t param = params[1];
if (param < 1 || param > s_curparams[0])
{
return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
}
return s_curparams[param];
}
static cell_t GetNativeCellRef(IPluginContext *pContext, const cell_t *params)
{
if (!s_curnative || (s_curnative->ctx != pContext))
{
return pContext->ThrowNativeError("Not called from inside a native function");
}
cell_t param = params[1];
if (param < 1 || param > s_curparams[0])
{
return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
}
cell_t *addr;
if (s_curcaller->LocalToPhysAddr(s_curparams[param], &addr) != SP_ERROR_NONE)
{
return s_curcaller->ThrowNativeErrorEx(SP_ERROR_INVALID_ADDRESS, "Invalid address value");
}
return *addr;
}
static cell_t SetNativeCellRef(IPluginContext *pContext, const cell_t *params)
{
if (!s_curnative || (s_curnative->ctx != pContext))
{
return pContext->ThrowNativeError("Not called from inside a native function");
}
cell_t param = params[1];
if (param < 1 || param > s_curparams[0])
{
return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
}
cell_t *addr;
if (s_curcaller->LocalToPhysAddr(s_curparams[param], &addr) != SP_ERROR_NONE)
{
return s_curcaller->ThrowNativeErrorEx(SP_ERROR_INVALID_ADDRESS, "Invalid address value");
}
*addr = params[2];
return 1;
}
static cell_t GetNativeArray(IPluginContext *pContext, const cell_t *params)
{
if (!s_curnative || (s_curnative->ctx != pContext))
{
return pContext->ThrowNativeError("Not called from inside a native function");
}
cell_t param = params[1];
if (param < 1 || param > s_curparams[0])
{
return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
}
int err;
cell_t *addr;
if ((err=s_curcaller->LocalToPhysAddr(s_curparams[param], &addr)) != SP_ERROR_NONE)
{
return err;
}
cell_t *src;
pContext->LocalToPhysAddr(params[2], &src);
memcpy(src, addr, sizeof(cell_t) * params[3]);
return SP_ERROR_NONE;
}
static cell_t SetNativeArray(IPluginContext *pContext, const cell_t *params)
{
if (!s_curnative || (s_curnative->ctx != pContext))
{
return pContext->ThrowNativeError("Not called from inside a native function");
}
cell_t param = params[1];
if (param < 1 || param > s_curparams[0])
{
return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", param);
}
int err;
cell_t *addr;
if ((err=s_curcaller->LocalToPhysAddr(s_curparams[param], &addr)) != SP_ERROR_NONE)
{
return err;
}
cell_t *src;
pContext->LocalToPhysAddr(params[2], &src);
memcpy(addr, src, sizeof(cell_t) * params[3]);
return SP_ERROR_NONE;
}
static cell_t FormatNativeString(IPluginContext *pContext, const cell_t *params)
{
if (!s_curnative || (s_curnative->ctx != pContext))
{
return pContext->ThrowNativeError("Not called from inside a native function");
}
int out_param = params[1];
int fmt_param = params[2];
int var_param = params[3];
/* Validate input */
if (out_param && (out_param < 1 || out_param > s_curparams[0]))
{
return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", out_param);
}
if (fmt_param && (fmt_param < 1 || fmt_param > s_curparams[0]))
{
return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", fmt_param);
}
if (var_param && (var_param < 1 || var_param > s_curparams[0] + 1))
{
return pContext->ThrowNativeErrorEx(SP_ERROR_PARAM, "Invalid parameter number: %d", fmt_param);
}
/* Get buffer information */
int err;
char *output_buffer;
char *format_buffer;
if (out_param)
{
if ((err=s_curcaller->LocalToString(s_curparams[out_param], &output_buffer)) != SP_ERROR_NONE)
{
return err;
}
} else {
pContext->LocalToString(params[6], &output_buffer);
}
if (fmt_param)
{
if ((err=s_curcaller->LocalToString(s_curparams[fmt_param], &format_buffer)) != SP_ERROR_NONE)
{
return err;
}
} else {
pContext->LocalToString(params[7], &format_buffer);
}
/* Get maximum length */
size_t maxlen = (size_t)params[4];
/* Do the format */
size_t written = atcprintf(output_buffer, maxlen, format_buffer, s_curcaller, s_curparams, &var_param);
cell_t *addr;
pContext->LocalToPhysAddr(params[5], &addr);
*addr = (cell_t)written;
return s_curcaller->GetContext()->n_err;
}
//tee hee
REGISTER_NATIVES(nativeNatives)
{
{"CreateNative", CreateNative},
{"GetNativeArray", GetNativeArray},
{"GetNativeCell", GetNativeCell},
{"GetNativeCellRef", GetNativeCellRef},
{"GetNativeString", GetNativeString},
{"GetNativeStringLength", GetNativeStringLength},
{"FormatNativeString", FormatNativeString},
{"ThrowNativeError", ThrowNativeError},
{"SetNativeArray", SetNativeArray},
{"SetNativeCellRef", SetNativeCellRef},
{"SetNativeString", SetNativeString},
{NULL, NULL},
};

View File

@ -588,6 +588,7 @@ CPluginManager::CPluginManager()
m_LoadLookup = sm_trie_create();
m_AllPluginsLoaded = false;
m_MyIdent = NULL;
m_pNativeLookup = sm_trie_create();
}
CPluginManager::~CPluginManager()
@ -598,9 +599,9 @@ CPluginManager::~CPluginManager()
* will crash anyway. YAY
*/
sm_trie_destroy(m_LoadLookup);
sm_trie_destroy(m_pNativeLookup);
}
void CPluginManager::LoadAll_FirstPass(const char *config, const char *basedir)
{
/* First read in the database of plugin settings */
@ -958,6 +959,7 @@ bool CPluginManager::RunSecondPass(CPlugin *pPlugin, char *error, size_t maxleng
/* Bind all extra natives */
g_Extensions.BindAllNativesToPlugin(pPlugin);
AddFakeNativesToPlugin(pPlugin);
/* Find any unbound natives
* Right now, these are not allowed
@ -1013,6 +1015,32 @@ void CPluginManager::AddCoreNativesToPlugin(CPlugin *pPlugin)
}
}
void CPluginManager::AddFakeNativesToPlugin(CPlugin *pPlugin)
{
IPluginContext *pContext = pPlugin->GetBaseContext();
sp_nativeinfo_t native;
List<FakeNative *>::iterator iter;
FakeNative *pNative;
sp_context_t *ctx;
for (iter = m_Natives.begin(); iter != m_Natives.end(); iter++)
{
pNative = (*iter);
ctx = pNative->ctx->GetContext();
if ((ctx->flags & SPFLAG_PLUGIN_PAUSED) == SPFLAG_PLUGIN_PAUSED)
{
/* Ignore natives in paused plugins */
continue;
}
native.name = pNative->name.c_str();
native.func = pNative->func;
if (pContext->BindNative(&native) == SP_ERROR_NONE)
{
/* :TODO: add to dependency list */
}
}
}
bool CPluginManager::UnloadPlugin(IPlugin *plugin)
{
CPlugin *pPlugin = (CPlugin *)plugin;
@ -1675,3 +1703,28 @@ void CPluginManager::_SetPauseState(CPlugin *pl, bool paused)
}
}
bool CPluginManager::AddFakeNative(IPluginFunction *pFunction, const char *name, SPVM_FAKENATIVE_FUNC func)
{
if (sm_trie_retrieve(m_pNativeLookup, name, NULL))
{
return false;
}
FakeNative *pNative = new FakeNative;
pNative->func = g_pVM->CreateFakeNative(func, pNative);
if (!pNative->func)
{
delete pNative;
return false;
}
pNative->call = pFunction;
pNative->name.assign(name);
pNative->ctx = pFunction->GetParentContext();
m_Natives.push_back(pNative);
sm_trie_insert(m_pNativeLookup, name,pNative);
return true;
}

View File

@ -22,6 +22,7 @@
#include <sh_list.h>
#include <sh_stack.h>
#include <sh_vector.h>
#include <sh_string.h>
#include "sm_globals.h"
#include "vm/sp_vm_basecontext.h"
#include "PluginInfoDatabase.h"
@ -232,6 +233,14 @@ private:
Trie *m_pProps;
};
struct FakeNative
{
IPluginContext *ctx;
IPluginFunction *call;
String name;
SPVM_NATIVE_FUNC func;
};
class CPluginManager :
public IPluginManager,
public SMGlobalClass,
@ -380,6 +389,10 @@ protected:
{
return m_MyIdent;
}
public:
bool AddFakeNative(IPluginFunction *pFunction, const char *name, SPVM_FAKENATIVE_FUNC func);
private:
void AddFakeNativesToPlugin(CPlugin *pPlugin);
private:
List<IPluginsListener *> m_listeners;
List<CPlugin *> m_plugins;
@ -389,6 +402,11 @@ private:
Trie *m_LoadLookup;
bool m_AllPluginsLoaded;
IdentityToken_t *m_MyIdent;
/* Dynamic native stuff */
List<FakeNative *> m_Natives;
Trie *m_pNativeLookup;
};
extern CPluginManager g_PluginSys;

View File

@ -0,0 +1,205 @@
/**
* vim: set ts=4 :
* ===============================================================
* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved.
* ===============================================================
*
* This file is part of the SourceMod/SourcePawn SDK. This file may only be used
* or modified under the Terms and Conditions of its License Agreement, which is found
* in LICENSE.txt. The Terms and Conditions for making SourceMod extensions/plugins
* may change at any time. To view the latest information, see:
* http://www.sourcemod.net/license.php
*
* Version: $Id$
*/
#define SP_ERROR_NONE 0 /**< No error occurred */
#define SP_ERROR_FILE_FORMAT 1 /**< File format unrecognized */
#define SP_ERROR_DECOMPRESSOR 2 /**< A decompressor was not found */
#define SP_ERROR_HEAPLOW 3 /**< Not enough space left on the heap */
#define SP_ERROR_PARAM 4 /**< Invalid parameter or parameter type */
#define SP_ERROR_INVALID_ADDRESS 5 /**< A memory address was not valid */
#define SP_ERROR_NOT_FOUND 6 /**< The object in question was not found */
#define SP_ERROR_INDEX 7 /**< Invalid index parameter */
#define SP_ERROR_STACKLOW 8 /**< Nnot enough space left on the stack */
#define SP_ERROR_NOTDEBUGGING 9 /**< Debug mode was not on or debug section not found */
#define SP_ERROR_INVALID_INSTRUCTION 10 /**< Invalid instruction was encountered */
#define SP_ERROR_MEMACCESS 11 /**< Invalid memory access */
#define SP_ERROR_STACKMIN 12 /**< Stack went beyond its minimum value */
#define SP_ERROR_HEAPMIN 13 /**< Heap went beyond its minimum value */
#define SP_ERROR_DIVIDE_BY_ZERO 14 /**< Division by zero */
#define SP_ERROR_ARRAY_BOUNDS 15 /**< Array index is out of bounds */
#define SP_ERROR_INSTRUCTION_PARAM 16 /**< Instruction had an invalid parameter */
#define SP_ERROR_STACKLEAK 17 /**< A native leaked an item on the stack */
#define SP_ERROR_HEAPLEAK 18 /**< A native leaked an item on the heap */
#define SP_ERROR_ARRAY_TOO_BIG 19 /**< A dynamic array is too big */
#define SP_ERROR_TRACKER_BOUNDS 20 /**< Tracker stack is out of bounds */
#define SP_ERROR_INVALID_NATIVE 21 /**< Native was pending or invalid */
#define SP_ERROR_PARAMS_MAX 22 /**< Maximum number of parameters reached */
#define SP_ERROR_NATIVE 23 /**< Error originates from a native */
#define SP_ERROR_NOT_RUNNABLE 24 /**< Function or plugin is not runnable */
#define SP_ERROR_ABORTED 25 /**< Function call was aborted */
/**
* Defines a native function.
*
* It is not necessary to validate the parameter count
*
* @param plugin Handle of the calling plugin.
* @param numParams Number of parameters passed to the native.
* @return Value for the native call to return.
*/
functag NativeCall public(Handle:plugin, numParams);
/**
* Creates a dynamic native. This should only be called in AskPluginLoad(), or
* else you risk not having your native shared with other plugins.
*
* @param name Name of the dynamic native; must be unique amongst
* all other registered dynamic native.s
* @param func Function to use as the dynamic native.
* @noreturn
*/
native CreateNative(const String:name[], NativeCall:func);
/**
* Throws an error in the calling plugin of a native, instead of your own plugin.
*
* @param error Error code to use.
* @param fmt Error message format.
* @param ... Format arguments.
*/
native ThrowNativeError(error, const String:fmt[], {Handle,Float,String,_}:...);
/**
* Retrieves the string length from a native parameter string. This is useful
* fetching the entire string using dynamic arrays.
* @note If this function succeeds, Get/SetNativeString will also succeed.
*
* @param param Parameter number, starting from 1.
* @param length Stores the length of the string.
* @return SP_ERROR_NONE on sucecss, any other integer on failure.
* @error Invalid parameter number or calling from a non-native function.
*/
native GetNativeStringLength(param, &length);
/**
* Retrieves a string from a native parameter.
* @note Output conditions are undefined on failure.
*
* @param param Parameter number, starting from 1.
* @param buffer Buffer to store the string in.
* @param maxlength Maximum length of the buffer.
* @param bytes Optionally store the number of bytes written.
* @return SP_ERROR_NONE on success, any other integer on failure.
* @error Invalid parameter number or calling from a non-native function.
*/
native GetNativeString(param, String:buffer[], maxlength, &bytes=0);
/**
* Sets a string in a native parameter.
* @note Output conditions are undefined on failure.
*
* @param param Parameter number, starting from 1.
* @param source Source string to use.
* @param maxlength Maximum number of bytes to write.
* @param utf8 If false, string will not be written
* with UTF8 safety.
* @param bytes Optionally store the number of bytes written.
* @return SP_ERROR_NONE on success, any other integer on failure.
* @error Invalid parameter number or calling from a non-native function.
*/
native SetNativeString(param, const String:source[], maxlength, bool:utf8=true, &bytes=0);
/**
* Gets a cell from a native parameter.
*
* @param param Parameter number, starting from 1.
* @return Cell value at the parameter number.
* @error Invalid parameter number or calling from a non-native function.
*/
native GetNativeCell(param);
/**
* Gets a cell from a native parameter, by reference.
*
* @param param Parameter number, starting from 1.
* @return Cell value at the parameter number.
* @error Invalid parameter number or calling from a non-native function.
*/
native GetNativeCellRef(param);
/**
* Sets a cell from a native parameter, by reference.
*
* @param param Parameter number, starting from 1.
* @param value Cell value at the parameter number to set by reference.
* @noreturn
* @error Invalid parameter number or calling from a non-native function.
*/
native SetNativeCellRef(param, {Float,Handle,_}:value);
/**
* Gets an array from a native parameter (always by reference).
*
* @param param Parameter number, starting from 1.
* @param local Local array to copy into.
* @param size Maximum size of local array.
* @return SP_ERROR_NONE on success, anything else on failure.
* @error Invalid parameter number or calling from a non-native function.
*/
native GetNativeArray(param, {Float,Handle,_}:local[], size);
/**
* Copies a local array into a native parameter array (always by reference).
*
* @param param Parameter number, starting from 1.
* @param local Local array to copy from.
* @param size Size of the local array to copy.
* @return SP_ERROR_NONE on success, anything else on failure.
* @error Invalid parameter number or calling from a non-native function.
*/
native SetNativeArray(param, const {Float,Handle,_}:local[], size);
/**
* Formats a string using parameters from a native.
*
* @note All parameter indexes start at 1.
* @note If the input and output buffers overlap, the contents
* of the output buffer at the end is undefined.
*
* @param out_param Output parameter number to write to. If 0, out_string is used.
* @param fmt_param Format parameter number. If 0, fmt_string is used.
* @param vararg_param First variable parameter number.
* @param out_len Output string buffer maximum length (always required).
* @param written Optionally stores the number of bytes written.
* @param out_string Output string buffer to use if out_param is not used.
* @param fmt_string Format string to use if fmt_param is not used.
* @return SP_ERROR_NONE on success, anything else on failure.
*/
native FormatNativeString(out_param,
fmt_param,
vararg_param,
out_len,
&written=0,
String:out_string[]="",
const String:fmt_string[]="");
stock Float:GetNativeFloat(param, bool:byref)
{
if (!byref)
{
return Float:GetNativeCell(param);
} else {
return Float:GetNativeCellRef(param);
}
}
stock Handle:GetNativeHandle(param, bool:byref)
{
if (!byref)
{
return Handle:GetNativeCell(param);
} else {
return Handle:GetNativeCellRef(param);
}
}

View File

@ -39,6 +39,7 @@ struct Plugin
#include <clients>
#include <usermessages>
#include <events>
#include <functions>
/**
* Declare this as a struct in your plugin to expose its information.

View File

@ -0,0 +1,85 @@
#include <sourcemod>
public Plugin:myinfo =
{
name = "FakeNative Testing Lab #1",
author = "AlliedModders LLC",
description = "Test suite #1 for dynamic natives",
version = "1.0.0.0",
url = "http://www.sourcemod.net/"
};
public bool:AskPluginLoad(Handle:myself, bool:late, String:error[], err_max)
{
CreateNative("TestNative1", __TestNative1);
CreateNative("TestNative2", __TestNative2);
CreateNative("TestNative3", __TestNative3);
CreateNative("TestNative4", __TestNative4);
CreateNative("TestNative5", __TestNative5);
return true;
}
public __TestNative1(Handle:plugin, numParams)
{
PrintToServer("TestNative1: Plugin: %x params: %d", plugin, numParams);
if (numParams == 4)
{
ThrowNativeError(SP_ERROR_NATIVE, "Four parameters ARE NOT ALLOWED lol");
}
return 5;
}
public __TestNative2(Handle:plugin, numParams)
{
new String:buffer[512];
new bytes;
GetNativeString(1, buffer, sizeof(buffer), bytes);
for (new i=0; i<bytes; i++)
{
buffer[i] = buffer[i] + 1;
}
SetNativeString(1, buffer, bytes+1);
}
public __TestNative3(Handle:plugin, numParams)
{
new val1 = GetNativeCell(1);
new val2 = GetNativeCellRef(2);
SetNativeCellRef(2, val1+val2);
}
public __TestNative4(Handle:plugin, numParams)
{
new size = GetNativeCell(3);
new local[size];
GetNativeArray(1, local, size);
SetNativeArray(2, local, size);
}
public __TestNative5(Handle:plugin, numParams)
{
new local = GetNativeCell(1);
if (local)
{
FormatNativeString(2, 4, 5, GetNativeCell(3));
} else {
new len = GetNativeCell(3);
new fmt_len;
new String:buffer[len];
GetNativeStringLength(4, fmt_len);
new String:format[fmt_len];
GetNativeString(2, buffer, len);
GetNativeString(4, format, fmt_len);
FormatNativeString(0, 0, 5, len, _, buffer, format);
}
}

View File

@ -0,0 +1,87 @@
#include <sourcemod>
native TestNative1(gaben, ...);
native TestNative2(String:buffer[]);
native TestNative3(value1, &value2);
native TestNative4(const input[], output[], size);
native TestNative5(bool:local, String:buffer[], maxlength, const String:fmt[], {Handle,Float,String,_}:...);
public Plugin:myinfo =
{
name = "FakeNative Testing Lab #2",
author = "AlliedModders LLC",
description = "Test suite #2 for dynamic natives",
version = "1.0.0.0",
url = "http://www.sourcemod.net/"
};
public OnPluginStart()
{
RegServerCmd("test_native1", Test_Native1);
RegServerCmd("test_native2", Test_Native2);
RegServerCmd("test_native3", Test_Native3);
RegServerCmd("test_native4", Test_Native4);
RegServerCmd("test_native5", Test_Native5);
}
public Action:Test_Native1(args)
{
PrintToServer("Returned: %d", TestNative1(1));
PrintToServer("Returned: %d", TestNative1(1,2));
PrintToServer("Returned: %d", TestNative1(1,2,3,4));
return Plugin_Handled;
}
public Action:Test_Native2(args)
{
new String:buffer[] = "IBM";
PrintToServer("Before: %s", buffer);
TestNative2(buffer);
PrintToServer("AfteR: %s", buffer);
return Plugin_Handled;
}
public Action:Test_Native3(args)
{
new value1 = 5, value2 = 6
PrintToServer("Before: %d, %d", value1, value2);
TestNative3(value1, value2);
PrintToServer("After: %d, %d", value1, value2);
return Plugin_Handled;
}
public Action:Test_Native4(args)
{
new input[5] = {0, 1, 2, 3, 4};
new output[5];
TestNative4(input, output, 5);
PrintToServer("[0=%d] [1=%d] [2=%d] [3=%d] [4=%d]", input[0], input[1], input[2], input[3], input[4]);
PrintToServer("[0=%d] [1=%d] [2=%d] [3=%d] [4=%d]", output[0], output[1], output[2], output[3], output[4]);
return Plugin_Handled;
}
public Action:Test_Native5(args)
{
new String:buffer1[512];
new String:buffer2[512];
TestNative5(true, buffer1, sizeof(buffer1), "%d gabens in the %s", 50, "gabpark");
TestNative5(true, buffer2, sizeof(buffer2), "%d gabens in the %s", 50, "gabpark");
PrintToServer("Test 1: %s", buffer1);
PrintToServer("Test 2: %s", buffer2);
return Plugin_Handled;
}

View File

@ -28,7 +28,7 @@
#include "sp_vm_types.h"
/** SourcePawn VM API Version */
#define SOURCEPAWN_VM_API_VERSION 1
#define SOURCEPAWN_VM_API_VERSION 2
#if defined SOURCEMOD_BUILD
namespace SourceMod
@ -820,6 +820,23 @@ namespace SourcePawn
* @return True if code index is valid, false otherwise.
*/
virtual bool FunctionPLookup(const sp_context_t *ctx, uint32_t code_addr, unsigned int *result) =0;
/**
* @brief Creates a fake native and binds it to a general callback function.
*
* @param callback Callback function to bind the native to.
* @param pData Private data to pass to the callback when the native is invoked.
* @return A new fake native function as a wrapper around the callback.
*/
virtual SPVM_NATIVE_FUNC CreateFakeNative(SPVM_FAKENATIVE_FUNC callback, void *pData) =0;
/**
* @brief Destroys a fake native function wrapper.
*
* @param function Pointer to the fake native created by CreateFakeNative.
* @noreturn
*/
virtual void DestroyFakenative(SPVM_NATIVE_FUNC func) =0;
};
};

View File

@ -136,6 +136,12 @@ struct sp_context_s;
*/
typedef cell_t (*SPVM_NATIVE_FUNC)(SourcePawn::IPluginContext *, const cell_t *);
/**
* @brief Fake native callback prototype, passed a context, parameter stack, and private data.
* A cell must be returned.
*/
typedef cell_t (*SPVM_FAKENATIVE_FUNC)(SourcePawn::IPluginContext *, const cell_t *, void *);
/**********************************************
*** The following structures are bound to the VM/JIT.
*** Changing them will result in necessary recompilation.

View File

@ -17,7 +17,7 @@
#include "dll_exports.h"
SourcePawn::ISourcePawnEngine *engine = NULL;
JITX86 jit;
JITX86 g_jit;
EXPORTFUNC int GiveEnginePointer(SourcePawn::ISourcePawnEngine *engine_p)
{
@ -45,7 +45,7 @@ EXPORTFUNC SourcePawn::IVirtualMachine *GetExport(unsigned int exportnum)
return NULL;
}
return &jit;
return &g_jit;
}
#if defined __linux__

View File

@ -2188,6 +2188,52 @@ jit_rewind:
return ctx;
}
SPVM_NATIVE_FUNC JITX86::CreateFakeNative(SPVM_FAKENATIVE_FUNC callback, void *pData)
{
JitWriter jw;
JitWriter *jit = &jw;
jw.outbase = NULL;
jw.outptr = NULL;
jw.data = NULL;
/* First pass, calculate size */
rewind:
//push pData ;push pData
//push [esp+12] ;push params
//push [esp+12] ;push ctx
//call [callback] ;invoke the meta-callback
//add esp, 12 ;restore the stack
//ret ;return
IA32_Push_Imm32(jit, (jit_int32_t)pData);
IA32_Push_Rm_Disp8_ESP(jit, 12);
IA32_Push_Rm_Disp8_ESP(jit, 12);
uint32_t call = IA32_Call_Imm32(jit, 0);
IA32_Write_Jump32_Abs(jit, call, (void *)callback);
IA32_Add_Rm_Imm8(jit, REG_ESP, 12, MOD_REG);
IA32_Return(jit);
if (jw.outbase == NULL)
{
/* Second pass: Actually write */
jw.outbase = (jitcode_t)engine->ExecAlloc(jw.get_outputpos());
if (!jw.outbase)
{
return NULL;
}
jw.outptr = jw.outbase;
goto rewind;
}
return (SPVM_NATIVE_FUNC)jw.outbase;
}
void JITX86::DestroyFakenative(SPVM_NATIVE_FUNC func)
{
engine->ExecFree(func);
}
const char *JITX86::GetVMName()
{
return "JIT (x86)";

View File

@ -98,6 +98,8 @@ public:
unsigned int FunctionCount(const sp_context_t *ctx);
const char *GetVersionString();
const char *GetCPUOptimizations();
SPVM_NATIVE_FUNC CreateFakeNative(SPVM_FAKENATIVE_FUNC callback, void *pData);
void DestroyFakenative(SPVM_NATIVE_FUNC func);
};
cell_t NativeCallback(sp_context_t *ctx, ucell_t native_idx, cell_t *params);

View File

@ -234,6 +234,10 @@
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
>
<File
RelativePath="..\jit_version.tpl"
>
</File>
<File
RelativePath="..\opcode_switch.inc"
>