Merge pull request #270 from alliedmodders/modernize-vm-style

Modernize sourcepawn/jit style.
This commit is contained in:
David Anderson 2015-02-23 14:38:28 -08:00
commit 7d64ade621
8 changed files with 1382 additions and 1497 deletions

View File

@ -1,4 +1,15 @@
// vim: set ts=4 sw=4 tw=99 noet: // vim: set sts=2 ts=8 sw=2 tw=99 et:
//
// Copyright (C) 2006-2015 AlliedModders LLC
//
// This file is part of SourcePawn. SourcePawn is free software: you can
// redistribute it and/or modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation, either version 3 of
// the License, or (at your option) any later version.
//
// You should have received a copy of the GNU General Public License along with
// SourcePawn. If not, see http://www.gnu.org/licenses/.
//
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@ -14,199 +25,208 @@ using namespace SourcePawn;
SourcePawnEngine2::SourcePawnEngine2() SourcePawnEngine2::SourcePawnEngine2()
{ {
profiler_ = NULL; profiler_ = NULL;
jit_enabled_ = true; jit_enabled_ = true;
} }
IPluginRuntime *SourcePawnEngine2::LoadPlugin(ICompilation *co, const char *file, int *err) IPluginRuntime *
SourcePawnEngine2::LoadPlugin(ICompilation *co, const char *file, int *err)
{ {
sp_file_hdr_t hdr; sp_file_hdr_t hdr;
uint8_t *base; uint8_t *base;
int z_result; int z_result;
int error; int error;
BaseRuntime *pRuntime; size_t ignore;
BaseRuntime *pRuntime;
FILE *fp = fopen(file, "rb"); FILE *fp = fopen(file, "rb");
if (!fp) if (!fp) {
{ error = SP_ERROR_NOT_FOUND;
error = SP_ERROR_NOT_FOUND; goto return_error;
goto return_error; }
}
/* Rewind for safety */ /* Rewind for safety */
fread(&hdr, sizeof(sp_file_hdr_t), 1, fp); ignore = fread(&hdr, sizeof(sp_file_hdr_t), 1, fp);
if (hdr.magic != SmxConsts::FILE_MAGIC) if (hdr.magic != SmxConsts::FILE_MAGIC) {
{ error = SP_ERROR_FILE_FORMAT;
error = SP_ERROR_FILE_FORMAT; goto return_error;
goto return_error; }
}
switch (hdr.compression) switch (hdr.compression)
{ {
case SmxConsts::FILE_COMPRESSION_GZ: case SmxConsts::FILE_COMPRESSION_GZ:
{ {
uint32_t uncompsize = hdr.imagesize - hdr.dataoffs; uint32_t uncompsize = hdr.imagesize - hdr.dataoffs;
uint32_t compsize = hdr.disksize - hdr.dataoffs; uint32_t compsize = hdr.disksize - hdr.dataoffs;
uint32_t sectsize = hdr.dataoffs - sizeof(sp_file_hdr_t); uint32_t sectsize = hdr.dataoffs - sizeof(sp_file_hdr_t);
uLongf destlen = uncompsize; uLongf destlen = uncompsize;
char *tempbuf = (char *)malloc(compsize); char *tempbuf = (char *)malloc(compsize);
void *uncompdata = malloc(uncompsize); void *uncompdata = malloc(uncompsize);
void *sectheader = malloc(sectsize); void *sectheader = malloc(sectsize);
fread(sectheader, sectsize, 1, fp); ignore = fread(sectheader, sectsize, 1, fp);
fread(tempbuf, compsize, 1, fp); ignore = fread(tempbuf, compsize, 1, fp);
z_result = uncompress((Bytef *)uncompdata, &destlen, (Bytef *)tempbuf, compsize); z_result = uncompress((Bytef *)uncompdata, &destlen, (Bytef *)tempbuf, compsize);
free(tempbuf); free(tempbuf);
if (z_result != Z_OK) if (z_result != Z_OK)
{ {
free(sectheader); free(sectheader);
free(uncompdata); free(uncompdata);
error = SP_ERROR_DECOMPRESSOR; error = SP_ERROR_DECOMPRESSOR;
goto return_error; goto return_error;
} }
base = (uint8_t *)malloc(hdr.imagesize); base = (uint8_t *)malloc(hdr.imagesize);
memcpy(base, &hdr, sizeof(sp_file_hdr_t)); memcpy(base, &hdr, sizeof(sp_file_hdr_t));
memcpy(base + sizeof(sp_file_hdr_t), sectheader, sectsize); memcpy(base + sizeof(sp_file_hdr_t), sectheader, sectsize);
free(sectheader); free(sectheader);
memcpy(base + hdr.dataoffs, uncompdata, uncompsize); memcpy(base + hdr.dataoffs, uncompdata, uncompsize);
free(uncompdata); free(uncompdata);
break; break;
} }
case SmxConsts::FILE_COMPRESSION_NONE: case SmxConsts::FILE_COMPRESSION_NONE:
{ {
base = (uint8_t *)malloc(hdr.imagesize); base = (uint8_t *)malloc(hdr.imagesize);
rewind(fp); rewind(fp);
fread(base, hdr.imagesize, 1, fp); ignore = fread(base, hdr.imagesize, 1, fp);
break; break;
} }
default: default:
{ {
error = SP_ERROR_DECOMPRESSOR; error = SP_ERROR_DECOMPRESSOR;
goto return_error; goto return_error;
} }
} }
pRuntime = new BaseRuntime(); pRuntime = new BaseRuntime();
if ((error = pRuntime->CreateFromMemory(&hdr, base)) != SP_ERROR_NONE) if ((error = pRuntime->CreateFromMemory(&hdr, base)) != SP_ERROR_NONE) {
{ delete pRuntime;
delete pRuntime; goto return_error;
goto return_error; }
}
size_t len; size_t len;
len = strlen(file); len = strlen(file);
for (size_t i = len - 1; i < len; i--) for (size_t i = len - 1; i < len; i--)
{ {
if (file[i] == '/' if (file[i] == '/'
#if defined WIN32 #if defined WIN32
|| file[i] == '\\' || file[i] == '\\'
#endif #endif
) )
{ {
pRuntime->SetName(&file[i+1]); pRuntime->SetName(&file[i+1]);
break; break;
} }
} }
if (!pRuntime->plugin()->name) (void)ignore;
{
pRuntime->SetName(file);
}
pRuntime->ApplyCompilationOptions(co); if (!pRuntime->plugin()->name)
pRuntime->SetName(file);
fclose(fp); pRuntime->ApplyCompilationOptions(co);
return pRuntime; fclose(fp);
return pRuntime;
return_error: return_error:
*err = error; *err = error;
if (fp != NULL) if (fp != NULL)
{ {
fclose(fp); fclose(fp);
} }
return NULL; return NULL;
} }
SPVM_NATIVE_FUNC SourcePawnEngine2::CreateFakeNative(SPVM_FAKENATIVE_FUNC callback, void *pData) SPVM_NATIVE_FUNC
SourcePawnEngine2::CreateFakeNative(SPVM_FAKENATIVE_FUNC callback, void *pData)
{ {
return g_Jit.CreateFakeNative(callback, pData); return g_Jit.CreateFakeNative(callback, pData);
} }
void SourcePawnEngine2::DestroyFakeNative(SPVM_NATIVE_FUNC func) void
SourcePawnEngine2::DestroyFakeNative(SPVM_NATIVE_FUNC func)
{ {
g_Jit.DestroyFakeNative(func); g_Jit.DestroyFakeNative(func);
} }
const char *SourcePawnEngine2::GetEngineName() const char *
SourcePawnEngine2::GetEngineName()
{ {
return "SourcePawn 1.7, jit-x86"; return "SourcePawn 1.7, jit-x86";
} }
const char *SourcePawnEngine2::GetVersionString() const char *
SourcePawnEngine2::GetVersionString()
{ {
return SOURCEMOD_VERSION; return SOURCEMOD_VERSION;
} }
IDebugListener *SourcePawnEngine2::SetDebugListener(IDebugListener *listener) IDebugListener *
SourcePawnEngine2::SetDebugListener(IDebugListener *listener)
{ {
return g_engine1.SetDebugListener(listener); return g_engine1.SetDebugListener(listener);
} }
unsigned int SourcePawnEngine2::GetAPIVersion() unsigned int
SourcePawnEngine2::GetAPIVersion()
{ {
return SOURCEPAWN_ENGINE2_API_VERSION; return SOURCEPAWN_ENGINE2_API_VERSION;
} }
ICompilation *SourcePawnEngine2::StartCompilation() ICompilation *
SourcePawnEngine2::StartCompilation()
{ {
return g_Jit.StartCompilation(); return g_Jit.StartCompilation();
} }
const char *SourcePawnEngine2::GetErrorString(int err) const char *
SourcePawnEngine2::GetErrorString(int err)
{ {
return g_engine1.GetErrorString(err); return g_engine1.GetErrorString(err);
} }
bool SourcePawnEngine2::Initialize() bool
SourcePawnEngine2::Initialize()
{ {
return g_Jit.InitializeJIT(); return g_Jit.InitializeJIT();
} }
void SourcePawnEngine2::Shutdown() void
SourcePawnEngine2::Shutdown()
{ {
g_WatchdogTimer.Shutdown(); g_WatchdogTimer.Shutdown();
g_Jit.ShutdownJIT(); g_Jit.ShutdownJIT();
} }
IPluginRuntime *SourcePawnEngine2::CreateEmptyRuntime(const char *name, uint32_t memory) IPluginRuntime *
SourcePawnEngine2::CreateEmptyRuntime(const char *name, uint32_t memory)
{ {
int err; int err;
BaseRuntime *rt;
rt = new BaseRuntime(); BaseRuntime *rt = new BaseRuntime();
if ((err = rt->CreateBlank(memory)) != SP_ERROR_NONE) if ((err = rt->CreateBlank(memory)) != SP_ERROR_NONE) {
{ delete rt;
delete rt; return NULL;
return NULL; }
}
rt->SetName(name != NULL ? name : "<anonymous>"); rt->SetName(name != NULL ? name : "<anonymous>");
rt->ApplyCompilationOptions(NULL); rt->ApplyCompilationOptions(NULL);
return rt; return rt;
} }
bool SourcePawnEngine2::InstallWatchdogTimer(size_t timeout_ms) bool
SourcePawnEngine2::InstallWatchdogTimer(size_t timeout_ms)
{ {
return g_WatchdogTimer.Initialize(timeout_ms); return g_WatchdogTimer.Initialize(timeout_ms);
} }

View File

@ -1,86 +1,100 @@
// vim: set ts=4 sw=4 tw=99 noet: // vim: set sts=2 ts=8 sw=2 tw=99 et:
//
// Copyright (C) 2006-2015 AlliedModders LLC
//
// This file is part of SourcePawn. SourcePawn is free software: you can
// redistribute it and/or modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation, either version 3 of
// the License, or (at your option) any later version.
//
// You should have received a copy of the GNU General Public License along with
// SourcePawn. If not, see http://www.gnu.org/licenses/.
//
#ifndef _INCLUDE_SOURCEPAWN_ENGINE_2_H_ #ifndef _INCLUDE_SOURCEPAWN_ENGINE_2_H_
#define _INCLUDE_SOURCEPAWN_ENGINE_2_H_ #define _INCLUDE_SOURCEPAWN_ENGINE_2_H_
#include <sp_vm_api.h> #include <sp_vm_api.h>
namespace SourcePawn namespace SourcePawn {
/**
* @brief Outlines the interface a Virtual Machine (JIT) must expose
*/
class SourcePawnEngine2 : public ISourcePawnEngine2
{ {
/** public:
* @brief Outlines the interface a Virtual Machine (JIT) must expose SourcePawnEngine2();
*/
class SourcePawnEngine2 : public ISourcePawnEngine2
{
public:
SourcePawnEngine2();
public:
unsigned int GetAPIVersion();
const char *GetEngineName();
const char *GetVersionString();
IPluginRuntime *LoadPlugin(ICompilation *co, const char *file, int *err);
SPVM_NATIVE_FUNC CreateFakeNative(SPVM_FAKENATIVE_FUNC callback, void *pData);
void DestroyFakeNative(SPVM_NATIVE_FUNC func);
IDebugListener *SetDebugListener(IDebugListener *listener);
ICompilation *StartCompilation();
const char *GetErrorString(int err);
bool Initialize();
void Shutdown();
IPluginRuntime *CreateEmptyRuntime(const char *name, uint32_t memory);
bool InstallWatchdogTimer(size_t timeout_ms);
bool SetJitEnabled(bool enabled) { public:
jit_enabled_ = enabled; unsigned int GetAPIVersion();
return true; const char *GetEngineName();
} const char *GetVersionString();
IPluginRuntime *LoadPlugin(ICompilation *co, const char *file, int *err);
SPVM_NATIVE_FUNC CreateFakeNative(SPVM_FAKENATIVE_FUNC callback, void *pData);
void DestroyFakeNative(SPVM_NATIVE_FUNC func);
IDebugListener *SetDebugListener(IDebugListener *listener);
ICompilation *StartCompilation();
const char *GetErrorString(int err);
bool Initialize();
void Shutdown();
IPluginRuntime *CreateEmptyRuntime(const char *name, uint32_t memory);
bool InstallWatchdogTimer(size_t timeout_ms);
bool IsJitEnabled() { bool SetJitEnabled(bool enabled) {
return jit_enabled_; jit_enabled_ = enabled;
} return true;
}
void SetProfiler(IProfiler *profiler) { bool IsJitEnabled() {
// Deprecated. return jit_enabled_;
} }
void EnableProfiling() { void SetProfiler(IProfiler *profiler) {
profiling_enabled_ = !!profiler_; // Deprecated.
} }
void DisableProfiling() {
profiling_enabled_ = false;
}
bool IsProfilingEnabled() {
return profiling_enabled_;
}
void SetProfilingTool(IProfilingTool *tool) {
profiler_ = tool;
}
public: void EnableProfiling() {
IProfilingTool *GetProfiler() { profiling_enabled_ = !!profiler_;
return profiler_; }
} void DisableProfiling() {
private: profiling_enabled_ = false;
IProfilingTool *profiler_; }
bool jit_enabled_; bool IsProfilingEnabled() {
bool profiling_enabled_; return profiling_enabled_;
}; }
} void SetProfilingTool(IProfilingTool *tool) {
profiler_ = tool;
}
public:
IProfilingTool *GetProfiler() {
return profiler_;
}
private:
IProfilingTool *profiler_;
bool jit_enabled_;
bool profiling_enabled_;
};
} // namespace SourcePawn
extern SourcePawn::SourcePawnEngine2 g_engine2; extern SourcePawn::SourcePawnEngine2 g_engine2;
class EnterProfileScope class EnterProfileScope
{ {
public: public:
EnterProfileScope(const char *group, const char *name) EnterProfileScope(const char *group, const char *name)
{ {
if (g_engine2.IsProfilingEnabled()) if (g_engine2.IsProfilingEnabled())
g_engine2.GetProfiler()->EnterScope(group, name); g_engine2.GetProfiler()->EnterScope(group, name);
} }
~EnterProfileScope() ~EnterProfileScope()
{ {
if (g_engine2.IsProfilingEnabled()) if (g_engine2.IsProfilingEnabled())
g_engine2.GetProfiler()->LeaveScope(); g_engine2.GetProfiler()->LeaveScope();
} }
}; };
#endif //_INCLUDE_SOURCEPAWN_ENGINE_2_H_ #endif //_INCLUDE_SOURCEPAWN_ENGINE_2_H_

File diff suppressed because it is too large Load Diff

View File

@ -1,34 +1,15 @@
/** // vim: set sts=2 ts=8 sw=2 tw=99 et:
* vim: set ts=4 : //
* ============================================================================= // Copyright (C) 2006-2015 AlliedModders LLC
* SourcePawn //
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. // This file is part of SourcePawn. SourcePawn is free software: you can
* ============================================================================= // redistribute it and/or modify it under the terms of the GNU General Public
* // License as published by the Free Software Foundation, either version 3 of
* This program is free software; you can redistribute it and/or modify it under // the License, or (at your option) any later version.
* the terms of the GNU General Public License, version 3.0, as published by the //
* Free Software Foundation. // You should have received a copy of the GNU General Public License along with
* // SourcePawn. If not, see http://www.gnu.org/licenses/.
* 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 <http://www.gnu.org/licenses/>.
*
* 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 <http://www.sourcemod.net/license.php>.
*
* Version: $Id$
*/
#ifndef _INCLUDE_SOURCEPAWN_BASECONTEXT_H_ #ifndef _INCLUDE_SOURCEPAWN_BASECONTEXT_H_
#define _INCLUDE_SOURCEPAWN_BASECONTEXT_H_ #define _INCLUDE_SOURCEPAWN_BASECONTEXT_H_
@ -43,72 +24,76 @@
class BaseContext : public IPluginContext class BaseContext : public IPluginContext
{ {
public: public:
BaseContext(BaseRuntime *pRuntime); BaseContext(BaseRuntime *pRuntime);
~BaseContext(); ~BaseContext();
public: //IPluginContext
IVirtualMachine *GetVirtualMachine(); public: //IPluginContext
sp_context_t *GetContext(); IVirtualMachine *GetVirtualMachine();
sp_context_t *GetCtx(); sp_context_t *GetContext();
bool IsDebugging(); sp_context_t *GetCtx();
int SetDebugBreak(void *newpfn, void *oldpfn); bool IsDebugging();
IPluginDebugInfo *GetDebugInfo(); int SetDebugBreak(void *newpfn, void *oldpfn);
int HeapAlloc(unsigned int cells, cell_t *local_addr, cell_t **phys_addr); IPluginDebugInfo *GetDebugInfo();
int HeapPop(cell_t local_addr); int HeapAlloc(unsigned int cells, cell_t *local_addr, cell_t **phys_addr);
int HeapRelease(cell_t local_addr); int HeapPop(cell_t local_addr);
int FindNativeByName(const char *name, uint32_t *index); int HeapRelease(cell_t local_addr);
int GetNativeByIndex(uint32_t index, sp_native_t **native); int FindNativeByName(const char *name, uint32_t *index);
uint32_t GetNativesNum(); int GetNativeByIndex(uint32_t index, sp_native_t **native);
int FindPublicByName(const char *name, uint32_t *index); uint32_t GetNativesNum();
int GetPublicByIndex(uint32_t index, sp_public_t **publicptr); int FindPublicByName(const char *name, uint32_t *index);
uint32_t GetPublicsNum(); int GetPublicByIndex(uint32_t index, sp_public_t **publicptr);
int GetPubvarByIndex(uint32_t index, sp_pubvar_t **pubvar); uint32_t GetPublicsNum();
int FindPubvarByName(const char *name, uint32_t *index); int GetPubvarByIndex(uint32_t index, sp_pubvar_t **pubvar);
int GetPubvarAddrs(uint32_t index, cell_t *local_addr, cell_t **phys_addr); int FindPubvarByName(const char *name, uint32_t *index);
uint32_t GetPubVarsNum(); int GetPubvarAddrs(uint32_t index, cell_t *local_addr, cell_t **phys_addr);
int LocalToPhysAddr(cell_t local_addr, cell_t **phys_addr); uint32_t GetPubVarsNum();
int LocalToString(cell_t local_addr, char **addr); int LocalToPhysAddr(cell_t local_addr, cell_t **phys_addr);
int StringToLocal(cell_t local_addr, size_t chars, const char *source); int LocalToString(cell_t local_addr, char **addr);
int StringToLocalUTF8(cell_t local_addr, size_t maxbytes, const char *source, size_t *wrtnbytes); int StringToLocal(cell_t local_addr, size_t chars, const char *source);
int PushCell(cell_t value); int StringToLocalUTF8(cell_t local_addr, size_t maxbytes, const char *source, size_t *wrtnbytes);
int PushCellArray(cell_t *local_addr, cell_t **phys_addr, cell_t array[], unsigned int numcells); int PushCell(cell_t value);
int PushString(cell_t *local_addr, char **phys_addr, const char *string); int PushCellArray(cell_t *local_addr, cell_t **phys_addr, cell_t array[], unsigned int numcells);
int PushCellsFromArray(cell_t array[], unsigned int numcells); int PushString(cell_t *local_addr, char **phys_addr, const char *string);
int BindNatives(const sp_nativeinfo_t *natives, unsigned int num, int overwrite); int PushCellsFromArray(cell_t array[], unsigned int numcells);
int BindNative(const sp_nativeinfo_t *native); int BindNatives(const sp_nativeinfo_t *natives, unsigned int num, int overwrite);
int BindNativeToAny(SPVM_NATIVE_FUNC native); int BindNative(const sp_nativeinfo_t *native);
int Execute(uint32_t code_addr, cell_t *result); int BindNativeToAny(SPVM_NATIVE_FUNC native);
cell_t ThrowNativeErrorEx(int error, const char *msg, ...); int Execute(uint32_t code_addr, cell_t *result);
cell_t ThrowNativeError(const char *msg, ...); cell_t ThrowNativeErrorEx(int error, const char *msg, ...);
IPluginFunction *GetFunctionByName(const char *public_name); cell_t ThrowNativeError(const char *msg, ...);
IPluginFunction *GetFunctionById(funcid_t func_id); IPluginFunction *GetFunctionByName(const char *public_name);
SourceMod::IdentityToken_t *GetIdentity(); IPluginFunction *GetFunctionById(funcid_t func_id);
cell_t *GetNullRef(SP_NULL_TYPE type); SourceMod::IdentityToken_t *GetIdentity();
int LocalToStringNULL(cell_t local_addr, char **addr); cell_t *GetNullRef(SP_NULL_TYPE type);
int BindNativeToIndex(uint32_t index, SPVM_NATIVE_FUNC native); int LocalToStringNULL(cell_t local_addr, char **addr);
int Execute2(IPluginFunction *function, const cell_t *params, unsigned int num_params, cell_t *result); int BindNativeToIndex(uint32_t index, SPVM_NATIVE_FUNC native);
IPluginRuntime *GetRuntime(); int Execute2(IPluginFunction *function, const cell_t *params, unsigned int num_params, cell_t *result);
int GetLastNativeError(); IPluginRuntime *GetRuntime();
cell_t *GetLocalParams(); int GetLastNativeError();
void SetKey(int k, void *value); cell_t *GetLocalParams();
bool GetKey(int k, void **value); void SetKey(int k, void *value);
void Refresh(); bool GetKey(int k, void **value);
void ClearLastNativeError(); void Refresh();
public: void ClearLastNativeError();
bool IsInExec();
private: public:
void SetErrorMessage(const char *msg, va_list ap); bool IsInExec();
void _SetErrorMessage(const char *msg, ...);
private: private:
cell_t *m_pNullVec; void SetErrorMessage(const char *msg, va_list ap);
cell_t *m_pNullString; void _SetErrorMessage(const char *msg, ...);
char m_MsgCache[1024];
bool m_CustomMsg; private:
bool m_InExec; cell_t *m_pNullVec;
BaseRuntime *m_pRuntime; cell_t *m_pNullString;
sp_context_t m_ctx; char m_MsgCache[1024];
void *m_keys[4]; bool m_CustomMsg;
bool m_keys_set[4]; bool m_InExec;
BaseRuntime *m_pRuntime;
sp_context_t m_ctx;
void *m_keys[4];
bool m_keys_set[4];
}; };
#endif //_INCLUDE_SOURCEPAWN_BASECONTEXT_H_ #endif //_INCLUDE_SOURCEPAWN_BASECONTEXT_H_

View File

@ -1,34 +1,15 @@
/** // vim: set sts=2 ts=8 sw=2 tw=99 et:
* vim: set ts=4 sw=4 tw=99 et: //
* ============================================================================= // Copyright (C) 2006-2015 AlliedModders LLC
* SourcePawn //
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. // This file is part of SourcePawn. SourcePawn is free software: you can
* ============================================================================= // redistribute it and/or modify it under the terms of the GNU General Public
* // License as published by the Free Software Foundation, either version 3 of
* This program is free software; you can redistribute it and/or modify it under // the License, or (at your option) any later version.
* the terms of the GNU General Public License, version 3.0, as published by the //
* Free Software Foundation. // You should have received a copy of the GNU General Public License along with
* // SourcePawn. If not, see http://www.gnu.org/licenses/.
* 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 <http://www.gnu.org/licenses/>.
*
* 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 <http://www.sourcemod.net/license.php>.
*
* Version: $Id$
*/
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <assert.h> #include <assert.h>
@ -57,298 +38,294 @@ SourcePawnEngine g_engine1;
using namespace SourcePawn; using namespace SourcePawn;
#define ERROR_MESSAGE_MAX 30 #define ERROR_MESSAGE_MAX 30
static const char *g_ErrorMsgTable[] = static const char *g_ErrorMsgTable[] =
{ {
NULL, NULL,
"Unrecognizable file format", "Unrecognizable file format",
"Decompressor was not found", "Decompressor was not found",
"Not enough space on the heap", "Not enough space on the heap",
"Invalid parameter or parameter type", "Invalid parameter or parameter type",
"Invalid plugin address", "Invalid plugin address",
"Object or index not found", "Object or index not found",
"Invalid index or index not found", "Invalid index or index not found",
"Not enough space on the stack", "Not enough space on the stack",
"Debug section not found or debug not enabled", "Debug section not found or debug not enabled",
"Invalid instruction", "Invalid instruction",
"Invalid memory access", "Invalid memory access",
"Stack went below stack boundary", "Stack went below stack boundary",
"Heap went below heap boundary", "Heap went below heap boundary",
"Divide by zero", "Divide by zero",
"Array index is out of bounds", "Array index is out of bounds",
"Instruction contained invalid parameter", "Instruction contained invalid parameter",
"Stack memory leaked by native", "Stack memory leaked by native",
"Heap memory leaked by native", "Heap memory leaked by native",
"Dynamic array is too big", "Dynamic array is too big",
"Tracker stack is out of bounds", "Tracker stack is out of bounds",
"Native is not bound", "Native is not bound",
"Maximum number of parameters reached", "Maximum number of parameters reached",
"Native detected error", "Native detected error",
"Plugin not runnable", "Plugin not runnable",
"Call was aborted", "Call was aborted",
"Plugin format is too old", "Plugin format is too old",
"Plugin format is too new", "Plugin format is too new",
"Out of memory", "Out of memory",
"Integer overflow", "Integer overflow",
"Script execution timed out" "Script execution timed out"
}; };
const char *SourcePawnEngine::GetErrorString(int error) const char *
SourcePawnEngine::GetErrorString(int error)
{ {
if (error < 1 || error > ERROR_MESSAGE_MAX) if (error < 1 || error > ERROR_MESSAGE_MAX)
{ return NULL;
return NULL; return g_ErrorMsgTable[error];
}
return g_ErrorMsgTable[error];
} }
SourcePawnEngine::SourcePawnEngine() SourcePawnEngine::SourcePawnEngine()
{ {
m_pDebugHook = NULL; m_pDebugHook = NULL;
} }
SourcePawnEngine::~SourcePawnEngine() SourcePawnEngine::~SourcePawnEngine()
{ {
} }
void *SourcePawnEngine::ExecAlloc(size_t size) void *
SourcePawnEngine::ExecAlloc(size_t size)
{ {
#if defined WIN32 #if defined WIN32
return VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE); return VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
#elif defined __GNUC__ #elif defined __GNUC__
# if defined __APPLE__ # if defined __APPLE__
void *base = valloc(size); void *base = valloc(size);
# else # else
void *base = memalign(sysconf(_SC_PAGESIZE), size); void *base = memalign(sysconf(_SC_PAGESIZE), size);
# endif # endif
if (mprotect(base, size, PROT_READ|PROT_WRITE|PROT_EXEC) != 0) if (mprotect(base, size, PROT_READ|PROT_WRITE|PROT_EXEC) != 0) {
{ free(base);
free(base); return NULL;
return NULL; }
} return base;
return base;
#endif #endif
} }
void *SourcePawnEngine::AllocatePageMemory(size_t size) void *
SourcePawnEngine::AllocatePageMemory(size_t size)
{ {
return g_Jit.AllocCode(size); return g_Jit.AllocCode(size);
} }
void SourcePawnEngine::SetReadExecute(void *ptr) void
SourcePawnEngine::SetReadExecute(void *ptr)
{ {
/* already re */ /* already re */
} }
void SourcePawnEngine::SetReadWrite(void *ptr) void
SourcePawnEngine::SetReadWrite(void *ptr)
{ {
/* already rw */ /* already rw */
} }
void SourcePawnEngine::FreePageMemory(void *ptr) void
SourcePawnEngine::FreePageMemory(void *ptr)
{ {
g_Jit.FreeCode(ptr); g_Jit.FreeCode(ptr);
} }
void SourcePawnEngine::ExecFree(void *address) void
SourcePawnEngine::ExecFree(void *address)
{ {
#if defined WIN32 #if defined WIN32
VirtualFree(address, 0, MEM_RELEASE); VirtualFree(address, 0, MEM_RELEASE);
#elif defined __GNUC__ #elif defined __GNUC__
free(address); free(address);
#endif #endif
} }
void SourcePawnEngine::SetReadWriteExecute(void *ptr) void
SourcePawnEngine::SetReadWriteExecute(void *ptr)
{ {
//:TODO: g_ExeMemory.SetRWE(ptr); //:TODO: g_ExeMemory.SetRWE(ptr);
SetReadExecute(ptr); SetReadExecute(ptr);
} }
void *SourcePawnEngine::BaseAlloc(size_t size) void *
SourcePawnEngine::BaseAlloc(size_t size)
{ {
return malloc(size); return malloc(size);
} }
void SourcePawnEngine::BaseFree(void *memory) void
SourcePawnEngine::BaseFree(void *memory)
{ {
free(memory); free(memory);
} }
sp_plugin_t *SourcePawnEngine::LoadFromFilePointer(FILE *fp, int *err) sp_plugin_t *
SourcePawnEngine::LoadFromFilePointer(FILE *fp, int *err)
{ {
if (err != NULL) if (err != NULL)
{ *err = SP_ERROR_ABORTED;
*err = SP_ERROR_ABORTED;
}
return NULL; return NULL;
} }
sp_plugin_t *SourcePawnEngine::LoadFromMemory(void *base, sp_plugin_t *plugin, int *err) sp_plugin_t *
SourcePawnEngine::LoadFromMemory(void *base, sp_plugin_t *plugin, int *err)
{ {
if (err != NULL) if (err != NULL)
{ *err = SP_ERROR_ABORTED;
*err = SP_ERROR_ABORTED;
}
return NULL; return NULL;
} }
int SourcePawnEngine::FreeFromMemory(sp_plugin_t *plugin) int
SourcePawnEngine::FreeFromMemory(sp_plugin_t *plugin)
{ {
return SP_ERROR_ABORTED; return SP_ERROR_ABORTED;
} }
IDebugListener *SourcePawnEngine::SetDebugListener(IDebugListener *pListener) IDebugListener *
SourcePawnEngine::SetDebugListener(IDebugListener *pListener)
{ {
IDebugListener *old = m_pDebugHook; IDebugListener *old = m_pDebugHook;
m_pDebugHook = pListener; m_pDebugHook = pListener;
return old; return old;
} }
unsigned int SourcePawnEngine::GetEngineAPIVersion() unsigned int
SourcePawnEngine::GetEngineAPIVersion()
{ {
return SOURCEPAWN_ENGINE_API_VERSION; return SOURCEPAWN_ENGINE_API_VERSION;
} }
unsigned int SourcePawnEngine::GetContextCallCount() unsigned int
SourcePawnEngine::GetContextCallCount()
{ {
return 0; return 0;
} }
void SourcePawnEngine::ReportError(BaseRuntime *runtime, int err, const char *errstr, cell_t rp_start) void
SourcePawnEngine::ReportError(BaseRuntime *runtime, int err, const char *errstr, cell_t rp_start)
{ {
if (m_pDebugHook == NULL) if (m_pDebugHook == NULL)
{ return;
return;
}
CContextTrace trace(runtime, err, errstr, rp_start); CContextTrace trace(runtime, err, errstr, rp_start);
m_pDebugHook->OnContextExecuteError(runtime->GetDefaultContext(), &trace); m_pDebugHook->OnContextExecuteError(runtime->GetDefaultContext(), &trace);
} }
CContextTrace::CContextTrace(BaseRuntime *pRuntime, int err, const char *errstr, cell_t start_rp) CContextTrace::CContextTrace(BaseRuntime *pRuntime, int err, const char *errstr, cell_t start_rp)
: m_pRuntime(pRuntime), m_Error(err), m_pMsg(errstr), m_StartRp(start_rp), m_Level(0) : m_pRuntime(pRuntime),
m_Error(err),
m_pMsg(errstr),
m_StartRp(start_rp),
m_Level(0)
{ {
m_ctx = pRuntime->m_pCtx->GetCtx(); m_ctx = pRuntime->m_pCtx->GetCtx();
m_pDebug = m_pRuntime->GetDebugInfo(); m_pDebug = m_pRuntime->GetDebugInfo();
} }
bool CContextTrace::DebugInfoAvailable() bool
CContextTrace::DebugInfoAvailable()
{ {
return (m_pDebug != NULL); return (m_pDebug != NULL);
} }
const char *CContextTrace::GetCustomErrorString() const char *
CContextTrace::GetCustomErrorString()
{ {
return m_pMsg; return m_pMsg;
} }
int CContextTrace::GetErrorCode() int
CContextTrace::GetErrorCode()
{ {
return m_Error; return m_Error;
} }
const char *CContextTrace::GetErrorString() const char *
CContextTrace::GetErrorString()
{ {
if (m_Error > ERROR_MESSAGE_MAX || m_Error < 1) if (m_Error > ERROR_MESSAGE_MAX || m_Error < 1)
{ return "Invalid error code";
return "Invalid error code"; return g_ErrorMsgTable[m_Error];
}
else
{
return g_ErrorMsgTable[m_Error];
}
} }
void CContextTrace::ResetTrace() void
CContextTrace::ResetTrace()
{ {
m_Level = 0; m_Level = 0;
} }
bool CContextTrace::GetTraceInfo(CallStackInfo *trace) bool
CContextTrace::GetTraceInfo(CallStackInfo *trace)
{ {
cell_t cip; cell_t cip;
if (m_Level == 0) if (m_Level == 0) {
{ cip = m_ctx->cip;
cip = m_ctx->cip; } else if (m_ctx->rp > 0) {
} /* Entries go from ctx.rp - 1 to m_StartRp */
else if (m_ctx->rp > 0) cell_t offs, start, end;
{
/* Entries go from ctx.rp - 1 to m_StartRp */
cell_t offs, start, end;
offs = m_Level - 1; offs = m_Level - 1;
start = m_ctx->rp - 1; start = m_ctx->rp - 1;
end = m_StartRp; end = m_StartRp;
if (start - offs < end) if (start - offs < end)
{ {
return false; return false;
} }
cip = m_ctx->rstk_cips[start - offs]; cip = m_ctx->rstk_cips[start - offs];
} } else {
else return false;
{ }
return false;
}
if (trace == NULL) if (trace == NULL) {
{ m_Level++;
m_Level++; return true;
return true; }
}
if (m_pDebug->LookupFile(cip, &(trace->filename)) != SP_ERROR_NONE) if (m_pDebug->LookupFile(cip, &(trace->filename)) != SP_ERROR_NONE)
{ trace->filename = NULL;
trace->filename = NULL;
}
if (m_pDebug->LookupFunction(cip, &(trace->function)) != SP_ERROR_NONE) if (m_pDebug->LookupFunction(cip, &(trace->function)) != SP_ERROR_NONE)
{ trace->function = NULL;
trace->function = NULL;
}
if (m_pDebug->LookupLine(cip, &(trace->line)) != SP_ERROR_NONE) if (m_pDebug->LookupLine(cip, &(trace->line)) != SP_ERROR_NONE)
{ trace->line = 0;
trace->line = 0;
}
m_Level++; m_Level++;
return true; return true;
} }
const char *CContextTrace::GetLastNative(uint32_t *index) const char *
CContextTrace::GetLastNative(uint32_t *index)
{ {
if (m_ctx->n_err == SP_ERROR_NONE) if (m_ctx->n_err == SP_ERROR_NONE)
{ return NULL;
return NULL;
}
sp_native_t *native; sp_native_t *native;
if (m_pRuntime->GetNativeByIndex(m_ctx->n_idx, &native) != SP_ERROR_NONE) if (m_pRuntime->GetNativeByIndex(m_ctx->n_idx, &native) != SP_ERROR_NONE)
{ return NULL;
return NULL;
}
if (index) if (index)
{ *index = m_ctx->n_idx;
*index = m_ctx->n_idx;
}
return native->name; return native->name;
} }
IDebugListener *SourcePawnEngine::GetDebugHook() IDebugListener *
SourcePawnEngine::GetDebugHook()
{ {
return m_pDebugHook; return m_pDebugHook;
} }

View File

@ -1,34 +1,15 @@
/** // vim: set sts=2 ts=8 sw=2 tw=99 et:
* vim: set ts=4 : //
* ============================================================================= // Copyright (C) 2006-2015 AlliedModders LLC
* SourcePawn //
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. // This file is part of SourcePawn. SourcePawn is free software: you can
* ============================================================================= // redistribute it and/or modify it under the terms of the GNU General Public
* // License as published by the Free Software Foundation, either version 3 of
* This program is free software; you can redistribute it and/or modify it under // the License, or (at your option) any later version.
* the terms of the GNU General Public License, version 3.0, as published by the //
* Free Software Foundation. // You should have received a copy of the GNU General Public License along with
* // SourcePawn. If not, see http://www.gnu.org/licenses/.
* 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 <http://www.gnu.org/licenses/>.
*
* 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 <http://www.sourcemod.net/license.php>.
*
* Version: $Id$
*/
#ifndef _INCLUDE_SOURCEPAWN_VM_ENGINE_H_ #ifndef _INCLUDE_SOURCEPAWN_VM_ENGINE_H_
#define _INCLUDE_SOURCEPAWN_VM_ENGINE_H_ #define _INCLUDE_SOURCEPAWN_VM_ENGINE_H_
@ -39,55 +20,60 @@ class BaseContext;
class CContextTrace : public IContextTrace class CContextTrace : public IContextTrace
{ {
public: public:
CContextTrace(BaseRuntime *pRuntime, int err, const char *errstr, cell_t start_rp); CContextTrace(BaseRuntime *pRuntime, int err, const char *errstr, cell_t start_rp);
public:
int GetErrorCode(); public:
const char *GetErrorString(); int GetErrorCode();
bool DebugInfoAvailable(); const char *GetErrorString();
const char *GetCustomErrorString(); bool DebugInfoAvailable();
bool GetTraceInfo(CallStackInfo *trace); const char *GetCustomErrorString();
void ResetTrace(); bool GetTraceInfo(CallStackInfo *trace);
const char *GetLastNative(uint32_t *index); void ResetTrace();
private: const char *GetLastNative(uint32_t *index);
BaseRuntime *m_pRuntime;
sp_context_t *m_ctx; private:
int m_Error; BaseRuntime *m_pRuntime;
const char *m_pMsg; sp_context_t *m_ctx;
cell_t m_StartRp; int m_Error;
cell_t m_Level; const char *m_pMsg;
IPluginDebugInfo *m_pDebug; cell_t m_StartRp;
cell_t m_Level;
IPluginDebugInfo *m_pDebug;
}; };
class SourcePawnEngine : public ISourcePawnEngine class SourcePawnEngine : public ISourcePawnEngine
{ {
public: public:
SourcePawnEngine(); SourcePawnEngine();
~SourcePawnEngine(); ~SourcePawnEngine();
public: //ISourcePawnEngine
sp_plugin_t *LoadFromFilePointer(FILE *fp, int *err); public: //ISourcePawnEngine
sp_plugin_t *LoadFromMemory(void *base, sp_plugin_t *plugin, int *err); sp_plugin_t *LoadFromFilePointer(FILE *fp, int *err);
int FreeFromMemory(sp_plugin_t *plugin); sp_plugin_t *LoadFromMemory(void *base, sp_plugin_t *plugin, int *err);
void *BaseAlloc(size_t size); int FreeFromMemory(sp_plugin_t *plugin);
void BaseFree(void *memory); void *BaseAlloc(size_t size);
void *ExecAlloc(size_t size); void BaseFree(void *memory);
void ExecFree(void *address); void *ExecAlloc(size_t size);
IDebugListener *SetDebugListener(IDebugListener *pListener); void ExecFree(void *address);
unsigned int GetContextCallCount(); IDebugListener *SetDebugListener(IDebugListener *pListener);
unsigned int GetEngineAPIVersion(); unsigned int GetContextCallCount();
void *AllocatePageMemory(size_t size); unsigned int GetEngineAPIVersion();
void SetReadWrite(void *ptr); void *AllocatePageMemory(size_t size);
void SetReadExecute(void *ptr); void SetReadWrite(void *ptr);
void SetReadWriteExecute(void *ptr); void SetReadExecute(void *ptr);
void FreePageMemory(void *ptr); void SetReadWriteExecute(void *ptr);
const char *GetErrorString(int err); void FreePageMemory(void *ptr);
void ReportError(BaseRuntime *runtime, int err, const char *errstr, cell_t rp_start); const char *GetErrorString(int err);
public: //Plugin function stuff void ReportError(BaseRuntime *runtime, int err, const char *errstr, cell_t rp_start);
CFunction *GetFunctionFromPool(funcid_t f, IPluginContext *plugin);
void ReleaseFunctionToPool(CFunction *func); public: //Plugin function stuff
IDebugListener *GetDebugHook(); CFunction *GetFunctionFromPool(funcid_t f, IPluginContext *plugin);
private: void ReleaseFunctionToPool(CFunction *func);
IDebugListener *m_pDebugHook; IDebugListener *GetDebugHook();
private:
IDebugListener *m_pDebugHook;
}; };
extern SourcePawnEngine g_engine1; extern SourcePawnEngine g_engine1;

View File

@ -1,31 +1,15 @@
/** // vim: set sts=2 ts=8 sw=2 tw=99 et:
* vim: set ts=4 sw=4 tw=99 noet : //
* ============================================================================= // Copyright (C) 2006-2015 AlliedModders LLC
* SourcePawn //
* Copyright (C) 2004-2009 AlliedModders LLC. All rights reserved. // This file is part of SourcePawn. SourcePawn is free software: you can
* ============================================================================= // redistribute it and/or modify it under the terms of the GNU General Public
* // License as published by the Free Software Foundation, either version 3 of
* This program is free software; you can redistribute it and/or modify it under // the License, or (at your option) any later version.
* the terms of the GNU General Public License, version 3.0, as published by the //
* Free Software Foundation. // You should have received a copy of the GNU General Public License along with
* // SourcePawn. If not, see http://www.gnu.org/licenses/.
* 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 <http://www.gnu.org/licenses/>.
*
* 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 <http://www.sourcemod.net/license.php>.
*/
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
@ -38,319 +22,303 @@
CFunction::~CFunction() CFunction::~CFunction()
{ {
delete [] full_name_; delete [] full_name_;
} }
bool CFunction::IsRunnable() bool
CFunction::IsRunnable()
{ {
return !m_pRuntime->IsPaused(); return !m_pRuntime->IsPaused();
} }
int CFunction::CallFunction(const cell_t *params, unsigned int num_params, cell_t *result) int
CFunction::CallFunction(const cell_t *params, unsigned int num_params, cell_t *result)
{ {
return CallFunction2(m_pRuntime->GetDefaultContext(), params, num_params, result); return CallFunction2(m_pRuntime->GetDefaultContext(), params, num_params, result);
} }
int CFunction::CallFunction2(IPluginContext *pContext, const cell_t *params, unsigned int num_params, cell_t *result) int
CFunction::CallFunction2(IPluginContext *pContext, const cell_t *params, unsigned int num_params, cell_t *result)
{ {
return pContext->Execute2(this, params, num_params, result); return pContext->Execute2(this, params, num_params, result);
} }
IPluginContext *CFunction::GetParentContext() IPluginContext *
CFunction::GetParentContext()
{ {
return m_pRuntime->GetDefaultContext(); return m_pRuntime->GetDefaultContext();
} }
CFunction::CFunction(BaseRuntime *runtime, funcid_t id, uint32_t pub_id) : CFunction::CFunction(BaseRuntime *runtime, funcid_t id, uint32_t pub_id)
m_curparam(0), m_errorstate(SP_ERROR_NONE), m_FnId(id) : m_curparam(0),
m_errorstate(SP_ERROR_NONE),
m_FnId(id)
{ {
m_pRuntime = runtime; m_pRuntime = runtime;
runtime->GetPublicByIndex(pub_id, &public_); runtime->GetPublicByIndex(pub_id, &public_);
size_t rt_len = strlen(runtime->plugin()->name); size_t rt_len = strlen(runtime->plugin()->name);
size_t len = rt_len + strlen("::") + strlen(public_->name); size_t len = rt_len + strlen("::") + strlen(public_->name);
full_name_ = new char[len + 1]; full_name_ = new char[len + 1];
strcpy(full_name_, runtime->plugin()->name); strcpy(full_name_, runtime->plugin()->name);
strcpy(&full_name_[rt_len], "::"); strcpy(&full_name_[rt_len], "::");
strcpy(&full_name_[rt_len + 2], public_->name); strcpy(&full_name_[rt_len + 2], public_->name);
} }
int CFunction::PushCell(cell_t cell) int CFunction::PushCell(cell_t cell)
{ {
if (m_curparam >= SP_MAX_EXEC_PARAMS) if (m_curparam >= SP_MAX_EXEC_PARAMS)
{ return SetError(SP_ERROR_PARAMS_MAX);
return SetError(SP_ERROR_PARAMS_MAX);
}
m_info[m_curparam].marked = false; m_info[m_curparam].marked = false;
m_params[m_curparam] = cell; m_params[m_curparam] = cell;
m_curparam++; m_curparam++;
return SP_ERROR_NONE; return SP_ERROR_NONE;
} }
int CFunction::PushCellByRef(cell_t *cell, int flags) int
CFunction::PushCellByRef(cell_t *cell, int flags)
{ {
return PushArray(cell, 1, flags); return PushArray(cell, 1, flags);
} }
int CFunction::PushFloat(float number) int
CFunction::PushFloat(float number)
{ {
cell_t val = *(cell_t *)&number; cell_t val = *(cell_t *)&number;
return PushCell(val); return PushCell(val);
} }
int CFunction::PushFloatByRef(float *number, int flags) int
CFunction::PushFloatByRef(float *number, int flags)
{ {
return PushCellByRef((cell_t *)number, flags); return PushCellByRef((cell_t *)number, flags);
} }
int CFunction::PushArray(cell_t *inarray, unsigned int cells, int copyback) int
CFunction::PushArray(cell_t *inarray, unsigned int cells, int copyback)
{ {
if (m_curparam >= SP_MAX_EXEC_PARAMS) if (m_curparam >= SP_MAX_EXEC_PARAMS)
{ {
return SetError(SP_ERROR_PARAMS_MAX); return SetError(SP_ERROR_PARAMS_MAX);
} }
ParamInfo *info = &m_info[m_curparam]; ParamInfo *info = &m_info[m_curparam];
info->flags = inarray ? copyback : 0; info->flags = inarray ? copyback : 0;
info->marked = true; info->marked = true;
info->size = cells; info->size = cells;
info->str.is_sz = false; info->str.is_sz = false;
info->orig_addr = inarray; info->orig_addr = inarray;
m_curparam++; m_curparam++;
return SP_ERROR_NONE; return SP_ERROR_NONE;
} }
int CFunction::PushString(const char *string) int
CFunction::PushString(const char *string)
{ {
return _PushString(string, SM_PARAM_STRING_COPY, 0, strlen(string)+1); return _PushString(string, SM_PARAM_STRING_COPY, 0, strlen(string)+1);
} }
int CFunction::PushStringEx(char *buffer, size_t length, int sz_flags, int cp_flags) int
CFunction::PushStringEx(char *buffer, size_t length, int sz_flags, int cp_flags)
{ {
return _PushString(buffer, sz_flags, cp_flags, length); return _PushString(buffer, sz_flags, cp_flags, length);
} }
int CFunction::_PushString(const char *string, int sz_flags, int cp_flags, size_t len) int
CFunction::_PushString(const char *string, int sz_flags, int cp_flags, size_t len)
{ {
if (m_curparam >= SP_MAX_EXEC_PARAMS) if (m_curparam >= SP_MAX_EXEC_PARAMS)
{ return SetError(SP_ERROR_PARAMS_MAX);
return SetError(SP_ERROR_PARAMS_MAX);
}
ParamInfo *info = &m_info[m_curparam]; ParamInfo *info = &m_info[m_curparam];
info->marked = true; info->marked = true;
info->orig_addr = (cell_t *)string; info->orig_addr = (cell_t *)string;
info->flags = cp_flags; info->flags = cp_flags;
info->size = len; info->size = len;
info->str.sz_flags = sz_flags; info->str.sz_flags = sz_flags;
info->str.is_sz = true; info->str.is_sz = true;
m_curparam++; m_curparam++;
return SP_ERROR_NONE; return SP_ERROR_NONE;
} }
void CFunction::Cancel() void
CFunction::Cancel()
{ {
if (!m_curparam) if (!m_curparam)
{ return;
return;
}
m_errorstate = SP_ERROR_NONE; m_errorstate = SP_ERROR_NONE;
m_curparam = 0; m_curparam = 0;
} }
int CFunction::Execute(cell_t *result) int
CFunction::Execute(cell_t *result)
{ {
return Execute2(m_pRuntime->GetDefaultContext(), result); return Execute2(m_pRuntime->GetDefaultContext(), result);
} }
int CFunction::Execute2(IPluginContext *ctx, cell_t *result) int
CFunction::Execute2(IPluginContext *ctx, cell_t *result)
{ {
int err = SP_ERROR_NONE; int err = SP_ERROR_NONE;
if (!IsRunnable()) if (!IsRunnable())
{ m_errorstate = SP_ERROR_NOT_RUNNABLE;
m_errorstate = SP_ERROR_NOT_RUNNABLE;
}
if (m_errorstate != SP_ERROR_NONE) if (m_errorstate != SP_ERROR_NONE) {
{ err = m_errorstate;
err = m_errorstate; Cancel();
Cancel(); return err;
return err; }
}
//This is for re-entrancy! //This is for re-entrancy!
cell_t temp_params[SP_MAX_EXEC_PARAMS]; cell_t temp_params[SP_MAX_EXEC_PARAMS];
ParamInfo temp_info[SP_MAX_EXEC_PARAMS]; ParamInfo temp_info[SP_MAX_EXEC_PARAMS];
unsigned int numparams = m_curparam; unsigned int numparams = m_curparam;
unsigned int i; unsigned int i;
bool docopies = true; bool docopies = true;
if (numparams) if (numparams)
{ {
//Save the info locally, then reset it for re-entrant calls. //Save the info locally, then reset it for re-entrant calls.
memcpy(temp_info, m_info, numparams * sizeof(ParamInfo)); memcpy(temp_info, m_info, numparams * sizeof(ParamInfo));
} }
m_curparam = 0; m_curparam = 0;
/* Browse the parameters and build arrays */ /* Browse the parameters and build arrays */
for (i=0; i<numparams; i++) for (i=0; i<numparams; i++) {
{ /* Is this marked as an array? */
/* Is this marked as an array? */ if (temp_info[i].marked) {
if (temp_info[i].marked) if (!temp_info[i].str.is_sz) {
{ /* Allocate a normal/generic array */
if (!temp_info[i].str.is_sz) if ((err=ctx->HeapAlloc(temp_info[i].size,
{ &(temp_info[i].local_addr),
/* Allocate a normal/generic array */ &(temp_info[i].phys_addr)))
if ((err=ctx->HeapAlloc(temp_info[i].size, != SP_ERROR_NONE)
&(temp_info[i].local_addr), {
&(temp_info[i].phys_addr))) break;
!= SP_ERROR_NONE) }
{ if (temp_info[i].orig_addr)
break; {
} memcpy(temp_info[i].phys_addr, temp_info[i].orig_addr, sizeof(cell_t) * temp_info[i].size);
if (temp_info[i].orig_addr) }
{ } else {
memcpy(temp_info[i].phys_addr, temp_info[i].orig_addr, sizeof(cell_t) * temp_info[i].size); /* Calculate cells required for the string */
} size_t cells = (temp_info[i].size + sizeof(cell_t) - 1) / sizeof(cell_t);
}
else
{
/* Calculate cells required for the string */
size_t cells = (temp_info[i].size + sizeof(cell_t) - 1) / sizeof(cell_t);
/* Allocate the buffer */ /* Allocate the buffer */
if ((err=ctx->HeapAlloc(cells, if ((err=ctx->HeapAlloc(cells,
&(temp_info[i].local_addr), &(temp_info[i].local_addr),
&(temp_info[i].phys_addr))) &(temp_info[i].phys_addr)))
!= SP_ERROR_NONE) != SP_ERROR_NONE)
{ {
break; break;
} }
/* Copy original string if necessary */ /* Copy original string if necessary */
if ((temp_info[i].str.sz_flags & SM_PARAM_STRING_COPY) && (temp_info[i].orig_addr != NULL)) if ((temp_info[i].str.sz_flags & SM_PARAM_STRING_COPY) && (temp_info[i].orig_addr != NULL))
{ {
/* Cut off UTF-8 properly */ /* Cut off UTF-8 properly */
if (temp_info[i].str.sz_flags & SM_PARAM_STRING_UTF8) if (temp_info[i].str.sz_flags & SM_PARAM_STRING_UTF8) {
{ if ((err=ctx->StringToLocalUTF8(temp_info[i].local_addr,
if ((err=ctx->StringToLocalUTF8(temp_info[i].local_addr, temp_info[i].size,
temp_info[i].size, (const char *)temp_info[i].orig_addr,
(const char *)temp_info[i].orig_addr, NULL))
NULL)) != SP_ERROR_NONE)
!= SP_ERROR_NONE) {
{ break;
break; }
} }
} /* Copy a binary blob */
/* Copy a binary blob */ else if (temp_info[i].str.sz_flags & SM_PARAM_STRING_BINARY)
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);
memmove(temp_info[i].phys_addr, temp_info[i].orig_addr, temp_info[i].size); }
} /* Copy ASCII characters */
/* Copy ASCII characters */ else
else {
{ if ((err=ctx->StringToLocal(temp_info[i].local_addr,
if ((err=ctx->StringToLocal(temp_info[i].local_addr, temp_info[i].size,
temp_info[i].size, (const char *)temp_info[i].orig_addr))
(const char *)temp_info[i].orig_addr)) != SP_ERROR_NONE)
!= SP_ERROR_NONE) {
{ break;
break; }
} }
} }
} } /* End array/string calculation */
} /* End array/string calculation */ /* Update the pushed parameter with the byref local address */
/* Update the pushed parameter with the byref local address */ temp_params[i] = temp_info[i].local_addr;
temp_params[i] = temp_info[i].local_addr; } else {
} /* Just copy the value normally */
else temp_params[i] = m_params[i];
{ }
/* Just copy the value normally */ }
temp_params[i] = m_params[i];
}
}
/* Make the call if we can */ /* Make the call if we can */
if (err == SP_ERROR_NONE) if (err == SP_ERROR_NONE) {
{ if ((err = CallFunction2(ctx, temp_params, numparams, result)) != SP_ERROR_NONE)
if ((err = CallFunction2(ctx, temp_params, numparams, result)) != SP_ERROR_NONE) docopies = false;
{ } else {
docopies = false; docopies = false;
} }
}
else
{
docopies = false;
}
/* i should be equal to the last valid parameter + 1 */ /* i should be equal to the last valid parameter + 1 */
while (i--) while (i--) {
{ if (!temp_info[i].marked)
if (!temp_info[i].marked) continue;
{
continue;
}
if (docopies && (temp_info[i].flags & SM_PARAM_COPYBACK)) if (docopies && (temp_info[i].flags & SM_PARAM_COPYBACK)) {
{ if (temp_info[i].orig_addr) {
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);
if (temp_info[i].str.is_sz)
{
memcpy(temp_info[i].orig_addr, temp_info[i].phys_addr, temp_info[i].size);
} } else {
else if (temp_info[i].size == 1) {
{ *temp_info[i].orig_addr = *(temp_info[i].phys_addr);
if (temp_info[i].size == 1) } else {
{ memcpy(temp_info[i].orig_addr,
*temp_info[i].orig_addr = *(temp_info[i].phys_addr); temp_info[i].phys_addr,
} temp_info[i].size * sizeof(cell_t));
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) if ((err=ctx->HeapPop(temp_info[i].local_addr)) != SP_ERROR_NONE)
{ return err;
return err; }
}
}
return err; return err;
} }
IPluginRuntime *CFunction::GetParentRuntime() IPluginRuntime *
CFunction::GetParentRuntime()
{ {
return m_pRuntime; return m_pRuntime;
} }
funcid_t CFunction::GetFunctionID() funcid_t
CFunction::GetFunctionID()
{ {
return m_FnId; return m_FnId;
} }
int CFunction::SetError(int err) int
CFunction::SetError(int err)
{ {
m_errorstate = err; m_errorstate = err;
return err; return err;
} }

View File

@ -1,32 +1,15 @@
/** // vim: set sts=2 ts=8 sw=2 tw=99 et:
* vim: set ts=4 sw=4 tw=99 noet : //
* ============================================================================= // Copyright (C) 2006-2015 AlliedModders LLC
* SourcePawn //
* Copyright (C) 2004-2009 AlliedModders LLC. All rights reserved. // This file is part of SourcePawn. SourcePawn is free software: you can
* ============================================================================= // redistribute it and/or modify it under the terms of the GNU General Public
* // License as published by the Free Software Foundation, either version 3 of
* This program is free software; you can redistribute it and/or modify it under // the License, or (at your option) any later version.
* the terms of the GNU General Public License, version 3.0, as published by the //
* Free Software Foundation. // You should have received a copy of the GNU General Public License along with
* // SourcePawn. If not, see http://www.gnu.org/licenses/.
* 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 <http://www.gnu.org/licenses/>.
*
* 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 <http://www.sourcemod.net/license.php>.
*/
#ifndef _INCLUDE_SOURCEMOD_BASEFUNCTION_H_ #ifndef _INCLUDE_SOURCEMOD_BASEFUNCTION_H_
#define _INCLUDE_SOURCEMOD_BASEFUNCTION_H_ #define _INCLUDE_SOURCEMOD_BASEFUNCTION_H_
@ -38,17 +21,16 @@ using namespace SourcePawn;
struct ParamInfo struct ParamInfo
{ {
int flags; /* Copy-back flags */ int flags; /* Copy-back flags */
bool marked; /* Whether this is marked as being used */ bool marked; /* Whether this is marked as being used */
cell_t local_addr; /* Local address to free */ cell_t local_addr; /* Local address to free */
cell_t *phys_addr; /* Physical address of our copy */ cell_t *phys_addr; /* Physical address of our copy */
cell_t *orig_addr; /* Original address to copy back to */ cell_t *orig_addr; /* Original address to copy back to */
ucell_t size; /* Size of array in bytes */ ucell_t size; /* Size of array in bytes */
struct struct {
{ bool is_sz; /* is a string */
bool is_sz; /* is a string */ int sz_flags; /* has sz flags */
int sz_flags; /* has sz flags */ } str;
} str;
}; };
class CPlugin; class CPlugin;
@ -56,51 +38,54 @@ class JitFunction;
class CFunction : public IPluginFunction class CFunction : public IPluginFunction
{ {
friend class SourcePawnEngine; friend class SourcePawnEngine;
public:
CFunction(BaseRuntime *pRuntime, public:
funcid_t fnid, CFunction(BaseRuntime *pRuntime, funcid_t fnid, uint32_t pub_id);
uint32_t pub_id); ~CFunction();
~CFunction();
public: public:
virtual int PushCell(cell_t cell); virtual int PushCell(cell_t cell);
virtual int PushCellByRef(cell_t *cell, int flags); virtual int PushCellByRef(cell_t *cell, int flags);
virtual int PushFloat(float number); virtual int PushFloat(float number);
virtual int PushFloatByRef(float *number, int flags); virtual int PushFloatByRef(float *number, int flags);
virtual int PushArray(cell_t *inarray, unsigned int cells, int copyback); virtual int PushArray(cell_t *inarray, unsigned int cells, int copyback);
virtual int PushString(const char *string); virtual int PushString(const char *string);
virtual int PushStringEx(char *buffer, size_t length, int sz_flags, int cp_flags); virtual int PushStringEx(char *buffer, size_t length, int sz_flags, int cp_flags);
virtual int Execute(cell_t *result); virtual int Execute(cell_t *result);
virtual void Cancel(); virtual void Cancel();
virtual int CallFunction(const cell_t *params, unsigned int num_params, cell_t *result); virtual int CallFunction(const cell_t *params, unsigned int num_params, cell_t *result);
virtual IPluginContext *GetParentContext(); virtual IPluginContext *GetParentContext();
bool IsRunnable(); bool IsRunnable();
funcid_t GetFunctionID(); funcid_t GetFunctionID();
int Execute2(IPluginContext *ctx, cell_t *result); int Execute2(IPluginContext *ctx, cell_t *result);
int CallFunction2(IPluginContext *ctx, int CallFunction2(IPluginContext *ctx,
const cell_t *params, const cell_t *params,
unsigned int num_params, unsigned int num_params,
cell_t *result); cell_t *result);
IPluginRuntime *GetParentRuntime(); IPluginRuntime *GetParentRuntime();
public:
const char *FullName() const { public:
return full_name_; const char *FullName() const {
} return full_name_;
sp_public_t *Public() const { }
return public_; sp_public_t *Public() const {
} return public_;
private: }
int _PushString(const char *string, int sz_flags, int cp_flags, size_t len);
int SetError(int err); private:
private: int _PushString(const char *string, int sz_flags, int cp_flags, size_t len);
BaseRuntime *m_pRuntime; int SetError(int err);
cell_t m_params[SP_MAX_EXEC_PARAMS];
ParamInfo m_info[SP_MAX_EXEC_PARAMS]; private:
unsigned int m_curparam; BaseRuntime *m_pRuntime;
int m_errorstate; cell_t m_params[SP_MAX_EXEC_PARAMS];
funcid_t m_FnId; ParamInfo m_info[SP_MAX_EXEC_PARAMS];
char *full_name_; unsigned int m_curparam;
sp_public_t *public_; int m_errorstate;
funcid_t m_FnId;
char *full_name_;
sp_public_t *public_;
}; };
#endif //_INCLUDE_SOURCEMOD_BASEFUNCTION_H_ #endif //_INCLUDE_SOURCEMOD_BASEFUNCTION_H_