diff --git a/core/Makefile b/core/Makefile
index 2b883445..995f425b 100644
--- a/core/Makefile
+++ b/core/Makefile
@@ -33,7 +33,8 @@ OBJECTS += ExtensionSys.cpp \
LibrarySys.cpp \
PluginInfoDatabase.cpp \
PluginSys.cpp \
- ShareSys.cpp
+ ShareSys.cpp \
+ NativeInvoker.cpp
OBJECTS += thread/ThreadWorker.cpp thread/BaseWorker.cpp thread/PosixThreads.cpp ThreadSupport.cpp
##############################################
diff --git a/core/NativeInvoker.cpp b/core/NativeInvoker.cpp
new file mode 100644
index 00000000..3759684c
--- /dev/null
+++ b/core/NativeInvoker.cpp
@@ -0,0 +1,379 @@
+/**
+ * vim: set ts=4 :
+ * =============================================================================
+ * SourcePawn
+ * Copyright (C) 2004-2009 AlliedModders LLC. All rights reserved.
+ * =============================================================================
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, version 3.0, as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see .
+ *
+ * As a special exception, AlliedModders LLC gives you permission to link the
+ * code of this program (as well as its derivative works) to "Half-Life 2," the
+ * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
+ * by the Valve Corporation. You must obey the GNU General Public License in
+ * all respects for all other code used. Additionally, AlliedModders LLC grants
+ * this exception to all derivative works. AlliedModders LLC defines further
+ * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
+ * or .
+ *
+ * Version: $Id$
+ */
+
+#include "NativeInvoker.h"
+#include "ShareSys.h"
+
+NativeInterface g_NInvoke;
+
+NativeInvoker::NativeInvoker()
+{
+}
+
+NativeInvoker::~NativeInvoker()
+{
+}
+
+const char *NativeInterface::GetInterfaceName()
+{
+ return SMINTERFACE_NINVOKE_NAME;
+}
+
+unsigned int NativeInterface::GetInterfaceVersion()
+{
+ return SMINTERFACE_NINVOKE_VERSION;
+}
+
+void NativeInterface::OnSourceModAllInitialized()
+{
+ g_ShareSys.AddInterface(NULL, &g_NInvoke);
+}
+
+IPluginRuntime *NativeInterface::CreateRuntime(const char *name, size_t bytes)
+{
+ return g_pSourcePawn2->CreateEmptyRuntime(name, bytes);
+}
+
+INativeInvoker *NativeInterface::CreateInvoker()
+{
+ return new NativeInvoker();
+}
+
+bool NativeInvoker::Start(IPluginContext *pContext, const char *name)
+{
+ NativeEntry *entry;
+
+ entry = g_ShareSys.FindNative(name);
+ if (entry == NULL)
+ {
+ return false;
+ }
+
+ native = NULL;
+ if (entry->replacement.owner != NULL)
+ {
+ native = entry->replacement.func;
+ }
+ else if (entry->owner != NULL)
+ {
+ native = entry->func;
+ }
+
+ if (native == NULL)
+ {
+ return false;
+ }
+
+ this->pContext = pContext;
+
+ m_curparam = 0;
+ m_errorstate = SP_ERROR_NONE;
+
+ return true;
+}
+
+cell_t NativeInvoker::PushCell(cell_t cell)
+{
+ if (m_curparam >= SP_MAX_EXEC_PARAMS)
+ {
+ return SetError(SP_ERROR_PARAMS_MAX);
+ }
+
+ m_info[m_curparam].marked = false;
+ m_params[m_curparam] = cell;
+ m_curparam++;
+
+ return SP_ERROR_NONE;
+}
+
+int NativeInvoker::PushCellByRef(cell_t *cell, int flags)
+{
+ return PushArray(cell, 1, flags);
+}
+
+int NativeInvoker::PushFloat(float number)
+{
+ cell_t val = *(cell_t *)&number;
+
+ return PushCell(val);
+}
+
+int NativeInvoker::PushFloatByRef(float *number, int flags)
+{
+ return PushCellByRef((cell_t *)number, flags);
+}
+
+int NativeInvoker::PushArray(cell_t *inarray, unsigned int cells, int copyback)
+{
+ if (m_curparam >= SP_MAX_EXEC_PARAMS)
+ {
+ return SetError(SP_ERROR_PARAMS_MAX);
+ }
+
+ ParamInfo *info = &m_info[m_curparam];
+
+ info->flags = inarray ? copyback : 0;
+ info->marked = true;
+ info->size = cells;
+ info->str.is_sz = false;
+ info->orig_addr = inarray;
+
+ m_curparam++;
+
+ return SP_ERROR_NONE;
+}
+
+int NativeInvoker::PushString(const char *string)
+{
+ return _PushString(string, SM_PARAM_STRING_COPY, 0, strlen(string)+1);
+}
+
+int NativeInvoker::PushStringEx(char *buffer, size_t length, int sz_flags, int cp_flags)
+{
+ return _PushString(buffer, sz_flags, cp_flags, length);
+}
+
+int NativeInvoker::_PushString(const char *string, int sz_flags, int cp_flags, size_t len)
+{
+ if (m_curparam >= SP_MAX_EXEC_PARAMS)
+ {
+ return SetError(SP_ERROR_PARAMS_MAX);
+ }
+
+ ParamInfo *info = &m_info[m_curparam];
+
+ info->marked = true;
+ info->orig_addr = (cell_t *)string;
+ info->flags = cp_flags;
+ info->size = len;
+ info->str.sz_flags = sz_flags;
+ info->str.is_sz = true;
+
+ m_curparam++;
+
+ return SP_ERROR_NONE;
+}
+
+void NativeInvoker::Cancel()
+{
+ if (pContext == NULL)
+ {
+ return;
+ }
+
+ m_errorstate = SP_ERROR_NONE;
+ m_curparam = 0;
+ pContext = NULL;
+ native = NULL;
+}
+
+int NativeInvoker::SetError(int err)
+{
+ m_errorstate = err;
+ return err;
+}
+
+int NativeInvoker::Invoke(cell_t *result)
+{
+ int err = SP_ERROR_NONE;
+
+ if (pContext == NULL)
+ {
+ return SP_ERROR_INVALID_NATIVE;
+ }
+
+ if (m_errorstate != SP_ERROR_NONE)
+ {
+ err = m_errorstate;
+ Cancel();
+ return err;
+ }
+
+ cell_t tresult;
+
+ if (result == NULL)
+ {
+ result = &tresult;
+ }
+
+ //This is for re-entrancy!
+ IPluginContext *ctx = pContext;
+ cell_t _temp_params[SP_MAX_EXEC_PARAMS + 1];
+ cell_t *temp_params = &_temp_params[1];
+ ParamInfo temp_info[SP_MAX_EXEC_PARAMS];
+ unsigned int numparams = m_curparam;
+ unsigned int i;
+ bool docopies = true;
+
+ if (numparams)
+ {
+ //Save the info locally, then reset it for re-entrant calls.
+ memcpy(temp_info, m_info, numparams * sizeof(ParamInfo));
+ }
+ m_curparam = 0;
+ pContext = NULL;
+
+ /* Initialize 0th parameter */
+ _temp_params[0] = numparams;
+
+ /* Browse the parameters and build arrays */
+ for (i = 0; i < numparams; i++)
+ {
+ /* Is this marked as an array? */
+ if (temp_info[i].marked)
+ {
+ if (!temp_info[i].str.is_sz)
+ {
+ /* Allocate a normal/generic array */
+ if ((err = ctx->HeapAlloc(temp_info[i].size,
+ &temp_info[i].local_addr,
+ &temp_info[i].phys_addr))
+ != SP_ERROR_NONE)
+ {
+ break;
+ }
+ if (temp_info[i].orig_addr)
+ {
+ memcpy(temp_info[i].phys_addr, temp_info[i].orig_addr, sizeof(cell_t) * temp_info[i].size);
+ }
+ }
+ else
+ {
+ /* Calculate cells required for the string */
+ size_t cells = (temp_info[i].size + sizeof(cell_t) - 1) / sizeof(cell_t);
+
+ /* Allocate the buffer */
+ if ((err = ctx->HeapAlloc(cells,
+ &temp_info[i].local_addr,
+ &temp_info[i].phys_addr))
+ != SP_ERROR_NONE)
+ {
+ break;
+ }
+ /* Copy original string if necessary */
+ if ((temp_info[i].str.sz_flags & SM_PARAM_STRING_COPY) && (temp_info[i].orig_addr != NULL))
+ {
+ /* Cut off UTF-8 properly */
+ if (temp_info[i].str.sz_flags & SM_PARAM_STRING_UTF8)
+ {
+ if ((err = ctx->StringToLocalUTF8(temp_info[i].local_addr,
+ temp_info[i].size,
+ (const char *)temp_info[i].orig_addr,
+ NULL))
+ != SP_ERROR_NONE)
+ {
+ break;
+ }
+ }
+ /* Copy a binary blob */
+ else if (temp_info[i].str.sz_flags & SM_PARAM_STRING_BINARY)
+ {
+ memmove(temp_info[i].phys_addr, temp_info[i].orig_addr, temp_info[i].size);
+ }
+ /* Copy ASCII characters */
+ else
+ {
+ if ((err = ctx->StringToLocal(temp_info[i].local_addr,
+ temp_info[i].size,
+ (const char *)temp_info[i].orig_addr))
+ != SP_ERROR_NONE)
+ {
+ break;
+ }
+ }
+ }
+ } /* End array/string calculation */
+ /* Update the pushed parameter with the byref local address */
+ temp_params[i] = temp_info[i].local_addr;
+ }
+ else
+ {
+ /* Just copy the value normally */
+ temp_params[i] = m_params[i];
+ }
+ }
+
+ /* Make the call if we can */
+ if (err == SP_ERROR_NONE)
+ {
+ *result = native(ctx, _temp_params);
+ if (ctx->GetLastNativeError() != SP_ERROR_NONE)
+ {
+ docopies = false;
+ ctx->ClearLastNativeError();
+ }
+ }
+ else
+ {
+ docopies = false;
+ }
+
+ /* i should be equal to the last valid parameter + 1 */
+ while (i--)
+ {
+ if (!temp_info[i].marked)
+ {
+ continue;
+ }
+
+ if (docopies && (temp_info[i].flags & SM_PARAM_COPYBACK))
+ {
+ if (temp_info[i].orig_addr)
+ {
+ if (temp_info[i].str.is_sz)
+ {
+ memcpy(temp_info[i].orig_addr, temp_info[i].phys_addr, temp_info[i].size);
+
+ }
+ else
+ {
+ if (temp_info[i].size == 1)
+ {
+ *temp_info[i].orig_addr = *(temp_info[i].phys_addr);
+ }
+ else
+ {
+ memcpy(temp_info[i].orig_addr,
+ temp_info[i].phys_addr,
+ temp_info[i].size * sizeof(cell_t));
+ }
+ }
+ }
+ }
+
+ if ((err = ctx->HeapPop(temp_info[i].local_addr)) != SP_ERROR_NONE)
+ {
+ return err;
+ }
+ }
+
+ return err;
+}
diff --git a/core/NativeInvoker.h b/core/NativeInvoker.h
new file mode 100644
index 00000000..120b7019
--- /dev/null
+++ b/core/NativeInvoker.h
@@ -0,0 +1,98 @@
+/**
+ * vim: set ts=4 :
+ * =============================================================================
+ * SourceMod
+ * Copyright (C) 2004-2009 AlliedModders LLC. All rights reserved.
+ * =============================================================================
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, version 3.0, as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see .
+ *
+ * As a special exception, AlliedModders LLC gives you permission to link the
+ * code of this program (as well as its derivative works) to "Half-Life 2," the
+ * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
+ * by the Valve Corporation. You must obey the GNU General Public License in
+ * all respects for all other code used. Additionally, AlliedModders LLC grants
+ * this exception to all derivative works. AlliedModders LLC defines further
+ * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
+ * or .
+ *
+ * Version: $Id$
+ */
+
+#ifndef _INCLUDE_SOURCEMOD_NATIVE_INVOKER_H_
+#define _INCLUDE_SOURCEMOD_NATIVE_INVOKER_H_
+
+#include "sm_globals.h"
+#include
+
+struct ParamInfo
+{
+ int flags; /* Copy-back flags */
+ bool marked; /* Whether this is marked as being used */
+ cell_t local_addr; /* Local address to free */
+ cell_t *phys_addr; /* Physical address of our copy */
+ cell_t *orig_addr; /* Original address to copy back to */
+ ucell_t size; /* Size of array in bytes */
+ struct
+ {
+ bool is_sz; /* is a string */
+ int sz_flags; /* has sz flags */
+ } str;
+};
+
+class NativeInvoker : public INativeInvoker
+{
+public:
+ NativeInvoker();
+ ~NativeInvoker();
+public: /* ICallable */
+ int PushCell(cell_t cell);
+ int PushCellByRef(cell_t *cell, int flags=SM_PARAM_COPYBACK);
+ int PushFloat(float number);
+ int PushFloatByRef(float *number, int flags=SM_PARAM_COPYBACK);
+ int PushArray(cell_t *inarray, unsigned int cells, int flags=0);
+ int PushString(const char *string);
+ int PushStringEx(char *buffer, size_t length, int sz_flags, int cp_flags);
+ void Cancel();
+public: /* INativeInvoker */
+ bool Start(IPluginContext *pContext, const char *name);
+ int Invoke(cell_t *result);
+private:
+ int _PushString(const char *string, int sz_flags, int cp_flags, size_t len);
+ int SetError(int err);
+private:
+ IPluginContext *pContext;
+ SPVM_NATIVE_FUNC native;
+ cell_t m_params[SP_MAX_EXEC_PARAMS];
+ ParamInfo m_info[SP_MAX_EXEC_PARAMS];
+ unsigned int m_curparam;
+ int m_errorstate;
+};
+
+class NativeInterface :
+ public INativeInterface,
+ public SMGlobalClass
+{
+public: /* SMGlobalClass */
+ void OnSourceModAllInitialized();
+public: /* SMInterface */
+ unsigned int GetInterfaceVersion();
+ const char *GetInterfaceName();
+public: /* INativeInvoker */
+ IPluginRuntime *CreateRuntime(const char *name, size_t bytes);
+ INativeInvoker *CreateInvoker();
+};
+
+extern NativeInterface g_NInvoke;
+
+#endif /* _INCLUDE_SOURCEMOD_NATIVE_INVOKER_H_ */
diff --git a/core/ShareSys.h b/core/ShareSys.h
index ffba6b56..b600f9c2 100644
--- a/core/ShareSys.h
+++ b/core/ShareSys.h
@@ -128,10 +128,10 @@ public:
void BindNativesToPlugin(CPlugin *pPlugin, bool bCoreOnly);
void BindNativeToPlugin(CPlugin *pPlugin, NativeEntry *pEntry);
NativeEntry *AddFakeNative(IPluginFunction *pFunc, const char *name, SPVM_FAKENATIVE_FUNC func);
+ NativeEntry *FindNative(const char *name);
private:
NativeEntry *AddNativeToCache(CNativeOwner *pOwner, const sp_nativeinfo_t *ntv);
void ClearNativeFromCache(CNativeOwner *pOwner, const char *name);
- NativeEntry *FindNative(const char *name);
void BindNativeToPlugin(CPlugin *pPlugin,
sp_native_t *ntv,
uint32_t index,
diff --git a/core/msvc9/sourcemod_mm.vcproj b/core/msvc9/sourcemod_mm.vcproj
index 8ee550bf..6372c961 100644
--- a/core/msvc9/sourcemod_mm.vcproj
+++ b/core/msvc9/sourcemod_mm.vcproj
@@ -1185,6 +1185,10 @@
RelativePath="..\MenuVoting.cpp"
>
+
+
@@ -1391,6 +1395,10 @@
RelativePath="..\MenuVoting.h"
>
+
+
@@ -1556,6 +1564,10 @@
RelativePath="..\..\public\IMenuManager.h"
>
+
+
diff --git a/core/sourcemod.cpp b/core/sourcemod.cpp
index 20a4cd36..b61abcd9 100644
--- a/core/sourcemod.cpp
+++ b/core/sourcemod.cpp
@@ -200,7 +200,7 @@ bool SourceModBase::InitializeSourceMod(char *error, size_t maxlength, bool late
g_pSourcePawn = getv1();
g_pSourcePawn2 = getv2();
- if (g_pSourcePawn2->GetAPIVersion() < 2)
+ if (g_pSourcePawn2->GetAPIVersion() < 3)
{
g_pSourcePawn2 = NULL;
if (error && maxlength)
diff --git a/public/INativeInvoker.h b/public/INativeInvoker.h
new file mode 100644
index 00000000..1c7025b5
--- /dev/null
+++ b/public/INativeInvoker.h
@@ -0,0 +1,106 @@
+/**
+ * vim: set ts=4 :
+ * =============================================================================
+ * SourceMod
+ * Copyright (C) 2004-2009 AlliedModders LLC. All rights reserved.
+ * =============================================================================
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, version 3.0, as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see .
+ *
+ * As a special exception, AlliedModders LLC gives you permission to link the
+ * code of this program (as well as its derivative works) to "Half-Life 2," the
+ * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
+ * by the Valve Corporation. You must obey the GNU General Public License in
+ * all respects for all other code used. Additionally, AlliedModders LLC grants
+ * this exception to all derivative works. AlliedModders LLC defines further
+ * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
+ * or .
+ *
+ * Version: $Id$
+ */
+
+#ifndef _INCLUDE_SOURCEMOD_INATIVEINVOKER_H_
+#define _INCLUDE_SOURCEMOD_INATIVEINVOKER_H_
+
+/**
+ * @file INativeInvoker.h
+ * @brief Interface for invoking natives.
+ */
+
+#include
+
+#define SMINTERFACE_NINVOKE_NAME "INativeInterface"
+#define SMINTERFACE_NINVOKE_VERSION 1
+
+#define NINVOKE_DEFAULT_MEMORY 16384
+
+namespace SourceMod
+{
+ class INativeInvoker : public SourcePawn::ICallable
+ {
+ public:
+ /**
+ * @brief Virtual destructor - use delete to free this.
+ */
+ virtual ~INativeInvoker()
+ {
+ }
+ public:
+ /**
+ * @brief Begins a native call.
+ *
+ * During a call's preparation, no new calls may be started.
+ *
+ * @param pContext Context to invoke native under.
+ * @param name Name of native.
+ * @return True if native was found, false otherwise.
+ */
+ virtual bool Start(IPluginContext *pContext, const char *name) = 0;
+
+ /**
+ * @brief Invokes the native. The preparation state is cleared immediately, meaning that
+ * this object can be re-used after or even from inside the native being called.
+ *
+ * @param result Optional pointer to retrieve a result.
+ * @return SP_ERROR return code.
+ */
+ virtual int Invoke(cell_t *result) = 0;
+ };
+
+ /**
+ * @brief Factory for dealing with native invocations.
+ */
+ class INativeInterface : public SMInterface
+ {
+ public:
+ /**
+ * @brief Creates a virtual plugin. This can be used as an environment to invoke natives.
+ *
+ * IPluginRuntime objects must be freed with the delete operator.
+ *
+ * @param name Name, or NULL for anonymous.
+ * @param bytes Number of bytes for memory (NINVOKE_DEFAULT_MEMORY recommended).
+ * @return New runtime, or NULL on failure.
+ */
+ virtual IPluginRuntime *CreateRuntime(const char *name, size_t bytes) = 0;
+
+ /**
+ * @brief Creates an object that can be used to invoke a single native code.
+ *
+ * @return New native invoker (free with delete).
+ */
+ virtual INativeInvoker *CreateInvoker() = 0;
+ };
+}
+
+#endif /* _INCLUDE_SOURCEMOD_INATIVEINVOKER_H_ */
diff --git a/public/sample_ext/sdk/smsdk_config.h b/public/sample_ext/sdk/smsdk_config.h
index 3d4f60cc..d272d3d5 100644
--- a/public/sample_ext/sdk/smsdk_config.h
+++ b/public/sample_ext/sdk/smsdk_config.h
@@ -76,5 +76,6 @@
//#define SMEXT_ENABLE_TEXTPARSERS
//#define SMEXT_ENABLE_USERMSGS
//#define SMEXT_ENABLE_TRANSLATOR
+//#define SMEXT_ENABLE_NINVOKE
#endif // _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_
diff --git a/public/sample_ext/sdk/smsdk_ext.cpp b/public/sample_ext/sdk/smsdk_ext.cpp
index 6404a919..f31352d9 100644
--- a/public/sample_ext/sdk/smsdk_ext.cpp
+++ b/public/sample_ext/sdk/smsdk_ext.cpp
@@ -97,6 +97,9 @@ IUserMessages *usermsgs = NULL;
#if defined SMEXT_ENABLE_TRANSLATOR
ITranslator *translator = NULL;
#endif
+#if defined SMEXT_ENABLE_NINVOKE
+INativeInterface *ninvoke = NULL;
+#endif
/** Exports the main interface */
PLATFORM_EXTERN_C IExtensionInterface *GetSMExtAPI()
diff --git a/public/sample_ext/sdk/smsdk_ext.h b/public/sample_ext/sdk/smsdk_ext.h
index 115fc800..61861866 100644
--- a/public/sample_ext/sdk/smsdk_ext.h
+++ b/public/sample_ext/sdk/smsdk_ext.h
@@ -91,6 +91,9 @@
#if defined SMEXT_ENABLE_TRANSLATOR
#include
#endif
+#if defined SMEXT_ENABLE_NINVOKE
+#include
+#endif
#if defined SMEXT_CONF_METAMOD
#include
@@ -289,6 +292,9 @@ extern IUserMessages *usermsgs;
#if defined SMEXT_ENABLE_TRANSLATOR
extern ITranslator *translator;
#endif
+#if defined SMEXT_ENABLE_NINVOKE
+extern INativeInterface *ninvoke;
+#endif
#if defined SMEXT_CONF_METAMOD
PLUGIN_GLOBALVARS();
diff --git a/public/sourcepawn/sp_vm_api.h b/public/sourcepawn/sp_vm_api.h
index 7938c12e..65e7fa3f 100644
--- a/public/sourcepawn/sp_vm_api.h
+++ b/public/sourcepawn/sp_vm_api.h
@@ -42,7 +42,7 @@
/** SourcePawn Engine API Version */
#define SOURCEPAWN_ENGINE_API_VERSION 4
-#define SOURCEPAWN_ENGINE2_API_VERSION 2
+#define SOURCEPAWN_ENGINE2_API_VERSION 3
#if !defined SOURCEMOD_BUILD
#define SOURCEMOD_BUILD
@@ -876,6 +876,11 @@ namespace SourcePawn
* @return True on success, false on failure.
*/
virtual bool GetKey(int k, void **value) =0;
+
+ /**
+ * @brief Clears the last native error.
+ */
+ virtual void ClearLastNativeError() =0;
};
@@ -1252,6 +1257,15 @@ namespace SourcePawn
* Initialize() succeeded.
*/
virtual void Shutdown() =0;
+
+ /**
+ * @brief Creates an empty plugin with a blob of memory.
+ *
+ * @param name Name, for debugging (NULL for anonymous).
+ * @param bytes Number of bytes of memory (hea+stk).
+ * @return New runtime, or NULL if not enough memory.
+ */
+ virtual IPluginRuntime *CreateEmptyRuntime(const char *name, uint32_t memory) =0;
};
};
diff --git a/sourcepawn/jit/BaseRuntime.cpp b/sourcepawn/jit/BaseRuntime.cpp
index a4d88def..942eea28 100644
--- a/sourcepawn/jit/BaseRuntime.cpp
+++ b/sourcepawn/jit/BaseRuntime.cpp
@@ -535,3 +535,21 @@ uint32_t BaseRuntime::AddJittedFunction(JitFunction *fn)
return m_NumFuncs;
}
+
+int BaseRuntime::CreateBlank(uint32_t heastk)
+{
+ memset(m_pPlugin, 0, sizeof(sp_plugin_t));
+
+ /* Align to cell_t bytes */
+ heastk += sizeof(cell_t);
+ heastk -= heastk % sizeof(cell_t);
+
+ m_pPlugin->mem_size = heastk;
+ m_pPlugin->memory = new uint8_t[heastk];
+
+ m_pPlugin->profiler = g_engine2.GetProfiler();
+ m_pCtx = new BaseContext(this);
+ m_pCo = g_Jit.StartCompilation(this);
+
+ return SP_ERROR_NONE;
+}
diff --git a/sourcepawn/jit/BaseRuntime.h b/sourcepawn/jit/BaseRuntime.h
index bcd797ae..2217db8f 100644
--- a/sourcepawn/jit/BaseRuntime.h
+++ b/sourcepawn/jit/BaseRuntime.h
@@ -27,6 +27,7 @@ public:
BaseRuntime();
~BaseRuntime();
public:
+ virtual int CreateBlank(uint32_t heastk);
virtual int CreateFromMemory(sp_file_hdr_t *hdr, uint8_t *base);
virtual bool IsDebugging();
virtual IPluginDebugInfo *GetDebugInfo();
diff --git a/sourcepawn/jit/engine2.cpp b/sourcepawn/jit/engine2.cpp
index 4793611c..ad4aa9a8 100644
--- a/sourcepawn/jit/engine2.cpp
+++ b/sourcepawn/jit/engine2.cpp
@@ -191,3 +191,22 @@ void SourcePawnEngine2::Shutdown()
{
g_Jit.ShutdownJIT();
}
+
+IPluginRuntime *SourcePawnEngine2::CreateEmptyRuntime(const char *name, uint32_t memory)
+{
+ int err;
+ BaseRuntime *rt;
+
+ rt = new BaseRuntime();
+ if ((err = rt->CreateBlank(memory)) != SP_ERROR_NONE)
+ {
+ delete rt;
+ return NULL;
+ }
+
+ rt->m_pPlugin->name = strdup(name != NULL ? name : "");
+
+ rt->ApplyCompilationOptions(NULL);
+
+ return rt;
+}
diff --git a/sourcepawn/jit/engine2.h b/sourcepawn/jit/engine2.h
index 6198df7a..b35410d5 100644
--- a/sourcepawn/jit/engine2.h
+++ b/sourcepawn/jit/engine2.h
@@ -25,6 +25,7 @@ namespace SourcePawn
const char *GetErrorString(int err);
bool Initialize();
void Shutdown();
+ IPluginRuntime *CreateEmptyRuntime(const char *name, uint32_t memory);
public:
IProfiler *GetProfiler();
private:
diff --git a/sourcepawn/jit/sp_vm_basecontext.cpp b/sourcepawn/jit/sp_vm_basecontext.cpp
index 7fa902fe..8c91b9df 100644
--- a/sourcepawn/jit/sp_vm_basecontext.cpp
+++ b/sourcepawn/jit/sp_vm_basecontext.cpp
@@ -873,3 +873,8 @@ bool BaseContext::GetKey(int k, void **value)
return true;
}
+
+void BaseContext::ClearLastNativeError()
+{
+ m_ctx.n_err = SP_ERROR_NONE;
+}
diff --git a/sourcepawn/jit/sp_vm_basecontext.h b/sourcepawn/jit/sp_vm_basecontext.h
index b92b33df..7bd5058a 100644
--- a/sourcepawn/jit/sp_vm_basecontext.h
+++ b/sourcepawn/jit/sp_vm_basecontext.h
@@ -93,6 +93,7 @@ public: //IPluginContext
void SetKey(int k, void *value);
bool GetKey(int k, void **value);
void Refresh();
+ void ClearLastNativeError();
public:
bool IsInExec();
private: