landed massive refactoring of the JIT. contexts are actually contexts now, and a higher level structure wraps sp_plugin_t info. on that note, both sp_plugin_t and sp_context_t are entirely opaque, and not even core has access to them. amazingly, i managed to keep binary compatibility here although a large number of functions are deprecated (and core should eventually stop calling them).

NOTE: the JIT is now embeddable out-of-box and usable by other projects which is pretty cool.  I will commit a shell app demonstrating this soon

--HG--
extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%402400
This commit is contained in:
David Anderson 2008-07-11 08:18:43 +00:00
parent ea1f5e86c0
commit 1a156deca5
69 changed files with 2836 additions and 2801 deletions

View File

@ -36,11 +36,6 @@
DebugReport g_DbgReporter; DebugReport g_DbgReporter;
/* I'm really lazy. This should probably be exported to ISourcePawnEngine someday,
* but we need to make sure the JIT will deal with the version bump.
*/
extern const char *GetSourcePawnErrorMessage(int error);
void DebugReport::OnSourceModAllInitialized() void DebugReport::OnSourceModAllInitialized()
{ {
g_pSourcePawn->SetDebugListener(this); g_pSourcePawn->SetDebugListener(this);
@ -56,7 +51,7 @@ void DebugReport::GenerateError(IPluginContext *ctx, cell_t func_idx, int err, c
va_end(ap); va_end(ap);
const char *plname = g_PluginSys.FindPluginByContext(ctx->GetContext())->GetFilename(); const char *plname = g_PluginSys.FindPluginByContext(ctx->GetContext())->GetFilename();
const char *error = GetSourcePawnErrorMessage(err); const char *error = g_pSourcePawn2->GetErrorString(err);
if (error) if (error)
{ {
@ -91,7 +86,7 @@ void DebugReport::GenerateCodeError(IPluginContext *pContext, uint32_t code_addr
va_end(ap); va_end(ap);
const char *plname = g_PluginSys.FindPluginByContext(pContext->GetContext())->GetFilename(); const char *plname = g_PluginSys.FindPluginByContext(pContext->GetContext())->GetFilename();
const char *error = GetSourcePawnErrorMessage(err); const char *error = g_pSourcePawn2->GetErrorString(err);
if (error) if (error)
{ {

View File

@ -29,12 +29,8 @@ OBJECTS += smn_admin.cpp smn_bitbuffer.cpp smn_console.cpp smn_core.cpp \
smn_adt_trie.cpp smn_hudtext.cpp smn_adt_stack.cpp smn_nextmap.cpp smn_adt_trie.cpp smn_hudtext.cpp smn_adt_stack.cpp smn_nextmap.cpp
OBJECTS += systems/ExtensionSys.cpp systems/ForwardSys.cpp systems/HandleSys.cpp \ OBJECTS += systems/ExtensionSys.cpp systems/ForwardSys.cpp systems/HandleSys.cpp \
systems/LibrarySys.cpp systems/PluginInfoDatabase.cpp systems/PluginSys.cpp \ systems/LibrarySys.cpp systems/PluginInfoDatabase.cpp systems/PluginSys.cpp \
systems/ShareSys.cpp vm/sp_vm_basecontext.cpp vm/sp_vm_engine.cpp \ systems/ShareSys.cpp
vm/sp_vm_function.cpp
OBJECTS += thread/ThreadWorker.cpp thread/BaseWorker.cpp thread/PosixThreads.cpp ThreadSupport.cpp OBJECTS += thread/ThreadWorker.cpp thread/BaseWorker.cpp thread/PosixThreads.cpp ThreadSupport.cpp
OBJECTS += zlib/adler32.c zlib/compress.c zlib/crc32.c zlib/deflate.c zlib/gzio.c \
zlib/infback.c zlib/inffast.c zlib/inflate.c zlib/inftrees.c zlib/trees.c \
zlib/uncompr.c zlib/zutil.c
############################################## ##############################################
### CONFIGURE ANY OTHER FLAGS/OPTIONS HERE ### ### CONFIGURE ANY OTHER FLAGS/OPTIONS HERE ###
@ -103,13 +99,9 @@ ifeq "$(GCC_VERSION)" "4"
CPPFLAGS += $(CPP_GCC4_FLAGS) CPPFLAGS += $(CPP_GCC4_FLAGS)
endif endif
OBJ_LINUX := $(OBJECTS:%vm_engine.cpp=$(BIN_DIR)/%vm_engine.o) OBJ_LINUX := $(OBJECTS:%.cpp=$(BIN_DIR)/%.o)
OBJ_LINUX := $(OBJ_LINUX:%.cpp=$(BIN_DIR)/%.o)
OBJ_LINUX := $(OBJ_LINUX:%.c=$(BIN_DIR)/%.o) OBJ_LINUX := $(OBJ_LINUX:%.c=$(BIN_DIR)/%.o)
$(BIN_DIR)/%vm_engine.o: %vm_engine.cpp
$(CPP) $(INCLUDE_SM16) $(CFLAGS) $(CPPFLAGS) -o $@ -c $<
$(BIN_DIR)/%.o: %.cpp $(BIN_DIR)/%.o: %.cpp
$(CPP) $(INCLUDE) $(CFLAGS) $(CPPFLAGS) -o $@ -c $< $(CPP) $(INCLUDE) $(CFLAGS) $(CPPFLAGS) -o $@ -c $<
@ -118,8 +110,6 @@ $(BIN_DIR)/%.o: %.c
all: check all: check
mkdir -p $(BIN_DIR)/systems mkdir -p $(BIN_DIR)/systems
mkdir -p $(BIN_DIR)/vm
mkdir -p $(BIN_DIR)/zlib
mkdir -p $(BIN_DIR)/thread mkdir -p $(BIN_DIR)/thread
ln -sf $(SRCDS)/bin/vstdlib_i486.so vstdlib_i486.so; ln -sf $(SRCDS)/bin/vstdlib_i486.so vstdlib_i486.so;
ln -sf $(SRCDS)/bin/tier0_i486.so tier0_i486.so; ln -sf $(SRCDS)/bin/tier0_i486.so tier0_i486.so;
@ -142,7 +132,5 @@ default: all
clean: check clean: check
rm -rf $(BIN_DIR)/*.o rm -rf $(BIN_DIR)/*.o
rm -rf $(BIN_DIR)/systems/*.o rm -rf $(BIN_DIR)/systems/*.o
rm -rf $(BIN_DIR)/zlib/*.o
rm -rf $(BIN_DIR)/vm/*.o
rm -rf $(BIN_DIR)/thread/*.o rm -rf $(BIN_DIR)/thread/*.o
rm -rf $(BIN_DIR)/$(BINARY) rm -rf $(BIN_DIR)/$(BINARY)

View File

@ -1358,204 +1358,26 @@
Name="SourcePawn" Name="SourcePawn"
UniqueIdentifier="{C3C3DC6E-E392-4916-B893-7ACB92192DE0}" UniqueIdentifier="{C3C3DC6E-E392-4916-B893-7ACB92192DE0}"
> >
<Filter <File
Name="Header Files" RelativePath="..\..\public\sourcepawn\sp_file_headers.h"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{D06F7D18-C940-4200-990B-2D0CF72F91AB}"
> >
<File </File>
RelativePath="..\vm\sp_vm_basecontext.h" <File
> RelativePath="..\..\public\sourcepawn\sp_typeutil.h"
</File>
<File
RelativePath="..\vm\sp_vm_engine.h"
>
</File>
<File
RelativePath="..\vm\sp_vm_function.h"
>
</File>
</Filter>
<Filter
Name="Source Files"
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{605A5261-30CD-4cca-BBE2-23BB190DA44E}"
> >
<File </File>
RelativePath="..\vm\sp_vm_basecontext.cpp" <File
> RelativePath="..\..\public\sourcepawn\sp_vm_api.h"
</File>
<File
RelativePath="..\vm\sp_vm_engine.cpp"
>
<FileConfiguration
Name="CrazyDebug - Old Metamod|Win32"
>
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories="&quot;$(SOURCEMM16)\sourcehook&quot;"
/>
</FileConfiguration>
<FileConfiguration
Name="Debug - Old Metamod|Win32"
>
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories="&quot;$(SOURCEMM16)\sourcehook&quot;"
/>
</FileConfiguration>
<FileConfiguration
Name="Release - Old Metamod|Win32"
>
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories="&quot;$(SOURCEMM16)\sourcehook&quot;"
/>
</FileConfiguration>
<FileConfiguration
Name="CrazyDebug|Win32"
>
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories="&quot;$(SOURCEMM16)\sourcehook&quot;"
/>
</FileConfiguration>
</File>
<File
RelativePath="..\vm\sp_vm_function.cpp"
>
</File>
</Filter>
<Filter
Name="SDK"
UniqueIdentifier="{A76160D7-4623-42c7-9587-62049792B924}"
> >
<File </File>
RelativePath="..\..\public\sourcepawn\sp_file_headers.h" <File
> RelativePath="..\..\public\sourcepawn\sp_vm_base.h"
</File>
<File
RelativePath="..\..\public\sourcepawn\sp_typeutil.h"
>
</File>
<File
RelativePath="..\..\public\sourcepawn\sp_vm_api.h"
>
</File>
<File
RelativePath="..\..\public\sourcepawn\sp_vm_base.h"
>
</File>
<File
RelativePath="..\..\public\sourcepawn\sp_vm_types.h"
>
</File>
</Filter>
</Filter>
<Filter
Name="zlib"
UniqueIdentifier="{27E223C9-0208-4c7d-BBAA-DE4BF1745020}"
>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{65A17C3B-0B6E-450f-96B8-661D47876D4B}"
> >
<File </File>
RelativePath="..\zlib\crc32.h" <File
> RelativePath="..\..\public\sourcepawn\sp_vm_types.h"
</File>
<File
RelativePath="..\zlib\deflate.h"
>
</File>
<File
RelativePath="..\zlib\inffast.h"
>
</File>
<File
RelativePath="..\zlib\inffixed.h"
>
</File>
<File
RelativePath="..\zlib\inflate.h"
>
</File>
<File
RelativePath="..\zlib\inftrees.h"
>
</File>
<File
RelativePath="..\zlib\trees.h"
>
</File>
<File
RelativePath="..\zlib\zconf.h"
>
</File>
<File
RelativePath="..\zlib\zlib.h"
>
</File>
<File
RelativePath="..\zlib\zutil.h"
>
</File>
</Filter>
<Filter
Name="Source Files"
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{9279E65A-C154-4296-AE23-949EB8C62BEB}"
> >
<File </File>
RelativePath="..\zlib\adler32.c"
>
</File>
<File
RelativePath="..\zlib\compress.c"
>
</File>
<File
RelativePath="..\zlib\crc32.c"
>
</File>
<File
RelativePath="..\zlib\deflate.c"
>
</File>
<File
RelativePath="..\zlib\gzio.c"
>
</File>
<File
RelativePath="..\zlib\infback.c"
>
</File>
<File
RelativePath="..\zlib\inffast.c"
>
</File>
<File
RelativePath="..\zlib\inflate.c"
>
</File>
<File
RelativePath="..\zlib\inftrees.c"
>
</File>
<File
RelativePath="..\zlib\trees.c"
>
</File>
<File
RelativePath="..\zlib\uncompr.c"
>
</File>
<File
RelativePath="..\zlib\zutil.c"
>
</File>
</Filter>
</Filter> </Filter>
<Filter <Filter
Name="HL2SDK" Name="HL2SDK"

View File

@ -173,7 +173,7 @@ private:
}; };
extern ISourcePawnEngine *g_pSourcePawn; extern ISourcePawnEngine *g_pSourcePawn;
extern IVirtualMachine *g_pVM; extern ISourcePawnEngine2 *g_pSourcePawn2;
extern IdentityToken_t *g_pCoreIdent; extern IdentityToken_t *g_pCoreIdent;
#include "sm_autonatives.h" #include "sm_autonatives.h"

View File

@ -281,8 +281,8 @@ void RootConsoleMenu::OnRootConsoleCommand(const char *cmdname, const CCommand &
{ {
ConsolePrint(" SourceMod Version Information:"); ConsolePrint(" SourceMod Version Information:");
ConsolePrint(" SourceMod Version: %s", SVN_FULL_VERSION); ConsolePrint(" SourceMod Version: %s", SVN_FULL_VERSION);
ConsolePrint(" JIT Version: %s, %s", g_pVM->GetVMName(), g_pVM->GetVersionString()); ConsolePrint(" SourcePawn Engine: %s (build %s)", g_pSourcePawn2->GetEngineName(), g_pSourcePawn2->GetVersionString());
ConsolePrint(" JIT Settings: %s", g_pVM->GetCPUOptimizations()); ConsolePrint(" SourcePawn API: v1 = %d, v2 = %d", g_pSourcePawn->GetEngineAPIVersion(), g_pSourcePawn2->GetAPIVersion());
ConsolePrint(" Compiled on: %s %s", __DATE__, __TIME__); ConsolePrint(" Compiled on: %s %s", __DATE__, __TIME__);
ConsolePrint(" http://www.sourcemod.net/"); ConsolePrint(" http://www.sourcemod.net/");
} }

View File

@ -833,7 +833,7 @@ static cell_t sm_ServerCommand(IPluginContext *pContext, const cell_t *params)
char buffer[1024]; char buffer[1024];
size_t len = g_SourceMod.FormatString(buffer, sizeof(buffer)-2, pContext, params, 1); size_t len = g_SourceMod.FormatString(buffer, sizeof(buffer)-2, pContext, params, 1);
if (pContext->GetContext()->n_err != SP_ERROR_NONE) if (pContext->GetLastNativeError() != SP_ERROR_NONE)
{ {
return 0; return 0;
} }
@ -854,7 +854,7 @@ static cell_t sm_InsertServerCommand(IPluginContext *pContext, const cell_t *par
char buffer[1024]; char buffer[1024];
size_t len = g_SourceMod.FormatString(buffer, sizeof(buffer)-2, pContext, params, 1); size_t len = g_SourceMod.FormatString(buffer, sizeof(buffer)-2, pContext, params, 1);
if (pContext->GetContext()->n_err != SP_ERROR_NONE) if (pContext->GetLastNativeError() != SP_ERROR_NONE)
{ {
return 0; return 0;
} }
@ -894,7 +894,7 @@ static cell_t sm_ClientCommand(IPluginContext *pContext, const cell_t *params)
char buffer[256]; char buffer[256];
g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2); g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
if (pContext->GetContext()->n_err != SP_ERROR_NONE) if (pContext->GetLastNativeError() != SP_ERROR_NONE)
{ {
return 0; return 0;
} }
@ -921,7 +921,7 @@ static cell_t FakeClientCommand(IPluginContext *pContext, const cell_t *params)
char buffer[256]; char buffer[256];
g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2); g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
if (pContext->GetContext()->n_err != SP_ERROR_NONE) if (pContext->GetLastNativeError() != SP_ERROR_NONE)
{ {
return 0; return 0;
} }
@ -948,7 +948,7 @@ static cell_t FakeClientCommandEx(IPluginContext *pContext, const cell_t *params
char buffer[256]; char buffer[256];
g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2); g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
if (pContext->GetContext()->n_err != SP_ERROR_NONE) if (pContext->GetLastNativeError() != SP_ERROR_NONE)
{ {
return 0; return 0;
} }
@ -966,7 +966,7 @@ static cell_t ReplyToCommand(IPluginContext *pContext, const cell_t *params)
char buffer[1024]; char buffer[1024];
size_t len = g_SourceMod.FormatString(buffer, sizeof(buffer)-2, pContext, params, 2); size_t len = g_SourceMod.FormatString(buffer, sizeof(buffer)-2, pContext, params, 2);
if (pContext->GetContext()->n_err != SP_ERROR_NONE) if (pContext->GetLastNativeError() != SP_ERROR_NONE)
{ {
return 0; return 0;
} }

View File

@ -130,7 +130,7 @@ static cell_t ThrowError(IPluginContext *pContext, const cell_t *params)
g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 1); g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 1);
if (pContext->GetContext()->n_err == SP_ERROR_NONE) if (pContext->GetLastNativeError() == SP_ERROR_NONE)
{ {
pContext->ThrowNativeErrorEx(SP_ERROR_ABORTED, "%s", buffer); pContext->ThrowNativeErrorEx(SP_ERROR_ABORTED, "%s", buffer);
} }
@ -387,7 +387,7 @@ static cell_t SetFailState(IPluginContext *pContext, const cell_t *params)
char buffer[2048]; char buffer[2048];
g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 1); g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 1);
if (pContext->GetContext()->n_err != SP_ERROR_NONE) if (pContext->GetLastNativeError() != SP_ERROR_NONE)
{ {
pPlugin->SetErrorState(Plugin_Error, "%s", str); pPlugin->SetErrorState(Plugin_Error, "%s", str);
return pContext->ThrowNativeErrorEx(SP_ERROR_ABORTED, "Formatting error (%s)", str); return pContext->ThrowNativeErrorEx(SP_ERROR_ABORTED, "Formatting error (%s)", str);
@ -455,7 +455,7 @@ static cell_t MarkNativeAsOptional(IPluginContext *pContext, const cell_t *param
{ {
char *name; char *name;
uint32_t idx; uint32_t idx;
sp_context_t *ctx = pContext->GetContext(); sp_native_t *native;
pContext->LocalToString(params[1], &name); pContext->LocalToString(params[1], &name);
if (pContext->FindNativeByName(name, &idx) != SP_ERROR_NONE) if (pContext->FindNativeByName(name, &idx) != SP_ERROR_NONE)
@ -464,7 +464,9 @@ static cell_t MarkNativeAsOptional(IPluginContext *pContext, const cell_t *param
return 0; return 0;
} }
ctx->natives[idx].flags |= SP_NTVFLAG_OPTIONAL; pContext->GetNativeByIndex(idx, &native);
native->flags |= SP_NTVFLAG_OPTIONAL;
return 1; return 1;
} }
@ -505,7 +507,7 @@ static cell_t sm_LogAction(IPluginContext *pContext, const cell_t *params)
g_SourceMod.SetGlobalTarget(SOURCEMOD_SERVER_LANGUAGE); g_SourceMod.SetGlobalTarget(SOURCEMOD_SERVER_LANGUAGE);
g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 3); g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 3);
if (pContext->GetContext()->n_err != SP_ERROR_NONE) if (pContext->GetLastNativeError() != SP_ERROR_NONE)
{ {
return 0; return 0;
} }
@ -535,7 +537,7 @@ static cell_t LogToFile(IPluginContext *pContext, const cell_t *params)
g_SourceMod.SetGlobalTarget(SOURCEMOD_SERVER_LANGUAGE); g_SourceMod.SetGlobalTarget(SOURCEMOD_SERVER_LANGUAGE);
g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2); g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
if (pContext->GetContext()->n_err != SP_ERROR_NONE) if (pContext->GetLastNativeError() != SP_ERROR_NONE)
{ {
fclose(fp); fclose(fp);
return 0; return 0;
@ -568,7 +570,7 @@ static cell_t LogToFileEx(IPluginContext *pContext, const cell_t *params)
g_SourceMod.SetGlobalTarget(SOURCEMOD_SERVER_LANGUAGE); g_SourceMod.SetGlobalTarget(SOURCEMOD_SERVER_LANGUAGE);
g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2); g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
if (pContext->GetContext()->n_err != SP_ERROR_NONE) if (pContext->GetLastNativeError() != SP_ERROR_NONE)
{ {
fclose(fp); fclose(fp);
return 0; return 0;

View File

@ -54,8 +54,7 @@ cell_t FakeNativeRouter(IPluginContext *pContext, const cell_t *params, void *pD
} }
/* Check if the native is paused */ /* Check if the native is paused */
sp_context_t *pNativeCtx = native->ctx->GetContext(); if (native->ctx->GetRuntime()->IsPaused())
if ((pNativeCtx->flags & SPFLAG_PLUGIN_PAUSED) == SPFLAG_PLUGIN_PAUSED)
{ {
return pContext->ThrowNativeError("Plugin owning this native is currently paused."); return pContext->ThrowNativeError("Plugin owning this native is currently paused.");
} }
@ -90,7 +89,7 @@ cell_t FakeNativeRouter(IPluginContext *pContext, const cell_t *params, void *pD
int error; int error;
if ((error=native->call->Execute(&result)) != SP_ERROR_NONE) if ((error=native->call->Execute(&result)) != SP_ERROR_NONE)
{ {
if (pContext->GetContext()->n_err == SP_ERROR_NONE) if (pContext->GetLastNativeError() == SP_ERROR_NONE)
{ {
pContext->ThrowNativeErrorEx(error, "Error encountered while processing a dynamic native"); pContext->ThrowNativeErrorEx(error, "Error encountered while processing a dynamic native");
} }
@ -146,7 +145,7 @@ static cell_t ThrowNativeError(IPluginContext *pContext, const cell_t *params)
g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2); g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
if (pContext->GetContext()->n_err != SP_ERROR_NONE) if (pContext->GetLastNativeError() != SP_ERROR_NONE)
{ {
s_curcaller->ThrowNativeError("Error encountered while processing a dynamic native"); s_curcaller->ThrowNativeError("Error encountered while processing a dynamic native");
} else { } else {
@ -434,7 +433,7 @@ static cell_t FormatNativeString(IPluginContext *pContext, const cell_t *params)
pContext->LocalToPhysAddr(params[5], &addr); pContext->LocalToPhysAddr(params[5], &addr);
*addr = (cell_t)written; *addr = (cell_t)written;
return s_curcaller->GetContext()->n_err; return s_curcaller->GetLastNativeError();
} }
//tee hee //tee hee

View File

@ -573,7 +573,7 @@ static cell_t sm_LogToGame(IPluginContext *pContext, const cell_t *params)
char buffer[1024]; char buffer[1024];
size_t len = g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 1); size_t len = g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 1);
if (pContext->GetContext()->n_err != SP_ERROR_NONE) if (pContext->GetLastNativeError() != SP_ERROR_NONE)
{ {
return 0; return 0;
} }
@ -599,7 +599,7 @@ static cell_t sm_LogMessage(IPluginContext *pContext, const cell_t *params)
char buffer[1024]; char buffer[1024];
g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 1); g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 1);
if (pContext->GetContext()->n_err != SP_ERROR_NONE) if (pContext->GetLastNativeError() != SP_ERROR_NONE)
{ {
return 0; return 0;
} }
@ -617,7 +617,7 @@ static cell_t sm_LogError(IPluginContext *pContext, const cell_t *params)
char buffer[1024]; char buffer[1024];
g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 1); g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 1);
if (pContext->GetContext()->n_err != SP_ERROR_NONE) if (pContext->GetLastNativeError() != SP_ERROR_NONE)
{ {
return 0; return 0;
} }
@ -670,7 +670,7 @@ static cell_t sm_LogToOpenFile(IPluginContext *pContext, const cell_t *params)
g_SourceMod.SetGlobalTarget(SOURCEMOD_SERVER_LANGUAGE); g_SourceMod.SetGlobalTarget(SOURCEMOD_SERVER_LANGUAGE);
g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2); g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
if (pContext->GetContext()->n_err != SP_ERROR_NONE) if (pContext->GetLastNativeError() != SP_ERROR_NONE)
{ {
return 0; return 0;
} }
@ -701,7 +701,7 @@ static cell_t sm_LogToOpenFileEx(IPluginContext *pContext, const cell_t *params)
g_SourceMod.SetGlobalTarget(SOURCEMOD_SERVER_LANGUAGE); g_SourceMod.SetGlobalTarget(SOURCEMOD_SERVER_LANGUAGE);
g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2); g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
if (pContext->GetContext()->n_err != SP_ERROR_NONE) if (pContext->GetLastNativeError() != SP_ERROR_NONE)
{ {
return 0; return 0;
} }

View File

@ -289,7 +289,7 @@ static cell_t PrintToChat(IPluginContext *pContext, const cell_t *params)
g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2); g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
/* Check for an error before printing to the client */ /* Check for an error before printing to the client */
if (pContext->GetContext()->n_err != SP_ERROR_NONE) if (pContext->GetLastNativeError() != SP_ERROR_NONE)
{ {
return 0; return 0;
} }
@ -323,7 +323,7 @@ static cell_t PrintCenterText(IPluginContext *pContext, const cell_t *params)
g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2); g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
/* Check for an error before printing to the client */ /* Check for an error before printing to the client */
if (pContext->GetContext()->n_err != SP_ERROR_NONE) if (pContext->GetLastNativeError() != SP_ERROR_NONE)
{ {
return 0; return 0;
} }
@ -357,7 +357,7 @@ static cell_t PrintHintText(IPluginContext *pContext, const cell_t *params)
g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2); g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
/* Check for an error before printing to the client */ /* Check for an error before printing to the client */
if (pContext->GetContext()->n_err != SP_ERROR_NONE) if (pContext->GetLastNativeError() != SP_ERROR_NONE)
{ {
return 0; return 0;
} }

View File

@ -371,7 +371,7 @@ static cell_t ShowSyncHudText(IPluginContext *pContext, const cell_t *params)
} }
g_SourceMod.FormatString(message_buffer, sizeof(message_buffer), pContext, params, 3); g_SourceMod.FormatString(message_buffer, sizeof(message_buffer), pContext, params, 3);
if (pContext->GetContext()->n_err != SP_ERROR_NONE) if (pContext->GetLastNativeError() != SP_ERROR_NONE)
{ {
return 0; return 0;
} }
@ -443,7 +443,7 @@ static cell_t ShowHudText(IPluginContext *pContext, const cell_t *params)
} }
g_SourceMod.FormatString(message_buffer, sizeof(message_buffer), pContext, params, 3); g_SourceMod.FormatString(message_buffer, sizeof(message_buffer), pContext, params, 3);
if (pContext->GetContext()->n_err != SP_ERROR_NONE) if (pContext->GetLastNativeError() != SP_ERROR_NONE)
{ {
return 0; return 0;
} }

View File

@ -1000,7 +1000,7 @@ static cell_t _ShowActivity(IPluginContext *pContext,
g_SourceMod.SetGlobalTarget(client); g_SourceMod.SetGlobalTarget(client);
g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, fmt_param); g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, fmt_param);
if (pContext->GetContext()->n_err != SP_ERROR_NONE) if (pContext->GetLastNativeError() != SP_ERROR_NONE)
{ {
return 0; return 0;
} }
@ -1015,7 +1015,7 @@ static cell_t _ShowActivity(IPluginContext *pContext,
g_SourceMod.SetGlobalTarget(SOURCEMOD_SERVER_LANGUAGE); g_SourceMod.SetGlobalTarget(SOURCEMOD_SERVER_LANGUAGE);
g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, fmt_param); g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, fmt_param);
if (pContext->GetContext()->n_err != SP_ERROR_NONE) if (pContext->GetLastNativeError() != SP_ERROR_NONE)
{ {
return 0; return 0;
} }
@ -1054,7 +1054,7 @@ static cell_t _ShowActivity(IPluginContext *pContext,
} }
g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, fmt_param); g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, fmt_param);
if (pContext->GetContext()->n_err != SP_ERROR_NONE) if (pContext->GetLastNativeError() != SP_ERROR_NONE)
{ {
return 0; return 0;
} }
@ -1078,7 +1078,7 @@ static cell_t _ShowActivity(IPluginContext *pContext,
} }
g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, fmt_param); g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, fmt_param);
if (pContext->GetContext()->n_err != SP_ERROR_NONE) if (pContext->GetLastNativeError() != SP_ERROR_NONE)
{ {
return 0; return 0;
} }
@ -1123,7 +1123,7 @@ static cell_t _ShowActivity2(IPluginContext *pContext,
g_SourceMod.SetGlobalTarget(client); g_SourceMod.SetGlobalTarget(client);
g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, fmt_param); g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, fmt_param);
if (pContext->GetContext()->n_err != SP_ERROR_NONE) if (pContext->GetLastNativeError() != SP_ERROR_NONE)
{ {
return 0; return 0;
} }
@ -1152,7 +1152,7 @@ static cell_t _ShowActivity2(IPluginContext *pContext,
g_SourceMod.SetGlobalTarget(SOURCEMOD_SERVER_LANGUAGE); g_SourceMod.SetGlobalTarget(SOURCEMOD_SERVER_LANGUAGE);
g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, fmt_param); g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, fmt_param);
if (pContext->GetContext()->n_err != SP_ERROR_NONE) if (pContext->GetLastNativeError() != SP_ERROR_NONE)
{ {
return 0; return 0;
} }
@ -1191,7 +1191,7 @@ static cell_t _ShowActivity2(IPluginContext *pContext,
} }
g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, fmt_param); g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, fmt_param);
if (pContext->GetContext()->n_err != SP_ERROR_NONE) if (pContext->GetLastNativeError() != SP_ERROR_NONE)
{ {
return 0; return 0;
} }
@ -1215,7 +1215,7 @@ static cell_t _ShowActivity2(IPluginContext *pContext,
} }
g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, fmt_param); g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, fmt_param);
if (pContext->GetContext()->n_err != SP_ERROR_NONE) if (pContext->GetLastNativeError() != SP_ERROR_NONE)
{ {
return 0; return 0;
} }
@ -1286,7 +1286,7 @@ static cell_t KickClient(IPluginContext *pContext, const cell_t *params)
char buffer[256]; char buffer[256];
g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2); g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
if (pContext->GetContext()->n_err != SP_ERROR_NONE) if (pContext->GetLastNativeError() != SP_ERROR_NONE)
{ {
return 0; return 0;
} }
@ -1332,7 +1332,7 @@ static cell_t KickClientEx(IPluginContext *pContext, const cell_t *params)
char buffer[256]; char buffer[256];
g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2); g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
if (pContext->GetContext()->n_err != SP_ERROR_NONE) if (pContext->GetLastNativeError() != SP_ERROR_NONE)
{ {
return 0; return 0;
} }

View File

@ -233,8 +233,7 @@ static cell_t sm_vformat(IPluginContext *pContext, const cell_t *params)
int vargPos = static_cast<int>(params[4]); int vargPos = static_cast<int>(params[4]);
/* Get the parent parameter array */ /* Get the parent parameter array */
sp_context_t *ctx = pContext->GetContext(); cell_t *local_params = pContext->GetLocalParams();
cell_t *local_params = (cell_t *)(ctx->memory + ctx->frm + (2 * sizeof(cell_t)));
cell_t max = local_params[0]; cell_t max = local_params[0];
if (vargPos > (int)max + 1) if (vargPos > (int)max + 1)

View File

@ -33,7 +33,6 @@
#include "sourcemod.h" #include "sourcemod.h"
#include "sourcemm_api.h" #include "sourcemm_api.h"
#include "systems/LibrarySys.h" #include "systems/LibrarySys.h"
#include "vm/sp_vm_engine.h"
#include <sh_string.h> #include <sh_string.h>
#include "PluginSys.h" #include "PluginSys.h"
#include "ShareSys.h" #include "ShareSys.h"
@ -47,27 +46,26 @@
#include "ForwardSys.h" #include "ForwardSys.h"
#include "TimerSys.h" #include "TimerSys.h"
#include "GameConfigs.h" #include "GameConfigs.h"
#include "DebugReporter.h"
#include "Profiler.h"
SH_DECL_HOOK6(IServerGameDLL, LevelInit, SH_NOATTRIB, false, bool, const char *, const char *, const char *, const char *, bool, bool); SH_DECL_HOOK6(IServerGameDLL, LevelInit, SH_NOATTRIB, false, bool, const char *, const char *, const char *, const char *, bool, bool);
SH_DECL_HOOK0_void(IServerGameDLL, LevelShutdown, SH_NOATTRIB, false); SH_DECL_HOOK0_void(IServerGameDLL, LevelShutdown, SH_NOATTRIB, false);
SH_DECL_HOOK1_void(IServerGameDLL, GameFrame, SH_NOATTRIB, false, bool); SH_DECL_HOOK1_void(IServerGameDLL, GameFrame, SH_NOATTRIB, false, bool);
SH_DECL_HOOK1_void(IVEngineServer, ServerCommand, SH_NOATTRIB, false, const char *); SH_DECL_HOOK1_void(IVEngineServer, ServerCommand, SH_NOATTRIB, false, const char *);
SourcePawnEngine g_SourcePawn;
SourceModBase g_SourceMod; SourceModBase g_SourceMod;
ILibrary *g_pJIT = NULL; ILibrary *g_pJIT = NULL;
SourceHook::String g_BaseDir; SourceHook::String g_BaseDir;
ISourcePawnEngine *g_pSourcePawn = &g_SourcePawn; ISourcePawnEngine *g_pSourcePawn = NULL;
IVirtualMachine *g_pVM; ISourcePawnEngine2 *g_pSourcePawn2 = NULL;
IdentityToken_t *g_pCoreIdent = NULL; IdentityToken_t *g_pCoreIdent = NULL;
IForward *g_pOnMapEnd = NULL; IForward *g_pOnMapEnd = NULL;
bool g_Loaded = false; bool g_Loaded = false;
typedef int (*GIVEENGINEPOINTER)(ISourcePawnEngine *); typedef ISourcePawnEngine *(*GET_SP_V1)();
typedef int (*GIVEENGINEPOINTER2)(ISourcePawnEngine *, unsigned int api_version); typedef ISourcePawnEngine2 *(*GET_SP_V2)();
typedef unsigned int (*GETEXPORTCOUNT)();
typedef IVirtualMachine *(*GETEXPORT)(unsigned int);
typedef void (*NOTIFYSHUTDOWN)(); typedef void (*NOTIFYSHUTDOWN)();
void ShutdownJIT() void ShutdownJIT()
@ -165,105 +163,34 @@ bool SourceModBase::InitializeSourceMod(char *error, size_t maxlength, bool late
return false; return false;
} }
int err; GET_SP_V1 getv1 = (GET_SP_V1)g_pJIT->GetSymbolAddress("GetSourcePawnEngine1");
GET_SP_V2 getv2 = (GET_SP_V2)g_pJIT->GetSymbolAddress("GetSourcePawnEngine2");
GIVEENGINEPOINTER2 jit_init2 = (GIVEENGINEPOINTER2)g_pJIT->GetSymbolAddress("GiveEnginePointer2"); if (getv1 == NULL)
if (!jit_init2)
{ {
GIVEENGINEPOINTER jit_init = (GIVEENGINEPOINTER)g_pJIT->GetSymbolAddress("GiveEnginePointer");
if (!jit_init)
{
ShutdownJIT();
if (error && maxlength)
{
snprintf(error, maxlength, "Failed to find GiveEnginePointer in JIT!");
}
return false;
}
if ((err=jit_init(g_pSourcePawn)) != 0)
{
ShutdownJIT();
if (error && maxlength)
{
snprintf(error, maxlength, "GiveEnginePointer returned %d in the JIT", err);
}
return false;
}
}
else
{
/* On version bumps, we should check for older versions as well, if the new version fails.
* We can then check the exports to see if any VM versions will be sufficient.
*/
if ((err=jit_init2(g_pSourcePawn, SOURCEPAWN_ENGINE_API_VERSION)) != SP_ERROR_NONE)
{
ShutdownJIT();
if (error && maxlength)
{
snprintf(error, maxlength, "JIT incompatible with SourceMod version");
}
return false;
}
}
GETEXPORTCOUNT jit_getnum = (GETEXPORTCOUNT)g_pJIT->GetSymbolAddress("GetExportCount");
GETEXPORT jit_get = (GETEXPORT)g_pJIT->GetSymbolAddress("GetExport");
if (!jit_get)
{
ShutdownJIT();
if (error && maxlength) if (error && maxlength)
{ {
snprintf(error, maxlength, "JIT is missing a necessary export!"); snprintf(error, maxlength, "JIT is too old; upgrade SourceMod");
} }
ShutdownJIT();
return false; return false;
} }
else if (getv2 == NULL)
unsigned int num = jit_getnum();
if (!num)
{ {
ShutdownJIT();
if (error && maxlength) if (error && maxlength)
{ {
snprintf(error, maxlength, "JIT did not export any virtual machines!"); snprintf(error, maxlength, "JIT is too old; upgrade SourceMod");
} }
return false;
}
unsigned int api_version;
for (unsigned int i=0; i<num; i++)
{
if ((g_pVM=jit_get(i)) == NULL)
{
if (error && maxlength)
{
snprintf(error, maxlength, "JIT did not export any virtual machines!");
}
continue;
}
/* Refuse any API that we might not be able to deal with.
* <s>Also refuse anything < 3 because we need fake natives.</s>
* Also refuse anything < 7 because we need the new sp_native definition.
*/
api_version = g_pVM->GetAPIVersion();
if (api_version < 7 || api_version > SOURCEPAWN_VM_API_VERSION)
{
if (error && maxlength)
{
snprintf(error, maxlength, "JIT is not a compatible version");
}
g_pVM = NULL;
continue;
}
break;
}
if (!g_pVM)
{
ShutdownJIT(); ShutdownJIT();
return false; return false;
} }
g_pSourcePawn = getv1();
g_pSourcePawn2 = getv2();
g_pSourcePawn2->SetDebugListener(&g_DbgReporter);
g_pSourcePawn2->SetProfiler(&g_Profiler);
/* Hook this now so we can detect startup without calling StartSourceMod() */ /* Hook this now so we can detect startup without calling StartSourceMod() */
SH_ADD_HOOK_MEMFUNC(IServerGameDLL, LevelInit, gamedll, this, &SourceModBase::LevelInit, false); SH_ADD_HOOK_MEMFUNC(IServerGameDLL, LevelInit, gamedll, this, &SourceModBase::LevelInit, false);
@ -663,7 +590,7 @@ ISourcePawnEngine *SourceModBase::GetScriptingEngine()
IVirtualMachine *SourceModBase::GetScriptingVM() IVirtualMachine *SourceModBase::GetScriptingVM()
{ {
return g_pVM; return NULL;
} }
void SourceModBase::AllPluginsLoaded() void SourceModBase::AllPluginsLoaded()

View File

@ -990,7 +990,7 @@ bool HandleSystem::TryAndFreeSomeHandles()
g_Logger.LogFatal("[SM] Reloading plugin to free %d handles.", highest_handle_count); g_Logger.LogFatal("[SM] Reloading plugin to free %d handles.", highest_handle_count);
g_Logger.LogFatal("[SM] Contact the author(s) of this plugin to correct this error.", highest_handle_count); g_Logger.LogFatal("[SM] Contact the author(s) of this plugin to correct this error.", highest_handle_count);
highest_owner->GetContext()->n_err = SP_ERROR_MEMACCESS; highest_owner->GetBaseContext()->ThrowNativeErrorEx(SP_ERROR_MEMACCESS, "Memory leak");
return g_PluginSys.UnloadPlugin(highest_owner); return g_PluginSys.UnloadPlugin(highest_owner);
} }

View File

@ -58,7 +58,7 @@ CPlugin::CPlugin(const char *file)
m_type = PluginType_Private; m_type = PluginType_Private;
m_status = Plugin_Uncompiled; m_status = Plugin_Uncompiled;
m_serial = ++MySerial; m_serial = ++MySerial;
m_plugin = NULL; m_pRuntime = NULL;
m_errormsg[256] = '\0'; m_errormsg[256] = '\0';
snprintf(m_filename, sizeof(m_filename), "%s", file); snprintf(m_filename, sizeof(m_filename), "%s", file);
m_handle = 0; m_handle = 0;
@ -82,27 +82,12 @@ CPlugin::~CPlugin()
g_ShareSys.DestroyIdentity(m_ident); g_ShareSys.DestroyIdentity(m_ident);
} }
if (m_ctx.base) if (m_pRuntime != NULL)
{ {
delete m_ctx.base; delete m_pRuntime;
m_ctx.base = NULL; m_pRuntime = NULL;
}
if (m_ctx.ctx)
{
m_ctx.vm->FreeContext(m_ctx.ctx);
m_ctx.ctx = NULL;
}
if (m_ctx.co)
{
m_ctx.vm->AbortCompilation(m_ctx.co);
m_ctx.co = NULL;
} }
if (m_plugin)
{
g_pSourcePawn->FreeFromMemory(m_plugin);
m_plugin = NULL;
}
if (m_pProps) if (m_pProps)
{ {
sm_trie_destroy(m_pProps); sm_trie_destroy(m_pProps);
@ -125,7 +110,8 @@ void CPlugin::InitIdentity()
{ {
m_ident = g_ShareSys.CreateIdentity(g_PluginIdent, this); m_ident = g_ShareSys.CreateIdentity(g_PluginIdent, this);
m_handle = g_HandleSys.CreateHandle(g_PluginType, this, g_PluginSys.GetIdentity(), g_PluginSys.GetIdentity(), NULL); m_handle = g_HandleSys.CreateHandle(g_PluginType, this, g_PluginSys.GetIdentity(), g_PluginSys.GetIdentity(), NULL);
m_ctx.base->SetIdentity(m_ident); m_pRuntime->GetDefaultContext()->SetKey(1, m_ident);
m_pRuntime->GetDefaultContext()->SetKey(2, (IPlugin *)this);
} }
} }
@ -157,37 +143,6 @@ unsigned int CPlugin::CalcMemUsage()
base_size += (*i).size(); base_size += (*i).size();
} }
if (m_plugin != NULL)
{
base_size += sizeof(sp_plugin_t);
base_size += m_plugin->data_size;
base_size += m_plugin->pcode_size;
base_size += (m_plugin->info.natives_num * sizeof(sp_file_natives_t));
base_size += (m_plugin->info.publics_num * sizeof(sp_file_publics_t));
base_size += (m_plugin->info.pubvars_num * sizeof(sp_file_pubvars_t));
base_size += (m_plugin->debug.files_num * sizeof(sp_fdbg_file_t));
base_size += (m_plugin->debug.lines_num * sizeof(sp_fdbg_line_t));
base_size += (m_plugin->debug.syms_num * sizeof(sp_fdbg_symbol_t));
/* We can't get strtab size, oh well. */
}
if (m_ctx.base != NULL)
{
base_size += sizeof(BaseContext);
base_size += m_ctx.base->GetPublicsNum() * sizeof(CFunction);
}
if (m_ctx.ctx != NULL)
{
base_size += m_ctx.ctx->mem_size;
base_size += (m_plugin->debug.files_num * sizeof(sp_debug_file_t));
base_size += (m_plugin->debug.lines_num * sizeof(sp_debug_line_t));
base_size += (m_plugin->debug.syms_num * sizeof(sp_debug_symbol_t));
base_size += (m_plugin->info.pubvars_num * sizeof(sp_pubvar_t));
base_size += (m_plugin->info.publics_num * sizeof(sp_public_t));
base_size += (m_plugin->info.natives_num * sizeof(sp_native_t));
/* We also don't know the JIT code size, oh well. */
}
return base_size; return base_size;
} }
@ -214,23 +169,6 @@ CPlugin *CPlugin::CreatePlugin(const char *file, char *error, size_t maxlength)
return pPlugin; return pPlugin;
} }
int err;
sp_plugin_t *pl = g_pSourcePawn->LoadFromFilePointer(fp, &err);
if (pl == NULL)
{
fclose(fp);
if (error)
{
snprintf(error, maxlength, "Error %d while parsing plugin", err);
}
pPlugin->m_status = Plugin_BadLoad;
return pPlugin;
}
fclose(fp);
pPlugin->m_plugin = pl;
return pPlugin; return pPlugin;
} }
@ -251,69 +189,9 @@ bool CPlugin::SetProperty(const char *prop, void *ptr)
return sm_trie_insert(m_pProps, prop, ptr); return sm_trie_insert(m_pProps, prop, ptr);
} }
ICompilation *CPlugin::StartMyCompile(IVirtualMachine *vm) IPluginRuntime *CPlugin::GetRuntime()
{ {
if (!m_plugin) return m_pRuntime;
{
return NULL;
}
/* :NOTICE: We will eventually need to change these natives
* for swapping in new contexts
*/
if (m_ctx.co || m_ctx.ctx)
{
return NULL;
}
m_status = Plugin_Uncompiled;
m_ctx.vm = vm;
m_ctx.co = vm->StartCompilation(m_plugin);
return m_ctx.co;
}
void CPlugin::CancelMyCompile()
{
if (!m_ctx.co)
{
return;
}
m_ctx.vm->AbortCompilation(m_ctx.co);
m_ctx.co = NULL;
m_ctx.vm = NULL;
}
bool CPlugin::FinishMyCompile(char *error, size_t maxlength)
{
if (!m_ctx.co)
{
return false;
}
int err;
m_ctx.ctx = m_ctx.vm->CompileToContext(m_ctx.co, &err);
if (!m_ctx.ctx)
{
memset(&m_ctx, 0, sizeof(m_ctx));
if (error)
{
snprintf(error, maxlength, "JIT failed to compile (error %d)", err);
}
return false;
}
m_ctx.base = new BaseContext(m_ctx.ctx);
m_ctx.ctx->user[SM_CONTEXTVAR_MYSELF] = (void *)this;
m_status = Plugin_Created;
m_ctx.co = NULL;
UpdateInfo();
return true;
} }
void CPlugin::SetErrorState(PluginStatus status, const char *error_fmt, ...) void CPlugin::SetErrorState(PluginStatus status, const char *error_fmt, ...)
@ -332,9 +210,9 @@ void CPlugin::SetErrorState(PluginStatus status, const char *error_fmt, ...)
vsnprintf(m_errormsg, sizeof(m_errormsg), error_fmt, ap); vsnprintf(m_errormsg, sizeof(m_errormsg), error_fmt, ap);
va_end(ap); va_end(ap);
if (m_ctx.ctx) if (m_pRuntime != NULL)
{ {
m_ctx.ctx->flags |= SPFLAG_PLUGIN_PAUSED; m_pRuntime->SetPauseState(true);
} }
} }
@ -415,7 +293,7 @@ void CPlugin::Call_OnPluginStart()
m_status = Plugin_Running; m_status = Plugin_Running;
cell_t result; cell_t result;
IPluginFunction *pFunction = m_ctx.base->GetFunctionByName("OnPluginStart"); IPluginFunction *pFunction = m_pRuntime->GetFunctionByName("OnPluginStart");
if (!pFunction) if (!pFunction)
{ {
return; return;
@ -436,7 +314,7 @@ void CPlugin::Call_OnPluginEnd()
} }
cell_t result; cell_t result;
IPluginFunction *pFunction = m_ctx.base->GetFunctionByName("OnPluginEnd"); IPluginFunction *pFunction = m_pRuntime->GetFunctionByName("OnPluginEnd");
if (!pFunction) if (!pFunction)
{ {
return; return;
@ -460,7 +338,7 @@ void CPlugin::Call_OnAllPluginsLoaded()
m_bGotAllLoaded = true; m_bGotAllLoaded = true;
cell_t result; cell_t result;
IPluginFunction *pFunction = m_ctx.base->GetFunctionByName("OnAllPluginsLoaded"); IPluginFunction *pFunction = m_pRuntime->GetFunctionByName("OnAllPluginsLoaded");
if (pFunction != NULL) if (pFunction != NULL)
{ {
pFunction->Execute(&result); pFunction->Execute(&result);
@ -468,7 +346,7 @@ void CPlugin::Call_OnAllPluginsLoaded()
if (g_OnMapStarted) if (g_OnMapStarted)
{ {
if ((pFunction = m_ctx.base->GetFunctionByName("OnMapStart")) != NULL) if ((pFunction = m_pRuntime->GetFunctionByName("OnMapStart")) != NULL)
{ {
pFunction->Execute(NULL); pFunction->Execute(NULL);
} }
@ -491,7 +369,7 @@ bool CPlugin::Call_AskPluginLoad(char *error, size_t maxlength)
int err; int err;
cell_t result; cell_t result;
IPluginFunction *pFunction = m_ctx.base->GetFunctionByName("AskPluginLoad"); IPluginFunction *pFunction = m_pRuntime->GetFunctionByName("AskPluginLoad");
if (!pFunction) if (!pFunction)
{ {
@ -515,19 +393,24 @@ bool CPlugin::Call_AskPluginLoad(char *error, size_t maxlength)
return true; return true;
} }
const sp_plugin_t *CPlugin::GetPluginStructure() void *CPlugin::GetPluginStructure()
{ {
return m_plugin; return NULL;
} }
IPluginContext *CPlugin::GetBaseContext() IPluginContext *CPlugin::GetBaseContext()
{ {
return m_ctx.base; if (m_pRuntime == NULL)
{
return NULL;
}
return m_pRuntime->GetDefaultContext();
} }
sp_context_t *CPlugin::GetContext() sp_context_t *CPlugin::GetContext()
{ {
return m_ctx.ctx; return NULL;
} }
const char *CPlugin::GetFilename() const char *CPlugin::GetFilename()
@ -557,12 +440,12 @@ PluginStatus CPlugin::GetStatus()
bool CPlugin::IsDebugging() bool CPlugin::IsDebugging()
{ {
if (!m_ctx.ctx) if (m_pRuntime == NULL)
{ {
return false; return false;
} }
return ((m_ctx.ctx->flags & SP_FLAG_DEBUG) == SP_FLAG_DEBUG); return m_pRuntime->IsDebugging();
} }
void CPlugin::LibraryActions(bool dropping) void CPlugin::LibraryActions(bool dropping)
@ -590,7 +473,7 @@ bool CPlugin::SetPauseState(bool paused)
LibraryActions(true); LibraryActions(true);
} }
IPluginFunction *pFunction = m_ctx.base->GetFunctionByName("OnPluginPauseChange"); IPluginFunction *pFunction = m_pRuntime->GetFunctionByName("OnPluginPauseChange");
if (pFunction) if (pFunction)
{ {
cell_t result; cell_t result;
@ -601,10 +484,10 @@ bool CPlugin::SetPauseState(bool paused)
if (paused) if (paused)
{ {
m_status = Plugin_Paused; m_status = Plugin_Paused;
m_ctx.ctx->flags |= SPFLAG_PLUGIN_PAUSED; m_pRuntime->SetPauseState(true);
} else { } else {
m_status = Plugin_Running; m_status = Plugin_Running;
m_ctx.ctx->flags &= ~SPFLAG_PLUGIN_PAUSED; m_pRuntime->SetPauseState(false);
} }
g_PluginSys._SetPauseState(this, paused); g_PluginSys._SetPauseState(this, paused);
@ -652,8 +535,9 @@ bool CPlugin::ToggleDebugMode(bool debug, char *error, size_t maxlength)
return false; return false;
} }
ICompilation *co = g_pVM->StartCompilation(m_ctx.ctx->plugin); ICompilation *co = g_pSourcePawn2->StartCompilation();
if (!g_pVM->SetCompilationOption(co, "debug", (debug) ? "1" : "0"))
if (!co->SetOption("debug", (debug) ? "1" : "0"))
{ {
if (error) if (error)
{ {
@ -662,32 +546,7 @@ bool CPlugin::ToggleDebugMode(bool debug, char *error, size_t maxlength)
return false; return false;
} }
sp_context_t *new_ctx = g_pVM->CompileToContext(co, &err); if ((err = m_pRuntime->ApplyCompilationOptions(co)) != SP_ERROR_NONE)
if (new_ctx)
{
memcpy(new_ctx->memory, m_ctx.ctx->memory, m_ctx.ctx->mem_size);
new_ctx->hp = m_ctx.ctx->hp;
new_ctx->sp = m_ctx.ctx->sp;
new_ctx->frm = m_ctx.ctx->frm;
new_ctx->dbreak = m_ctx.ctx->dbreak;
new_ctx->context = m_ctx.ctx->context;
memcpy(new_ctx->user, m_ctx.ctx->user, sizeof(m_ctx.ctx->user));
uint32_t nativeCount = m_plugin->info.natives_num;
for (uint32_t i=0; i<nativeCount; i++)
{
new_ctx->natives[i].pfn = m_ctx.ctx->natives[i].pfn;
new_ctx->natives[i].status = m_ctx.ctx->natives[i].status;
}
g_pVM->FreeContext(m_ctx.ctx);
m_ctx.ctx = new_ctx;
m_ctx.base->SetContext(new_ctx);
UpdateInfo();
}
else
{ {
if (error) if (error)
{ {
@ -696,6 +555,8 @@ bool CPlugin::ToggleDebugMode(bool debug, char *error, size_t maxlength)
return false; return false;
} }
UpdateInfo();
return true; return true;
} }
@ -741,7 +602,7 @@ IPhraseCollection *CPlugin::GetPhrases()
void CPlugin::DependencyDropped(CPlugin *pOwner) void CPlugin::DependencyDropped(CPlugin *pOwner)
{ {
if (!m_ctx.ctx) if (!m_pRuntime)
{ {
return; return;
} }
@ -771,12 +632,12 @@ void CPlugin::DependencyDropped(CPlugin *pOwner)
{ {
pNative = (*iter); pNative = (*iter);
/* Find this native! */ /* Find this native! */
if (m_ctx.base->FindNativeByName(pNative->name, &idx) != SP_ERROR_NONE) if (m_pRuntime->FindNativeByName(pNative->name, &idx) != SP_ERROR_NONE)
{ {
continue; continue;
} }
/* Unbind it */ /* Unbind it */
m_ctx.base->GetNativeByIndex(idx, &native); m_pRuntime->GetNativeByIndex(idx, &native);
native->pfn = NULL; native->pfn = NULL;
native->status = SP_NATIVE_UNBOUND; native->status = SP_NATIVE_UNBOUND;
unbound++; unbound++;
@ -1047,6 +908,7 @@ LoadRes CPluginManager::_LoadPlugin(CPlugin **_plugin, const char *path, bool de
return LoadRes_NeverLoad; return LoadRes_NeverLoad;
} }
int err;
bool no_load = false; bool no_load = false;
PluginSettings *pset; PluginSettings *pset;
unsigned int setcount = m_PluginInfo.GetSettingsNum(); unsigned int setcount = m_PluginInfo.GetSettingsNum();
@ -1102,7 +964,7 @@ LoadRes CPluginManager::_LoadPlugin(CPlugin **_plugin, const char *path, bool de
if (pPlugin->m_status == Plugin_Uncompiled) if (pPlugin->m_status == Plugin_Uncompiled)
{ {
co = pPlugin->StartMyCompile(g_pVM); co = g_pSourcePawn2->StartCompilation();
} }
for (unsigned int i=0; i<setcount; i++) for (unsigned int i=0; i<setcount; i++)
@ -1122,13 +984,13 @@ LoadRes CPluginManager::_LoadPlugin(CPlugin **_plugin, const char *path, bool de
{ {
continue; continue;
} }
if (!g_pVM->SetCompilationOption(co, key, val)) if ((err = co->SetOption(key, val)) == SP_ERROR_NONE)
{ {
if (error) if (error)
{ {
snprintf(error, maxlength, "Unable to set JIT option (key \"%s\") (value \"%s\")", key, val); snprintf(error, maxlength, "Unable to set JIT option (key \"%s\") (value \"%s\")", key, val);
} }
pPlugin->CancelMyCompile(); co->Abort();
co = NULL; co = NULL;
break; break;
} }
@ -1137,10 +999,25 @@ LoadRes CPluginManager::_LoadPlugin(CPlugin **_plugin, const char *path, bool de
} }
/* Do the actual compiling */ /* Do the actual compiling */
if (co) if (co != NULL)
{ {
pPlugin->FinishMyCompile(error, maxlength); char fullpath[PLATFORM_MAX_PATH];
co = NULL; g_SourceMod.BuildPath(Path_SM, fullpath, sizeof(fullpath), "plugins/%s", pPlugin->m_filename);
pPlugin->m_pRuntime = g_pSourcePawn2->LoadPlugin(co, fullpath, &err);
if (pPlugin->m_pRuntime == NULL)
{
snprintf(error,
maxlength,
"Unable to load plugin (error %d: %s)",
err,
g_pSourcePawn2->GetErrorString(err));
}
else
{
pPlugin->UpdateInfo();
pPlugin->m_status = Plugin_Created;
}
} }
/* Get the status */ /* Get the status */
@ -1321,7 +1198,7 @@ bool CPluginManager::FindOrRequirePluginDeps(CPlugin *pPlugin, char *error, size
{ {
cell_t res; cell_t res;
pFunc->Execute(&res); pFunc->Execute(&res);
if (pPlugin->GetContext()->n_err != SP_ERROR_NONE) if (pPlugin->GetBaseContext()->GetLastNativeError() != SP_ERROR_NONE)
{ {
if (error) if (error)
{ {
@ -1448,7 +1325,7 @@ bool CPluginManager::LoadOrRequireExtensions(CPlugin *pPlugin, unsigned int pass
{ {
cell_t res; cell_t res;
pFunc->Execute(&res); pFunc->Execute(&res);
if (pPlugin->GetContext()->n_err != SP_ERROR_NONE) if (pPlugin->GetBaseContext()->GetLastNativeError() != SP_ERROR_NONE)
{ {
if (error) if (error)
{ {
@ -1615,9 +1492,9 @@ void CPluginManager::TryRefreshDependencies(CPlugin *pPlugin)
{ {
/* If we got here, all natives are okay again! */ /* If we got here, all natives are okay again! */
pPlugin->m_status = Plugin_Running; pPlugin->m_status = Plugin_Running;
if ((pPlugin->m_ctx.ctx->flags & SPFLAG_PLUGIN_PAUSED) == SPFLAG_PLUGIN_PAUSED) if (pPlugin->m_pRuntime->IsPaused())
{ {
pPlugin->m_ctx.ctx->flags &= ~SPFLAG_PLUGIN_PAUSED; pPlugin->m_pRuntime->SetPauseState(false);
_SetPauseState(pPlugin, false); _SetPauseState(pPlugin, false);
} }
} }
@ -1687,8 +1564,22 @@ bool CPluginManager::UnloadPlugin(IPlugin *plugin)
IPlugin *CPluginManager::FindPluginByContext(const sp_context_t *ctx) IPlugin *CPluginManager::FindPluginByContext(const sp_context_t *ctx)
{ {
IPlugin *pl = (IPlugin *)ctx->user[SM_CONTEXTVAR_MYSELF]; IPlugin *pPlugin;
return pl; IPluginContext *pContext;
pContext = reinterpret_cast<IPluginContext *>(const_cast<sp_context_t *>(ctx));
if (pContext->GetKey(2, (void **)&pPlugin))
{
return pPlugin;
}
return NULL;
}
CPlugin *CPluginManager::GetPluginByCtx(const sp_context_t *ctx)
{
return (CPlugin *)FindPluginByContext(ctx);
} }
unsigned int CPluginManager::GetPluginCount() unsigned int CPluginManager::GetPluginCount()

View File

@ -43,7 +43,6 @@
#include <sh_vector.h> #include <sh_vector.h>
#include <sh_string.h> #include <sh_string.h>
#include "sm_globals.h" #include "sm_globals.h"
#include "vm/sp_vm_basecontext.h"
#include "PluginInfoDatabase.h" #include "PluginInfoDatabase.h"
#include "sm_trie.h" #include "sm_trie.h"
#include "sourcemod.h" #include "sourcemod.h"
@ -109,19 +108,6 @@ using namespace SourceHook;
* 7. Once all plugins are deemed to be loaded, OnPluginStart() is called * 7. Once all plugins are deemed to be loaded, OnPluginStart() is called
*/ */
#define SM_CONTEXTVAR_MYSELF 0
struct ContextPair
{
ContextPair() : base(NULL), ctx(NULL), co(NULL)
{
};
BaseContext *base;
sp_context_t *ctx;
ICompilation *co;
IVirtualMachine *vm;
};
enum LoadRes enum LoadRes
{ {
LoadRes_Successful, LoadRes_Successful,
@ -152,18 +138,19 @@ public:
PluginType GetType(); PluginType GetType();
SourcePawn::IPluginContext *GetBaseContext(); SourcePawn::IPluginContext *GetBaseContext();
sp_context_t *GetContext(); sp_context_t *GetContext();
const sm_plugininfo_t *GetPublicInfo(); void *GetPluginStructure();
const char *GetFilename(); const char *GetFilename();
bool IsDebugging(); bool IsDebugging();
PluginStatus GetStatus(); PluginStatus GetStatus();
const sm_plugininfo_t *GetPublicInfo();
bool SetPauseState(bool paused); bool SetPauseState(bool paused);
unsigned int GetSerial(); unsigned int GetSerial();
const sp_plugin_t *GetPluginStructure();
IdentityToken_t *GetIdentity(); IdentityToken_t *GetIdentity();
unsigned int CalcMemUsage(); unsigned int CalcMemUsage();
bool SetProperty(const char *prop, void *ptr); bool SetProperty(const char *prop, void *ptr);
bool GetProperty(const char *prop, void **ptr, bool remove=false); bool GetProperty(const char *prop, void **ptr, bool remove=false);
void DropEverything(); void DropEverything();
SourcePawn::IPluginRuntime *GetRuntime();
public: public:
/** /**
* Creates a plugin object with default values. * Creates a plugin object with default values.
@ -174,16 +161,6 @@ public:
*/ */
static CPlugin *CreatePlugin(const char *file, char *error, size_t maxlength); static CPlugin *CreatePlugin(const char *file, char *error, size_t maxlength);
public: public:
/**
* Starts the initial compilation of a plugin.
* Returns false if another compilation exists or there is a current context set.
*/
ICompilation *StartMyCompile(IVirtualMachine *vm);
/**
* Finalizes a compilation. If error buffer is NULL, the error is saved locally.
*/
bool FinishMyCompile(char *error, size_t maxlength);
void CancelMyCompile();
/** /**
* Sets an error state on the plugin * Sets an error state on the plugin
@ -267,13 +244,11 @@ protected:
void SetTimeStamp(time_t t); void SetTimeStamp(time_t t);
void DependencyDropped(CPlugin *pOwner); void DependencyDropped(CPlugin *pOwner);
private: private:
ContextPair m_ctx;
PluginType m_type; PluginType m_type;
char m_filename[PLATFORM_MAX_PATH]; char m_filename[PLATFORM_MAX_PATH];
PluginStatus m_status; PluginStatus m_status;
unsigned int m_serial; unsigned int m_serial;
sm_plugininfo_t m_info; sm_plugininfo_t m_info;
sp_plugin_t *m_plugin;
char m_errormsg[256]; char m_errormsg[256];
time_t m_LastAccess; time_t m_LastAccess;
IdentityToken_t *m_ident; IdentityToken_t *m_ident;
@ -289,6 +264,8 @@ private:
bool m_bGotAllLoaded; bool m_bGotAllLoaded;
int m_FileVersion; int m_FileVersion;
char m_DateTime[256]; char m_DateTime[256];
IPluginRuntime *m_pRuntime;
IPluginContext *m_pContext;
}; };
class CPluginManager : class CPluginManager :
@ -382,10 +359,7 @@ public:
/** /**
* Internal version of FindPluginByContext() * Internal version of FindPluginByContext()
*/ */
inline CPlugin *GetPluginByCtx(const sp_context_t *ctx) CPlugin *GetPluginByCtx(const sp_context_t *ctx);
{
return reinterpret_cast<CPlugin *>(ctx->user[SM_CONTEXTVAR_MYSELF]);
}
/** /**
* Gets status text for a status code * Gets status text for a status code

View File

@ -488,7 +488,7 @@ NativeEntry *ShareSystem::AddFakeNative(IPluginFunction *pFunc, const char *name
pFake = new FakeNative; pFake = new FakeNative;
if ((gate = g_pVM->CreateFakeNative(func, pFake)) == NULL) if ((gate = g_pSourcePawn2->CreateFakeNative(func, pFake)) == NULL)
{ {
delete pFake; delete pFake;
return NULL; return NULL;

File diff suppressed because it is too large Load Diff

View File

@ -1,124 +0,0 @@
/**
* vim: set ts=4 :
* =============================================================================
* SourcePawn
* Copyright (C) 2004-2008 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 <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_
#define _INCLUDE_SOURCEPAWN_BASECONTEXT_H_
#include "sp_vm_api.h"
#include "sp_vm_function.h"
/**
* :TODO: Make functions allocate as a lump instead of individual allocations!
*/
extern IProfiler *sm_profiler;
namespace SourcePawn
{
class BaseContext :
public IPluginContext,
public IPluginDebugInfo
{
public:
BaseContext(sp_context_t *ctx);
~BaseContext();
public: //IPluginContext
IVirtualMachine *GetVirtualMachine();
sp_context_t *GetContext();
bool IsDebugging();
int SetDebugBreak(SPVM_DEBUGBREAK newpfn, SPVM_DEBUGBREAK *oldpfn);
IPluginDebugInfo *GetDebugInfo();
int HeapAlloc(unsigned int cells, cell_t *local_addr, cell_t **phys_addr);
int HeapPop(cell_t local_addr);
int HeapRelease(cell_t local_addr);
int FindNativeByName(const char *name, uint32_t *index);
int GetNativeByIndex(uint32_t index, sp_native_t **native);
uint32_t GetNativesNum();
int FindPublicByName(const char *name, uint32_t *index);
int GetPublicByIndex(uint32_t index, sp_public_t **publicptr);
uint32_t GetPublicsNum();
int GetPubvarByIndex(uint32_t index, sp_pubvar_t **pubvar);
int FindPubvarByName(const char *name, uint32_t *index);
int GetPubvarAddrs(uint32_t index, cell_t *local_addr, cell_t **phys_addr);
uint32_t GetPubVarsNum();
int LocalToPhysAddr(cell_t local_addr, cell_t **phys_addr);
int LocalToString(cell_t local_addr, char **addr);
int StringToLocal(cell_t local_addr, size_t chars, const char *source);
int StringToLocalUTF8(cell_t local_addr, size_t maxbytes, const char *source, size_t *wrtnbytes);
int PushCell(cell_t value);
int PushCellArray(cell_t *local_addr, cell_t **phys_addr, cell_t array[], unsigned int numcells);
int PushString(cell_t *local_addr, char **phys_addr, const char *string);
int PushCellsFromArray(cell_t array[], unsigned int numcells);
int BindNatives(const sp_nativeinfo_t *natives, unsigned int num, int overwrite);
int BindNative(const sp_nativeinfo_t *native);
int BindNativeToAny(SPVM_NATIVE_FUNC native);
int Execute(uint32_t code_addr, cell_t *result);
cell_t ThrowNativeErrorEx(int error, const char *msg, ...);
cell_t ThrowNativeError(const char *msg, ...);
IPluginFunction *GetFunctionByName(const char *public_name);
IPluginFunction *GetFunctionById(funcid_t func_id);
#if defined SOURCEMOD_BUILD
SourceMod::IdentityToken_t *GetIdentity();
void SetIdentity(SourceMod::IdentityToken_t *token);
cell_t *GetNullRef(SP_NULL_TYPE type);
int LocalToStringNULL(cell_t local_addr, char **addr);
#endif
int BindNativeToIndex(uint32_t index, SPVM_NATIVE_FUNC native);
public: //IPluginDebugInfo
int LookupFile(ucell_t addr, const char **filename);
int LookupFunction(ucell_t addr, const char **name);
int LookupLine(ucell_t addr, uint32_t *line);
public:
void SetContext(sp_context_t *_ctx);
bool IsInExec();
private:
void SetErrorMessage(const char *msg, va_list ap);
void FlushFunctionCache();
void RefreshFunctionCache();
private:
sp_context_t *ctx;
#if defined SOURCEMOD_BUILD
SourceMod::IdentityToken_t *m_pToken;
cell_t *m_pNullVec;
cell_t *m_pNullString;
#endif
char m_MsgCache[1024];
bool m_CustomMsg;
bool m_InExec;
unsigned int m_funcsnum;
#if 0
CFunction **m_priv_funcs;
#endif
CFunction **m_pub_funcs;
};
};
#endif //_INCLUDE_SOURCEPAWN_BASECONTEXT_H_

View File

@ -109,25 +109,25 @@ namespace SourceMod
virtual PluginType GetType() =0; virtual PluginType GetType() =0;
/** /**
* @brief Returns the current API context being used in the plugin. * @brief Returns the IPluginRuntime::GetDefaultContext() value.
* *
* @return Pointer to an IPluginContext, or NULL if not loaded. * @return Pointer to an IPluginContext, or NULL if not loaded.
*/ */
virtual SourcePawn::IPluginContext *GetBaseContext() =0; virtual SourcePawn::IPluginContext *GetBaseContext() =0;
/** /**
* @brief Returns the context structure being used in the plugin. * @brief Deprecated, returns NULL.
* *
* @return Pointer to an sp_context_t, or NULL if not loaded. * @return NULL.
*/ */
virtual sp_context_t *GetContext() =0; virtual sp_context_t *GetContext() =0;
/** /**
* @brief Returns the plugin file structure. * @brief Deprecated, returns NULL.
* *
* @return Pointer to an sp_plugin_t, or NULL if not loaded. * @return NULL.
*/ */
virtual const sp_plugin_t *GetPluginStructure() =0; virtual void *GetPluginStructure() =0;
/** /**
* @brief Returns information about the plugin by reference. * @brief Returns information about the plugin by reference.
@ -189,6 +189,13 @@ namespace SourceMod
* @return True if the property existed, false otherwise. * @return True if the property existed, false otherwise.
*/ */
virtual bool GetProperty(const char *prop, void **ptr, bool remove=false) =0; virtual bool GetProperty(const char *prop, void **ptr, bool remove=false) =0;
/**
* @brief Returns the runtime representing this plugin.
*
* @return IPluginRuntime pointer, or NULL if not loaded.
*/
virtual SourcePawn::IPluginRuntime *GetRuntime() =0;
}; };

View File

@ -203,9 +203,9 @@ namespace SourceMod
virtual SourcePawn::ISourcePawnEngine *GetScriptingEngine() =0; virtual SourcePawn::ISourcePawnEngine *GetScriptingEngine() =0;
/** /**
* @brief Returns the JIT interface. * @brief Deprecated, do not use.
* *
* @return A pointer to the JIT interface. * @return NULL.
*/ */
virtual SourcePawn::IVirtualMachine *GetScriptingVM() =0; virtual SourcePawn::IVirtualMachine *GetScriptingVM() =0;

View File

@ -41,10 +41,8 @@
#include "sp_vm_types.h" #include "sp_vm_types.h"
/** SourcePawn Engine API Version */ /** SourcePawn Engine API Version */
#define SOURCEPAWN_ENGINE_API_VERSION 3 #define SOURCEPAWN_ENGINE_API_VERSION 4
#define SOURCEPAWN_ENGINE2_API_VERSION 1
/** SourcePawn VM API Version */
#define SOURCEPAWN_VM_API_VERSION 7
#if !defined SOURCEMOD_BUILD #if !defined SOURCEMOD_BUILD
#define SOURCEMOD_BUILD #define SOURCEMOD_BUILD
@ -57,6 +55,9 @@ namespace SourceMod
}; };
#endif #endif
struct sp_context_s;
typedef struct sp_context_s sp_context_t;
namespace SourcePawn namespace SourcePawn
{ {
class IVirtualMachine; class IVirtualMachine;
@ -185,7 +186,8 @@ namespace SourcePawn
{ {
public: public:
/** /**
* @brief Executes the forward, resets the pushed parameter list, and performs any copybacks. * @brief Executes the function, resets the pushed parameter list, and
* performs any copybacks.
* *
* @param result Pointer to store return value in. * @param result Pointer to store return value in.
* @return Error code, if any. * @return Error code, if any.
@ -206,9 +208,9 @@ namespace SourcePawn
virtual int CallFunction(const cell_t *params, unsigned int num_params, cell_t *result) =0; virtual int CallFunction(const cell_t *params, unsigned int num_params, cell_t *result) =0;
/** /**
* @brief Returns which plugin this function belongs to. * @brief Deprecated, do not use.
* *
* @return IPluginContext pointer to parent plugin. * @return GetDefaultContext() of parent runtime.
*/ */
virtual IPluginContext *GetParentContext() =0; virtual IPluginContext *GetParentContext() =0;
@ -227,6 +229,37 @@ namespace SourcePawn
* @return Function id. * @return Function id.
*/ */
virtual funcid_t GetFunctionID() =0; virtual funcid_t GetFunctionID() =0;
/**
* @brief Executes the forward, resets the pushed parameter list, and
* performs any copybacks.
*
* Note: A function can only be executed given a runtime it was created in.
*
* @param ctx Context to execute the function in.
* @param result Pointer to store return value in.
* @return Error code, if any.
*/
virtual int Execute2(IPluginContext *ctx, cell_t *result) =0;
/**
* @brief Executes the function with the given parameter array.
* Parameters are read in forward order (i.e. index 0 is parameter #1)
* NOTE: You will get an error if you attempt to use CallFunction() with
* previously pushed parameters.
*
* Note: A function can only be executed given a runtime it was created in.
*
* @param ctx Context to execute the function in.
* @param params Array of cell parameters.
* @param num_params Number of parameters to push.
* @param result Pointer to store result of function on return.
* @return SourcePawn error code (if any).
*/
virtual int CallFunction2(IPluginContext *ctx,
const cell_t *params,
unsigned int num_params,
cell_t *result) =0;
}; };
@ -262,43 +295,38 @@ namespace SourcePawn
}; };
/** /**
* @brief Interface to managing a context at runtime. * @brief Represents a JIT compilation or plugin loading options.
*/ */
class IPluginContext class ICompilation
{ {
public: public:
/** Virtual destructor */ /**
virtual ~IPluginContext() { }; * @brief Sets a compilation option.
*
* @param key Option name.
* @param val Option value.
* @return True on success, false on failure.
*/
virtual bool SetOption(const char *key, const char *val) =0;
/**
* @brief Aborts the compilation and destroys this object.
*/
virtual void Abort() =0;
};
/**
* @brief Interface to managing a runtime plugin.
*/
class IPluginRuntime
{
public: public:
/** /**
* @brief Returns the parent IVirtualMachine. * @brief Virtual destructor (you may call delete).
*
* @return Parent virtual machine pointer.
*/ */
virtual IVirtualMachine *GetVirtualMachine() =0; virtual ~IPluginRuntime()
{
/** }
* @brief Returns the child sp_context_t structure.
*
* @return Child sp_context_t structure.
*/
virtual sp_context_t *GetContext() =0;
/**
* @brief Returns true if the plugin is in debug mode.
*
* @return True if in debug mode, false otherwise.
*/
virtual bool IsDebugging() =0;
/**
* @brief Installs a debug break and returns the old one, if any.
* This will fail if the plugin is not debugging.
*
* @param newpfn New function pointer.
* @param oldpfn Pointer to retrieve old function pointer.
*/
virtual int SetDebugBreak(SPVM_DEBUGBREAK newpfn, SPVM_DEBUGBREAK *oldpfn) =0;
/** /**
* @brief Returns debug info. * @brief Returns debug info.
@ -307,39 +335,6 @@ namespace SourcePawn
*/ */
virtual IPluginDebugInfo *GetDebugInfo() =0; virtual IPluginDebugInfo *GetDebugInfo() =0;
/**
* @brief Allocates memory on the secondary stack of a plugin.
* Note that although called a heap, it is in fact a stack.
*
* @param cells Number of cells to allocate.
* @param local_addr Will be filled with data offset to heap.
* @param phys_addr Physical address to heap memory.
*/
virtual int HeapAlloc(unsigned int cells, cell_t *local_addr, cell_t **phys_addr) =0;
/**
* @brief Pops a heap address off the heap stack. Use this to free memory allocated with
* SP_HeapAlloc().
* Note that in SourcePawn, the heap is in fact a bottom-up stack. Deallocations
* with this native should be performed in precisely the REVERSE order.
*
* @param local_addr Local address to free.
*/
virtual int HeapPop(cell_t local_addr) =0;
/**
* @brief Releases a heap address using a different method than SP_HeapPop().
* This allows you to release in any order. However, if you allocate N
* objects, release only some of them, then begin allocating again,
* you cannot go back and starting freeing the originals.
* In other words, for each chain of allocations, if you start deallocating,
* then allocating more in a chain, you must only deallocate from the current
* allocation chain. This is basically HeapPop() except on a larger scale.
*
* @param local_addr Local address to free.
*/
virtual int HeapRelease(cell_t local_addr) =0;
/** /**
* @brief Finds a native by name. * @brief Finds a native by name.
* *
@ -419,7 +414,227 @@ namespace SourcePawn
virtual uint32_t GetPubVarsNum() =0; virtual uint32_t GetPubVarsNum() =0;
/** /**
* @brief Round-about method of converting a plugin reference to a physical address * @brief Returns a function by name.
*
* @param public_name Name of the function.
* @return A new IPluginFunction pointer, NULL if not found.
*/
virtual IPluginFunction *GetFunctionByName(const char *public_name) =0;
/**
* @brief Returns a function by its id.
*
* @param func_id Function ID.
* @return A new IPluginFunction pointer, NULL if not found.
*/
virtual IPluginFunction *GetFunctionById(funcid_t func_id) =0;
/**
* @brief Returns the default context. The default context
* should not be destroyed.
*
* @return Default context pointer.
*/
virtual IPluginContext *GetDefaultContext() =0;
/**
* @brief Returns true if the plugin is in debug mode.
*
* @return True if in debug mode, false otherwise.
*/
virtual bool IsDebugging() =0;
/**
* @brief Applies new compilation/runtime settings to the runtime code.
*
* The compilation object is destroyed once this function completes.
*
* @return Error code (SP_ERROR_NONE on success).
*/
virtual int ApplyCompilationOptions(ICompilation *co) =0;
/**
* @brief Sets whether or not the plugin is paused (cannot be run).
*
* @param pause Pause state.
*/
virtual void SetPauseState(bool paused) =0;
/**
* @brief Returns whether or not the plugin is paused (runnable).
*
* @return Pause state (true = paused, false = not).
*/
virtual bool IsPaused() =0;
/**
* @brief Returns the estimated memory usage of this plugin.
*
* @return Memory usage, in bytes.
*/
virtual size_t GetMemUsage() =0;
};
/**
* @brief Interface to managing a context at runtime.
*/
class IPluginContext
{
public:
/** Virtual destructor */
virtual ~IPluginContext() { };
public:
/**
* @brief Deprecated, does nothing.
*
* @return NULL.
*/
virtual IVirtualMachine *GetVirtualMachine() =0;
/**
* @brief Deprecated, do not use.
*
* Returns the pointer of this object, casted to an opaque structure.
*
* @return Returns this.
*/
virtual sp_context_t *GetContext() =0;
/**
* @brief Returns true if the plugin is in debug mode.
*
* @return True if in debug mode, false otherwise.
*/
virtual bool IsDebugging() =0;
/**
* @brief Deprecated, does nothing.
*
* @param newpfn Unused.
* @param oldpfn Unused.
*/
virtual int SetDebugBreak(void *newpfn, void *oldpfn) =0;
/**
* @brief Deprecated, do not use.
*
* @return NULL.
*/
virtual IPluginDebugInfo *GetDebugInfo() =0;
/**
* @brief Allocates memory on the secondary stack of a plugin.
* Note that although called a heap, it is in fact a stack.
*
* @param cells Number of cells to allocate.
* @param local_addr Will be filled with data offset to heap.
* @param phys_addr Physical address to heap memory.
*/
virtual int HeapAlloc(unsigned int cells, cell_t *local_addr, cell_t **phys_addr) =0;
/**
* @brief Pops a heap address off the heap stack. Use this to free memory allocated with
* SP_HeapAlloc().
* Note that in SourcePawn, the heap is in fact a bottom-up stack. Deallocations
* with this native should be performed in precisely the REVERSE order.
*
* @param local_addr Local address to free.
*/
virtual int HeapPop(cell_t local_addr) =0;
/**
* @brief Releases a heap address using a different method than SP_HeapPop().
* This allows you to release in any order. However, if you allocate N
* objects, release only some of them, then begin allocating again,
* you cannot go back and starting freeing the originals.
* In other words, for each chain of allocations, if you start deallocating,
* then allocating more in a chain, you must only deallocate from the current
* allocation chain. This is basically HeapPop() except on a larger scale.
*
* @param local_addr Local address to free.
*/
virtual int HeapRelease(cell_t local_addr) =0;
/**
* @brief Deprecated, use IPluginRuntime instead.
*
* @param name Name of native.
* @param index Optionally filled with native index number.
*/
virtual int FindNativeByName(const char *name, uint32_t *index) =0;
/**
* @brief Deprecated, use IPluginRuntime instead.
*
* @param index Index number of native.
* @param native Optionally filled with pointer to native structure.
*/
virtual int GetNativeByIndex(uint32_t index, sp_native_t **native) =0;
/**
* @brief Deprecated, use IPluginRuntime instead.
*
* @return Filled with the number of natives.
*/
virtual uint32_t GetNativesNum() =0;
/**
* @brief Deprecated, use IPluginRuntime instead.
*
* @param name Name of public
* @param index Optionally filled with public index number.
*/
virtual int FindPublicByName(const char *name, uint32_t *index) =0;
/**
* @brief Deprecated, use IPluginRuntime instead.
*
* @param index Public function index number.
* @param publicptr Optionally filled with pointer to public structure.
*/
virtual int GetPublicByIndex(uint32_t index, sp_public_t **publicptr) =0;
/**
* @brief Deprecated, use IPluginRuntime instead.
*
* @return Filled with the number of public functions.
*/
virtual uint32_t GetPublicsNum() =0;
/**
* @brief Deprecated, use IPluginRuntime instead.
*
* @param index Public variable index number.
* @param pubvar Optionally filled with pointer to pubvar structure.
*/
virtual int GetPubvarByIndex(uint32_t index, sp_pubvar_t **pubvar) =0;
/**
* @brief Deprecated, use IPluginRuntime instead.
*
* @param name Name of pubvar
* @param index Optionally filled with pubvar index number.
*/
virtual int FindPubvarByName(const char *name, uint32_t *index) =0;
/**
* @brief Deprecated, use IPluginRuntime instead.
*
* @param index Index of public variable.
* @param local_addr Address to store local address in.
* @param phys_addr Address to store physically relocated in.
*/
virtual int GetPubvarAddrs(uint32_t index, cell_t *local_addr, cell_t **phys_addr) =0;
/**
* @brief Deprecated, use IPluginRuntime instead.
*
* @return Number of public variables.
*/
virtual uint32_t GetPubVarsNum() =0;
/**
* @brief Converts a plugin reference to a physical address
* *
* @param local_addr Local address in plugin. * @param local_addr Local address in plugin.
* @param phys_addr Optionally filled with relocated physical address. * @param phys_addr Optionally filled with relocated physical address.
@ -445,8 +660,8 @@ namespace SourcePawn
/** /**
* @brief Converts a physical UTF-8 string to a local address. * @brief Converts a physical UTF-8 string to a local address.
* This function is the same as the ANSI version, except it will copy the maximum number of characters possible * This function is the same as the ANSI version, except it will copy the maximum number
* without accidentally chopping a multi-byte character. * of characters possible without accidentally chopping a multi-byte character.
* *
* @param local_addr Local address in plugin. * @param local_addr Local address in plugin.
* @param maxbytes Number of bytes to write, including NULL terminator. * @param maxbytes Number of bytes to write, including NULL terminator.
@ -459,48 +674,41 @@ namespace SourcePawn
size_t *wrtnbytes) =0; size_t *wrtnbytes) =0;
/** /**
* @brief Pushes a cell onto the stack. Increases the parameter count by one. * @brief Deprecated, does nothing.
* *
* @param value Cell value. * @param value Unused.
*/ */
virtual int PushCell(cell_t value) =0; virtual int PushCell(cell_t value) =0;
/** /**
* @brief Pushes an array of cells onto the stack. Increases the parameter count by one. * @brief Deprecated, does nothing.
* If the function returns an error it will fail entirely, releasing anything allocated in the process.
* Note that this does not release the heap, so you should release it after
* calling Execute().
* *
* @param local_addr Filled with local address to release. * @param local_addr Unused.
* @param phys_addr Optionally filled with physical address of new array. * @param phys_addr Unused.
* @param array Cell array to copy. * @param array Unused.
* @param numcells Number of cells in the array to copy. * @param numcells Unused.
*/ */
virtual int PushCellArray(cell_t *local_addr, cell_t **phys_addr, cell_t array[], unsigned int numcells) =0; virtual int PushCellArray(cell_t *local_addr, cell_t **phys_addr, cell_t array[], unsigned int numcells) =0;
/** /**
* @brief Pushes a string onto the stack (by reference) and increases the parameter count by one. * @brief Deprecated, does nothing.
* Note that this does not release the heap, so you should release it after
* calling Execute().
* *
* @param local_addr Filled with local address to release. * @param local_addr Unused.
* @param phys_addr Optionally filled with physical address of new array. * @param phys_addr Unused.
* @param string Source string to push. * @param string Unused.
*/ */
virtual int PushString(cell_t *local_addr, char **phys_addr, const char *string) =0; virtual int PushString(cell_t *local_addr, char **phys_addr, const char *string) =0;
/** /**
* @brief Individually pushes each cell of an array of cells onto the stack. Increases the * @brief Deprecated, does nothing.
* parameter count by the number of cells pushed.
* If the function returns an error it will fail entirely, releasing anything allocated in the process.
* *
* @param array Array of cells to read from. * @param array Unused.
* @param numcells Number of cells to read. * @param numcells Unused.
*/ */
virtual int PushCellsFromArray(cell_t array[], unsigned int numcells) =0; virtual int PushCellsFromArray(cell_t array[], unsigned int numcells) =0;
/** /**
* @brief Deprecated; do not use. * @brief Deprecated, does nothing.
* *
* @param natives Deprecated; do not use. * @param natives Deprecated; do not use.
* @param num Deprecated; do not use. * @param num Deprecated; do not use.
@ -509,25 +717,25 @@ namespace SourcePawn
virtual int BindNatives(const sp_nativeinfo_t *natives, unsigned int num, int overwrite) =0; virtual int BindNatives(const sp_nativeinfo_t *natives, unsigned int num, int overwrite) =0;
/** /**
* @brief Deprecated; do not use. * @brief Deprecated, does nothing.
* *
* @param native Deprecated; do not use. * @param native Deprecated; do not use.
*/ */
virtual int BindNative(const sp_nativeinfo_t *native) =0; virtual int BindNative(const sp_nativeinfo_t *native) =0;
/** /**
* @brief Binds a single native to any non-registered native. * @brief Deprecated, does nothing.
* *
* @param native Native to bind. * @param native Unused.
*/ */
virtual int BindNativeToAny(SPVM_NATIVE_FUNC native) =0; virtual int BindNativeToAny(SPVM_NATIVE_FUNC native) =0;
/** /**
* @brief Executes a function ID located in this context. * @brief Deprecated, does nothing.
* *
* @param code_addr Address to execute at. * @param code_addr Unused.
* @param result Pointer to store the return value (required). * @param result Unused.
* @return Error code (if any) from the VM. * @return SP_ERROR_ABORTED.
*/ */
virtual int Execute(uint32_t code_addr, cell_t *result) =0; virtual int Execute(uint32_t code_addr, cell_t *result) =0;
@ -566,10 +774,10 @@ namespace SourcePawn
*/ */
virtual IPluginFunction *GetFunctionById(funcid_t func_id) =0; virtual IPluginFunction *GetFunctionById(funcid_t func_id) =0;
#if defined SOURCEMOD_BUILD
/** /**
* @brief Returns the identity token for this context. * @brief Returns the identity token for this context.
* Note: This is a helper function for native calls and the Handle System. *
* Note: This is a compatibility shim and is the same as GetKey(1).
* *
* @return Identity token. * @return Identity token.
*/ */
@ -592,7 +800,6 @@ namespace SourcePawn
* @param addr Destination output pointer. * @param addr Destination output pointer.
*/ */
virtual int LocalToStringNULL(cell_t local_addr, char **addr) =0; virtual int LocalToStringNULL(cell_t local_addr, char **addr) =0;
#endif
/** /**
* @brief Deprecated; do not use. * @brief Deprecated; do not use.
@ -608,6 +815,67 @@ namespace SourcePawn
* @return True if in exec, false otherwise. * @return True if in exec, false otherwise.
*/ */
virtual bool IsInExec() =0; virtual bool IsInExec() =0;
/**
* @brief Returns the parent runtime of a context.
*
* @return Parent runtime.
*/
virtual IPluginRuntime *GetRuntime() =0;
/**
* @brief Executes a function in the context. The function must be
* a member of the context's parent runtime.
*
* @param function Function.
* @param params Parameters.
* @param num_params Number of parameters in the parameter array.
* @param result Optional pointer to store the result on success.
* @return Error code.
*/
virtual int Execute2(IPluginFunction *function,
const cell_t *params,
unsigned int num_params,
cell_t *result) =0;
/**
* @brief Returns whether a context is in an error state.
*
* This should only be used inside natives to determine whether
* a prior call failed.
*/
virtual int GetLastNativeError() =0;
/**
* @brief Returns the local parameter stack, starting from the
* cell that contains the number of parameters passed.
*
* Local parameters are the parameters passed to the function
* from which a native was called (and thus this can only be
* called inside a native).
*
* @return Parameter stack.
*/
virtual cell_t *GetLocalParams() =0;
/**
* @brief Sets a local "key" that can be used for fast lookup.
*
* Only the "owner" of the context should be setting this.
*
* @param key Key number (values allowed: 1 through 4).
* @param value Pointer value.
*/
virtual void SetKey(int k, void *value) =0;
/**
* @brief Retrieves a previously set "key."
*
* @param key Key number (values allowed: 1 through 4).
* @param value Pointer to store value.
* @return True on success, false on failure.
*/
virtual bool GetKey(int k, void **value) =0;
}; };
@ -748,6 +1016,9 @@ namespace SourcePawn
virtual void OnCallbackEnd(int serial) =0; virtual void OnCallbackEnd(int serial) =0;
}; };
struct sp_plugin_s;
typedef struct sp_plugin_s sp_plugin_t;
/** /**
* @brief Contains helper functions used by VMs and the host app * @brief Contains helper functions used by VMs and the host app
*/ */
@ -755,30 +1026,29 @@ namespace SourcePawn
{ {
public: public:
/** /**
* @brief Loads a named file from a file pointer. * @brief Deprecated, do not use.
* Note: Using this means the memory will be allocated by the VM.
* *
* @param fp File pointer. May be at any offset. Not closed on return. * @param fp Unused.
* @param err Optional error code pointer. * @param err Unused.
* @return A new plugin structure. * @return NULL.
*/ */
virtual sp_plugin_t *LoadFromFilePointer(FILE *fp, int *err) =0; virtual sp_plugin_t *LoadFromFilePointer(FILE *fp, int *err) =0;
/** /**
* @brief Loads a file from a base memory address. * @brief Deprecated, do not use,
* *
* @param base Base address of the plugin's memory region. * @param base Unused.
* @param plugin If NULL, a new plugin pointer is returned. * @param plugin Unused.
* Otherwise, the passed pointer is used. * @param err Unused.
* @param err Optional error code pointer. * @return NULL.
* @return The resulting plugin pointer.
*/ */
virtual sp_plugin_t *LoadFromMemory(void *base, sp_plugin_t *plugin, int *err) =0; virtual sp_plugin_t *LoadFromMemory(void *base, sp_plugin_t *plugin, int *err) =0;
/** /**
* Frees all of the memory associated with a plugin file. * @brief Deprecated, do not use.
* If allocated using SP_LoadFromMemory, the base and plugin pointer *
* itself are not freed (so this may end up doing nothing). * @param plugin Unused.
* @return SP_ERROR_ABORTED.
*/ */
virtual int FreeFromMemory(sp_plugin_t *plugin) =0; virtual int FreeFromMemory(sp_plugin_t *plugin) =0;
@ -826,9 +1096,9 @@ namespace SourcePawn
virtual IDebugListener *SetDebugListener(IDebugListener *listener) =0; virtual IDebugListener *SetDebugListener(IDebugListener *listener) =0;
/** /**
* @brief Returns the number of plugins on the call stack. * @brief Deprecated, do not use.
* *
* @return Number of contexts in the call stack. * @return 0.
*/ */
virtual unsigned int GetContextCallCount() =0; virtual unsigned int GetContextCallCount() =0;
@ -869,103 +1139,23 @@ namespace SourcePawn
virtual void FreePageMemory(void *ptr) =0; virtual void FreePageMemory(void *ptr) =0;
}; };
/**
* @brief Dummy class for encapsulating private compilation data.
*/
class ICompilation
{
public:
/** Virtual destructor */
virtual ~ICompilation() { };
};
/** /**
* @brief Outlines the interface a Virtual Machine (JIT) must expose * @brief Outlines the interface a Virtual Machine (JIT) must expose
*/ */
class IVirtualMachine class ISourcePawnEngine2
{ {
public: public:
/** /**
* @brief Returns the current API version. * @brief Returns the second engine API version.
*
* @return API version.
*/ */
virtual unsigned int GetAPIVersion() =0; virtual unsigned int GetAPIVersion() =0;
/** /**
* @brief Returns the string name of a VM implementation. * @brief Returns the string name of a VM implementation.
*/ */
virtual const char *GetVMName() =0; virtual const char *GetEngineName() =0;
/**
* @brief Begins a new compilation
*
* @param plugin Pointer to a plugin structure.
* @return New compilation pointer.
*/
virtual ICompilation *StartCompilation(sp_plugin_t *plugin) =0;
/**
* @brief Sets a compilation option.
*
* @param co Pointer to a compilation.
* @param key Option key name.
* @param val Option value string.
* @return True if option could be set, false otherwise.
*/
virtual bool SetCompilationOption(ICompilation *co, const char *key, const char *val) =0;
/**
* @brief Finalizes a compilation into a new sp_context_t.
* Note: This will free the ICompilation pointer.
*
* @param co Compilation pointer.
* @param err Filled with error code on exit.
* @return New plugin context.
*/
virtual sp_context_t *CompileToContext(ICompilation *co, int *err) =0;
/**
* @brief Aborts a compilation and frees the ICompilation pointer.
*
* @param co Compilation pointer.
*/
virtual void AbortCompilation(ICompilation *co) =0;
/**
* @brief Frees any internal variable usage on a context.
*
* @param ctx Context structure pointer.
*/
virtual void FreeContext(sp_context_t *ctx) =0;
/**
* @brief Calls the "execute" function on a context.
*
* @param ctx Executes a function in a context.
* @param code_addr Index into the code section.
* @param result Pointer to store result into.
* @return Error code (if any).
*/
virtual int ContextExecute(sp_context_t *ctx, uint32_t code_addr, cell_t *result) =0;
/**
* @brief Given a context and a code address, returns the index of the function.
*
* @param ctx Context to search.
* @param code_addr Index into the code section.
* @param result Pointer to store result into.
* @return True if code index is valid, false otherwise.
*/
virtual bool FunctionLookup(const sp_context_t *ctx, uint32_t code_addr, unsigned int *result) =0;
/**
* @brief Returns the number of functions defined in the context.
*
* @param ctx Context to search.
* @return Number of functions.
*/
virtual unsigned int FunctionCount(const sp_context_t *ctx) =0;
/** /**
* @brief Returns a version string. * @brief Returns a version string.
@ -975,21 +1165,24 @@ namespace SourcePawn
virtual const char *GetVersionString() =0; virtual const char *GetVersionString() =0;
/** /**
* @brief Returns a string describing optimizations. * @brief Creates a new compilation options object.
* *
* @return String describing CPU specific optimizations. * @return Compilation options object.
*/ */
virtual const char *GetCPUOptimizations() =0; virtual ICompilation *StartCompilation() =0;
/** /**
* @brief Given a context and a p-code address, returns the index of the function. * @brief Loads a plugin from disk.
* *
* @param ctx Context to search. * If a compilation object is supplied, it is destroyed upon
* @param code_addr Index into the p-code section. * the function's return.
* @param result Pointer to store result into. *
* @return True if code index is valid, false otherwise. * @param co Compilation options, or NULL for defaults.
* @param file Path to the file to compile.
* @param err Error code (filled on failure); required.
* @return New runtime pointer, or NULL on failure.
*/ */
virtual bool FunctionPLookup(const sp_context_t *ctx, uint32_t code_addr, unsigned int *result) =0; virtual IPluginRuntime *LoadPlugin(ICompilation *co, const char *file, int *err) =0;
/** /**
* @brief Creates a fake native and binds it to a general callback function. * @brief Creates a fake native and binds it to a general callback function.
@ -1006,6 +1199,32 @@ namespace SourcePawn
* @param func Pointer to the fake native created by CreateFakeNative. * @param func Pointer to the fake native created by CreateFakeNative.
*/ */
virtual void DestroyFakeNative(SPVM_NATIVE_FUNC func) =0; virtual void DestroyFakeNative(SPVM_NATIVE_FUNC func) =0;
/**
* @brief Sets the debug listener. This should only be called once.
* If called successively (using manual chaining), only the last function should
* attempt to call back into the same plugin. Otherwise, globally cached states
* can be accidentally overwritten.
*
* @param listener Pointer to an IDebugListener.
* @return Old IDebugListener, or NULL if none.
*/
virtual IDebugListener *SetDebugListener(IDebugListener *listener) =0;
/**
* @brief Sets the global profiler.
*
* @param profiler Profiler pointer.
*/
virtual void SetProfiler(IProfiler *profiler) =0;
/**
* @brief Returns the string representation of an error message.
*
* @param err Error code.
* @return Error string, or NULL if not found.
*/
virtual const char *GetErrorString(int err) =0;
}; };
}; };

View File

@ -47,8 +47,5 @@
#define EXPORT_LINK extern "C" __attribute__((visibility("default"))) #define EXPORT_LINK extern "C" __attribute__((visibility("default")))
#endif #endif
/** No longer used */
typedef SourcePawn::IVirtualMachine *(*SP_GETVM_FUNC)(SourcePawn::ISourcePawnEngine *);
#endif //_INCLUDE_SOURCEPAWN_VM_BASE_H_ #endif //_INCLUDE_SOURCEPAWN_VM_BASE_H_

View File

@ -92,56 +92,6 @@ typedef uint32_t funcid_t; /**< Function index code */
*** binary. *** binary.
**********************************************/ **********************************************/
/**
* @brief Information about the core plugin tables. These may or may not be present!
*/
typedef struct sp_plugin_infotab_s
{
const char *stringbase; /**< base of string table */
uint32_t publics_num; /**< number of publics */
sp_file_publics_t *publics; /**< public table */
uint32_t natives_num; /**< number of natives */
sp_file_natives_t *natives; /**< native table */
uint32_t pubvars_num; /**< number of pubvars */
sp_file_pubvars_t *pubvars; /**< pubvars table */
} sp_plugin_infotab_t;
/**
* @brief Information about the plugin's debug tables. These are all present if one is present.
*/
typedef struct sp_plugin_debug_s
{
const char *stringbase; /**< base of string table */
uint32_t files_num; /**< number of files */
sp_fdbg_file_t *files; /**< files table */
uint32_t lines_num; /**< number of lines */
sp_fdbg_line_t *lines; /**< lines table */
uint32_t syms_num; /**< number of symbols */
sp_fdbg_symbol_t *symbols; /**< symbol table */
} sp_plugin_debug_t;
#define SP_FA_SELF_EXTERNAL (1<<0) /**< Allocation of structure is external */
#define SP_FA_BASE_EXTERNAL (1<<1) /**< Allocation of base is external */
/**
* @brief The rebased memory format of a plugin. This differs from the on-disk structure
* to ensure that the format is properly read.
*/
typedef struct sp_plugin_s
{
uint8_t *base; /**< Base of memory for this plugin. */
uint8_t *pcode; /**< P-Code of plugin */
uint32_t pcode_size; /**< Size of p-code */
uint8_t *data; /**< Data/memory layout */
uint32_t data_size; /**< Size of data */
uint32_t memory; /**< Required memory space */
uint16_t flags; /**< Code flags */
uint32_t allocflags; /**< Allocation flags */
sp_plugin_infotab_t info; /**< Base info table */
sp_plugin_debug_t debug; /**< Debug info table */
} sp_plugin_t;
namespace SourcePawn namespace SourcePawn
{ {
class IPluginContext; class IPluginContext;
@ -251,51 +201,7 @@ typedef struct sp_debug_symbol_s
sp_fdbg_symbol_t *sym; /**< Pointer to original symbol */ sp_fdbg_symbol_t *sym; /**< Pointer to original symbol */
} sp_debug_symbol_t; } sp_debug_symbol_t;
/** //#define SPFLAG_PLUGIN_DEBUG (1<<0) /**< plugin is in debug mode */
* Breaks into a debugger //#define SPFLAG_PLUGIN_PAUSED (1<<1) /**< plugin is "paused" (blocked from executing) */
* Params:
* [0] - plugin context
* [1] - frm
* [2] - cip
*/
typedef int (*SPVM_DEBUGBREAK)(struct sp_context_s *, uint32_t, uint32_t);
#define SPFLAG_PLUGIN_DEBUG (1<<0) /**< plugin is in debug mode */
#define SPFLAG_PLUGIN_PAUSED (1<<1) /**< plugin is "paused" (blocked from executing) */
/**
* @brief This is the heart of the VM. It contains all of the runtime
* information about a plugin context. Note that user[0..3] can be used for any user based pointers.
* However, vm[0..3] should not be touched, as it is reserved for the VM.
*/
typedef struct sp_context_s
{
void *codebase; /**< Base of generated code and memory */
sp_plugin_t *plugin; /**< Pointer back to parent information */
SourcePawn::IPluginContext *context; /**< Pointer to IPluginContext */
SourcePawn::IVirtualMachine *vmbase; /**< Pointer to IVirtualMachine */
void *user[4]; /**< User specific pointers */
void *vm[4]; /**< VM specific pointers */
uint32_t flags; /**< Compilation flags */
SPVM_DEBUGBREAK dbreak; /**< Debug break function */
uint8_t *memory; /**< Data chunk */
ucell_t mem_size; /**< Total memory size; */
cell_t data_size; /**< Data chunk size, always starts at 0 */
cell_t heap_base; /**< Where the heap starts */
cell_t hp; /**< Heap pointer */
cell_t sp; /**< Stack pointer */
cell_t frm; /**< Frame pointer */
uint32_t pushcount; /**< Push count */
int32_t n_err; /**< Error code set by a native */
uint32_t n_idx; /**< Current native index being executed */
sp_public_t *publics; /**< Public functions table */
sp_pubvar_t *pubvars; /**< Public variables table */
sp_native_t *natives; /**< Natives table */
sp_debug_file_t *files; /**< Files */
sp_debug_line_t *lines; /**< Lines */
sp_debug_symbol_t *symbols; /**< Symbols */
SourcePawn::IProfiler *profiler; /**< Pointer to IProfiler */
uint32_t prof_flags; /**< Profiling flags */
} sp_context_t;
#endif //_INCLUDE_SOURCEPAWN_VM_TYPES_H #endif //_INCLUDE_SOURCEPAWN_VM_TYPES_H

View File

@ -0,0 +1,357 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "BaseRuntime.h"
#include "sp_vm_engine.h"
#include "x86/jit_x86.h"
#include "sp_vm_basecontext.h"
#include "engine2.h"
using namespace SourcePawn;
int GlobalDebugBreak(BaseContext *ctx, uint32_t frm, uint32_t cip)
{
g_engine1.RunTracer(ctx, frm, cip);
return SP_ERROR_NONE;
}
BaseRuntime::BaseRuntime(sp_plugin_t *pl) : m_Debug(pl), m_pPlugin(pl)
{
m_pCtx = new BaseContext(this);
if (m_pPlugin->info.publics_num > 0)
{
m_PubFuncs = new CFunction *[m_pPlugin->info.publics_num];
memset(m_PubFuncs, 0, sizeof(CFunction *) * m_pPlugin->info.publics_num);
}
else
{
m_PubFuncs = NULL;
}
m_pPlugin->dbreak = GlobalDebugBreak;
m_pPlugin->profiler = g_engine2.GetProfiler();
}
BaseRuntime::~BaseRuntime()
{
for (uint32_t i = 0; i < m_pPlugin->info.publics_num; i++)
{
delete m_PubFuncs[i];
m_PubFuncs[i] = NULL;
}
delete [] m_PubFuncs;
ClearCompile();
free(m_pPlugin->base);
delete [] m_pPlugin->memory;
delete m_pPlugin;
}
void BaseRuntime::ClearCompile()
{
g_Jit1.FreeContextVars(m_pCtx->GetCtx());
g_Jit1.FreePluginVars(m_pPlugin);
}
int BaseRuntime::FindNativeByName(const char *name, uint32_t *index)
{
int high;
high = m_pPlugin->info.natives_num - 1;
for (uint32_t i=0; i<m_pPlugin->info.natives_num; i++)
{
if (strcmp(m_pPlugin->natives[i].name, name) == 0)
{
if (index)
{
*index = i;
}
return SP_ERROR_NONE;
}
}
return SP_ERROR_NOT_FOUND;
}
int BaseRuntime::GetNativeByIndex(uint32_t index, sp_native_t **native)
{
if (index >= m_pPlugin->info.natives_num)
{
return SP_ERROR_INDEX;
}
if (native)
{
*native = &(m_pPlugin->natives[index]);
}
return SP_ERROR_NONE;
}
uint32_t BaseRuntime::GetNativesNum()
{
return m_pPlugin->info.natives_num;
}
int BaseRuntime::FindPublicByName(const char *name, uint32_t *index)
{
int diff, high, low;
uint32_t mid;
high = m_pPlugin->info.publics_num - 1;
low = 0;
while (low <= high)
{
mid = (low + high) / 2;
diff = strcmp(m_pPlugin->publics[mid].name, name);
if (diff == 0)
{
if (index)
{
*index = mid;
}
return SP_ERROR_NONE;
} else if (diff < 0) {
low = mid + 1;
} else {
high = mid - 1;
}
}
return SP_ERROR_NOT_FOUND;
}
int BaseRuntime::GetPublicByIndex(uint32_t index, sp_public_t **pblic)
{
if (index >= m_pPlugin->info.publics_num)
{
return SP_ERROR_INDEX;
}
if (pblic)
{
*pblic = &(m_pPlugin->publics[index]);
}
return SP_ERROR_NONE;
}
uint32_t BaseRuntime::GetPublicsNum()
{
return m_pPlugin->info.publics_num;
}
int BaseRuntime::GetPubvarByIndex(uint32_t index, sp_pubvar_t **pubvar)
{
if (index >= m_pPlugin->info.pubvars_num)
{
return SP_ERROR_INDEX;
}
if (pubvar)
{
*pubvar = &(m_pPlugin->pubvars[index]);
}
return SP_ERROR_NONE;
}
int BaseRuntime::FindPubvarByName(const char *name, uint32_t *index)
{
int diff, high, low;
uint32_t mid;
high = m_pPlugin->info.pubvars_num - 1;
low = 0;
while (low <= high)
{
mid = (low + high) / 2;
diff = strcmp(m_pPlugin->pubvars[mid].name, name);
if (diff == 0)
{
if (index)
{
*index = mid;
}
return SP_ERROR_NONE;
} else if (diff < 0) {
low = mid + 1;
} else {
high = mid - 1;
}
}
return SP_ERROR_NOT_FOUND;
}
int BaseRuntime::GetPubvarAddrs(uint32_t index, cell_t *local_addr, cell_t **phys_addr)
{
if (index >= m_pPlugin->info.pubvars_num)
{
return SP_ERROR_INDEX;
}
*local_addr = m_pPlugin->info.pubvars[index].address;
*phys_addr = m_pPlugin->pubvars[index].offs;
return SP_ERROR_NONE;
}
uint32_t BaseRuntime::GetPubVarsNum()
{
return m_pPlugin->info.pubvars_num;
}
IPluginContext *BaseRuntime::GetDefaultContext()
{
return m_pCtx;
}
IPluginDebugInfo *BaseRuntime::GetDebugInfo()
{
if (!IsDebugging())
{
return NULL;
}
return &m_Debug;
}
void BaseRuntime::RefreshFunctionCache()
{
if (m_PubFuncs != NULL)
{
sp_public_t *pub;
for (uint32_t i = 0; i < m_pPlugin->info.publics_num; i++)
{
if (m_PubFuncs[i] == NULL)
{
continue;
}
if (GetPublicByIndex(i, &pub) != SP_ERROR_NONE)
{
continue;
}
m_PubFuncs[i]->Set(pub->code_offs, this, (i << 1) | 1, i);
}
}
}
IPluginFunction *BaseRuntime::GetFunctionById(funcid_t func_id)
{
CFunction *pFunc = NULL;
if (func_id & 1)
{
func_id >>= 1;
if (func_id >= m_pPlugin->info.publics_num)
{
return NULL;
}
pFunc = m_PubFuncs[func_id];
if (!pFunc)
{
m_PubFuncs[func_id] = new CFunction(m_pPlugin->publics[func_id].code_offs,
this,
(func_id << 1) | 1,
func_id);
pFunc = m_PubFuncs[func_id];
}
else if (pFunc->IsInvalidated())
{
pFunc->Set(m_pPlugin->publics[func_id].code_offs,
this,
(func_id << 1) | 1,
func_id);
}
}
return pFunc;
}
IPluginFunction *BaseRuntime::GetFunctionByName(const char *public_name)
{
uint32_t index;
if (FindPublicByName(public_name, &index) != SP_ERROR_NONE)
{
return NULL;
}
CFunction *pFunc = m_PubFuncs[index];
if (!pFunc)
{
sp_public_t *pub = NULL;
GetPublicByIndex(index, &pub);
if (pub)
{
m_PubFuncs[index] = new CFunction(pub->code_offs, this, (index << 1) | 1, index);
}
pFunc = m_PubFuncs[index];
}
else if (pFunc->IsInvalidated())
{
sp_public_t *pub = NULL;
GetPublicByIndex(index, &pub);
if (pub)
{
pFunc->Set(pub->code_offs, this, (index << 1) | 1, index);
}
else
{
pFunc = NULL;
}
}
return pFunc;
}
bool BaseRuntime::IsDebugging()
{
return ((m_pPlugin->run_flags & SPFLAG_PLUGIN_DEBUG) == SPFLAG_PLUGIN_DEBUG);
}
void BaseRuntime::SetPauseState(bool paused)
{
if (paused)
{
m_pPlugin->run_flags |= SPFLAG_PLUGIN_PAUSED;
}
else
{
m_pPlugin->run_flags &= ~SPFLAG_PLUGIN_PAUSED;
}
}
bool BaseRuntime::IsPaused()
{
return ((m_pPlugin->run_flags & SPFLAG_PLUGIN_PAUSED) == SPFLAG_PLUGIN_PAUSED);
}
size_t BaseRuntime::GetMemUsage()
{
size_t mem = 0;
mem += sizeof(this);
mem += sizeof(sp_plugin_t);
mem += sizeof(BaseContext);
mem += m_pPlugin->base_size;
mem += m_pPlugin->jit_codesize;
mem += m_pPlugin->jit_memsize;
return mem;
}
BaseContext *BaseRuntime::GetBaseContext()
{
return m_pCtx;
}

View File

@ -0,0 +1,60 @@
#ifndef _INCLUDE_SOURCEPAWN_JIT_RUNTIME_H_
#define _INCLUDE_SOURCEPAWN_JIT_RUNTIME_H_
#include <sp_vm_api.h>
#include "jit_shared.h"
#include "sp_vm_function.h"
class BaseContext;
class DebugInfo : public IPluginDebugInfo
{
public:
DebugInfo(sp_plugin_t *plugin);
public:
int LookupFile(ucell_t addr, const char **filename);
int LookupFunction(ucell_t addr, const char **name);
int LookupLine(ucell_t addr, uint32_t *line);
private:
sp_plugin_t *m_pPlugin;
};
/* Jit wants fast access to this so we expose things as public */
class BaseRuntime : public SourcePawn::IPluginRuntime
{
public:
BaseRuntime(sp_plugin_t *pl);
~BaseRuntime();
public:
virtual bool IsDebugging();
virtual IPluginDebugInfo *GetDebugInfo();
virtual int FindNativeByName(const char *name, uint32_t *index);
virtual int GetNativeByIndex(uint32_t index, sp_native_t **native);
virtual uint32_t GetNativesNum();
virtual int FindPublicByName(const char *name, uint32_t *index);
virtual int GetPublicByIndex(uint32_t index, sp_public_t **publicptr);
virtual uint32_t GetPublicsNum();
virtual int GetPubvarByIndex(uint32_t index, sp_pubvar_t **pubvar);
virtual int FindPubvarByName(const char *name, uint32_t *index);
virtual int GetPubvarAddrs(uint32_t index, cell_t *local_addr, cell_t **phys_addr);
virtual uint32_t GetPubVarsNum();
virtual IPluginFunction *GetFunctionByName(const char *public_name);
virtual IPluginFunction *GetFunctionById(funcid_t func_id);
virtual IPluginContext *GetDefaultContext();
virtual int ApplyCompilationOptions(ICompilation *co);
virtual void SetPauseState(bool paused);
virtual bool IsPaused();
virtual size_t GetMemUsage();
public:
BaseContext *GetBaseContext();
private:
void ClearCompile();
void RefreshFunctionCache();
public:
DebugInfo m_Debug;
sp_plugin_t *m_pPlugin;
BaseContext *m_pCtx;
CFunction **m_PubFuncs;
};
#endif //_INCLUDE_SOURCEPAWN_JIT_RUNTIME_H_

View File

@ -1,7 +1,8 @@
# (C)2004-2008 SourceMod Development Team # (C)2004-2008 SourceMod Development Team
# Makefile written by David "BAILOPAN" Anderson # Makefile written by David "BAILOPAN" Anderson
SMSDK = ../../.. SMSDK = ../..
SOURCEHOOK = ../../../sourcemm-1.6/sourcehook
##################################### #####################################
### EDIT BELOW FOR OTHER PROJECTS ### ### EDIT BELOW FOR OTHER PROJECTS ###
@ -9,7 +10,26 @@ SMSDK = ../../..
PROJECT = sourcepawn.jit.x86 PROJECT = sourcepawn.jit.x86
OBJECTS = dll_exports.cpp jit_x86.cpp opcode_helpers.cpp OBJECTS = dll_exports.cpp \
x86/jit_x86.cpp \
x86/opcode_helpers.cpp \
sp_vm_basecontext.cpp \
sp_vm_engine.cpp \
sp_vm_function.cpp \
engine2.cpp \
BaseRuntime.cpp \
zlib/adler32.c \
zlib/compress.c \
zlib/crc32.c \
zlib/deflate.c \
zlib/gzio.c \
zlib/infback.c \
zlib/inffast.c \
zlib/inflate.c \
zlib/inftrees.c \
zlib/trees.c \
zlib/uncompr.c \
zlib/zutil.c
############################################## ##############################################
### CONFIGURE ANY OTHER FLAGS/OPTIONS HERE ### ### CONFIGURE ANY OTHER FLAGS/OPTIONS HERE ###
@ -24,7 +44,7 @@ CPP = gcc-4.1
LINK = -static-libgcc LINK = -static-libgcc
INCLUDE = -I. -I.. -I$(SMSDK)/public -I$(SMSDK)/public/jit -I$(SMSDK)/public/jit/x86 \ INCLUDE = -I. -I.. -I$(SMSDK)/public -I$(SMSDK)/public/jit -I$(SMSDK)/public/jit/x86 \
-I$(SMSDK)/public/sourcepawn -I$(SMSDK)/public/sourcepawn -I$(SOURCEHOOK)
CFLAGS += -D_LINUX -Dstricmp=strcasecmp -D_stricmp=strcasecmp -D_strnicmp=strncasecmp -Dstrnicmp=strncasecmp \ CFLAGS += -D_LINUX -Dstricmp=strcasecmp -D_stricmp=strcasecmp -D_strnicmp=strncasecmp -Dstrnicmp=strncasecmp \
-D_snprintf=snprintf -D_vsnprintf=vsnprintf -D_alloca=alloca -Dstrcmpi=strcasecmp -Wall -DHAVE_STDINT_H \ -D_snprintf=snprintf -D_vsnprintf=vsnprintf -D_alloca=alloca -Dstrcmpi=strcasecmp -Wall -DHAVE_STDINT_H \
@ -52,12 +72,17 @@ endif
BINARY = $(PROJECT).so BINARY = $(PROJECT).so
OBJ_LINUX := $(OBJECTS:%.cpp=$(BIN_DIR)/%.o) OBJ_LINUX := $(OBJECTS:%.cpp=$(BIN_DIR)/%.o)
OBJ_LINUX := $(OBJ_LINUX:%.c=$(BIN_DIR)/%.o)
$(BIN_DIR)/%.o: %.c
$(CPP) $(INCLUDE) $(CFLAGS) -o $@ -c $<
$(BIN_DIR)/%.o: %.cpp $(BIN_DIR)/%.o: %.cpp
$(CPP) $(INCLUDE) $(CFLAGS) $(CPPFLAGS) -o $@ -c $< $(CPP) $(INCLUDE) $(CFLAGS) $(CPPFLAGS) -o $@ -c $<
all: all:
mkdir -p $(BIN_DIR) mkdir -p $(BIN_DIR)/x86
mkdir -p $(BIN_DIR)/zlib
$(MAKE) -f Makefile jit $(MAKE) -f Makefile jit
jit: $(OBJ_LINUX) jit: $(OBJ_LINUX)

View File

@ -31,44 +31,21 @@
#include <sp_vm_api.h> #include <sp_vm_api.h>
#include <malloc.h> #include <malloc.h>
#include "jit_x86.h" #include "x86/jit_x86.h"
#include "dll_exports.h" #include "dll_exports.h"
#include "sp_vm_engine.h"
#include "engine2.h"
SourcePawn::ISourcePawnEngine *engine = NULL; SourcePawnEngine2 g_engine2;
JITX86 g_jit;
EXPORTFUNC int GiveEnginePointer2(SourcePawn::ISourcePawnEngine *engine_p, unsigned int api_version) EXPORTFUNC ISourcePawnEngine *GetSourcePawnEngine1()
{ {
engine = engine_p; return &g_engine1;
if (api_version > SOURCEPAWN_ENGINE_API_VERSION || api_version < 2)
{
return SP_ERROR_PARAM;
}
return SP_ERROR_NONE;
} }
EXPORTFUNC unsigned int GetExportCount() EXPORTFUNC ISourcePawnEngine2 *GetSourcePawnEngine2()
{ {
return 1; return &g_engine2;
}
EXPORTFUNC SourcePawn::IVirtualMachine *GetExport(unsigned int exportnum)
{
/* Don't return anything if we're not initialized yet */
if (!engine)
{
return NULL;
}
/* We only have one export - 0 */
if (exportnum)
{
return NULL;
}
return &g_jit;
} }
#if defined __linux__ #if defined __linux__

278
sourcepawn/jit/engine2.cpp Normal file
View File

@ -0,0 +1,278 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "engine2.h"
#include "x86/jit_x86.h"
#include "jit_version.h"
#include "zlib/zlib.h"
#include "BaseRuntime.h"
#include "sp_vm_engine.h"
using namespace SourcePawn;
SourcePawnEngine2::SourcePawnEngine2()
{
m_Profiler = NULL;
}
sp_plugin_t *_ReadPlugin(sp_file_hdr_t *hdr, uint8_t *base, sp_plugin_t *plugin, int *err)
{
char *nameptr;
uint8_t sectnum = 0;
sp_file_section_t *secptr = (sp_file_section_t *)(base + sizeof(sp_file_hdr_t));
memset(plugin, 0, sizeof(sp_plugin_t));
plugin->base = base;
while (sectnum < hdr->sections)
{
nameptr = (char *)(base + hdr->stringtab + secptr->nameoffs);
if (!(plugin->pcode) && !strcmp(nameptr, ".code"))
{
sp_file_code_t *cod = (sp_file_code_t *)(base + secptr->dataoffs);
plugin->pcode = base + secptr->dataoffs + cod->code;
plugin->pcode_size = cod->codesize;
plugin->flags = cod->flags;
}
else if (!(plugin->data) && !strcmp(nameptr, ".data"))
{
sp_file_data_t *dat = (sp_file_data_t *)(base + secptr->dataoffs);
plugin->data = base + secptr->dataoffs + dat->data;
plugin->data_size = dat->datasize;
plugin->mem_size = dat->memsize;
plugin->memory = new uint8_t[plugin->mem_size];
memcpy(plugin->memory, plugin->data, plugin->data_size);
}
else if (!(plugin->info.publics) && !strcmp(nameptr, ".publics"))
{
plugin->info.publics_num = secptr->size / sizeof(sp_file_publics_t);
plugin->info.publics = (sp_file_publics_t *)(base + secptr->dataoffs);
}
else if (!(plugin->info.pubvars) && !strcmp(nameptr, ".pubvars"))
{
plugin->info.pubvars_num = secptr->size / sizeof(sp_file_pubvars_t);
plugin->info.pubvars = (sp_file_pubvars_t *)(base + secptr->dataoffs);
}
else if (!(plugin->info.natives) && !strcmp(nameptr, ".natives"))
{
plugin->info.natives_num = secptr->size / sizeof(sp_file_natives_t);
plugin->info.natives = (sp_file_natives_t *)(base + secptr->dataoffs);
}
else if (!(plugin->info.stringbase) && !strcmp(nameptr, ".names"))
{
plugin->info.stringbase = (const char *)(base + secptr->dataoffs);
}
else if (!(plugin->debug.files) && !strcmp(nameptr, ".dbg.files"))
{
plugin->debug.files = (sp_fdbg_file_t *)(base + secptr->dataoffs);
}
else if (!(plugin->debug.lines) && !strcmp(nameptr, ".dbg.lines"))
{
plugin->debug.lines = (sp_fdbg_line_t *)(base + secptr->dataoffs);
}
else if (!(plugin->debug.symbols) && !strcmp(nameptr, ".dbg.symbols"))
{
plugin->debug.symbols = (sp_fdbg_symbol_t *)(base + secptr->dataoffs);
}
else if (!(plugin->debug.lines_num) && !strcmp(nameptr, ".dbg.info"))
{
sp_fdbg_info_t *inf = (sp_fdbg_info_t *)(base + secptr->dataoffs);
plugin->debug.files_num = inf->num_files;
plugin->debug.lines_num = inf->num_lines;
plugin->debug.syms_num = inf->num_syms;
}
else if (!(plugin->debug.stringbase) && !strcmp(nameptr, ".dbg.strings"))
{
plugin->debug.stringbase = (const char *)(base + secptr->dataoffs);
}
secptr++;
sectnum++;
}
if (!(plugin->pcode) || !(plugin->data) || !(plugin->info.stringbase))
{
goto return_error;
}
if ((plugin->flags & SP_FLAG_DEBUG) && (!(plugin->debug.files) || !(plugin->debug.lines) || !(plugin->debug.symbols)))
{
goto return_error;
}
if (err)
{
*err = SP_ERROR_NONE;
}
return plugin;
return_error:
if (err)
{
*err = SP_ERROR_FILE_FORMAT;
}
return NULL;
}
IPluginRuntime *SourcePawnEngine2::LoadPlugin(ICompilation *co, const char *file, int *err)
{
sp_file_hdr_t hdr;
sp_plugin_t *plugin;
uint8_t *base;
int z_result;
int error;
BaseRuntime *pRuntime;
FILE *fp = fopen(file, "rb");
if (!fp)
{
error = SP_ERROR_NOT_FOUND;
goto return_error;
}
/* Rewind for safety */
fread(&hdr, sizeof(sp_file_hdr_t), 1, fp);
if (hdr.magic != SPFILE_MAGIC)
{
error = SP_ERROR_FILE_FORMAT;
goto return_error;
}
switch (hdr.compression)
{
case SPFILE_COMPRESSION_GZ:
{
uint32_t uncompsize = hdr.imagesize - hdr.dataoffs;
uint32_t compsize = hdr.disksize - hdr.dataoffs;
uint32_t sectsize = hdr.dataoffs - sizeof(sp_file_hdr_t);
uLongf destlen = uncompsize;
char *tempbuf = (char *)malloc(compsize);
void *uncompdata = malloc(uncompsize);
void *sectheader = malloc(sectsize);
fread(sectheader, sectsize, 1, fp);
fread(tempbuf, compsize, 1, fp);
z_result = uncompress((Bytef *)uncompdata, &destlen, (Bytef *)tempbuf, compsize);
free(tempbuf);
if (z_result != Z_OK)
{
free(sectheader);
free(uncompdata);
error = SP_ERROR_DECOMPRESSOR;
goto return_error;
}
base = (uint8_t *)malloc(hdr.imagesize);
memcpy(base, &hdr, sizeof(sp_file_hdr_t));
memcpy(base + sizeof(sp_file_hdr_t), sectheader, sectsize);
free(sectheader);
memcpy(base + hdr.dataoffs, uncompdata, uncompsize);
free(uncompdata);
break;
}
case SPFILE_COMPRESSION_NONE:
{
base = (uint8_t *)malloc(hdr.imagesize);
rewind(fp);
fread(base, hdr.imagesize, 1, fp);
break;
}
default:
{
error = SP_ERROR_DECOMPRESSOR;
goto return_error;
}
}
plugin = new sp_plugin_t;
memset(plugin, 0, sizeof(sp_plugin_t));
plugin->base_size = hdr.imagesize;
if (!_ReadPlugin(&hdr, base, plugin, err))
{
delete plugin;
free(base);
return NULL;
}
pRuntime = new BaseRuntime(plugin);
if (co == NULL)
{
co = g_Jit1.StartCompilation(pRuntime);
}
*err = pRuntime->ApplyCompilationOptions(co);
if (*err != SP_ERROR_NONE)
{
delete pRuntime;
return NULL;
}
return pRuntime;
return_error:
*err = error;
return NULL;
}
SPVM_NATIVE_FUNC SourcePawnEngine2::CreateFakeNative(SPVM_FAKENATIVE_FUNC callback, void *pData)
{
return g_Jit1.CreateFakeNative(callback, pData);
}
void SourcePawnEngine2::DestroyFakeNative(SPVM_NATIVE_FUNC func)
{
g_Jit1.DestroyFakeNative(func);
}
const char *SourcePawnEngine2::GetEngineName()
{
return "SourcePawn 1.1, jit-x86";
}
const char *SourcePawnEngine2::GetVersionString()
{
return SVN_FULL_VERSION;
}
IProfiler *SourcePawnEngine2::GetProfiler()
{
return m_Profiler;
}
void SourcePawnEngine2::SetProfiler(IProfiler *profiler)
{
m_Profiler = profiler;
}
IDebugListener *SourcePawnEngine2::SetDebugListener(IDebugListener *listener)
{
return g_engine1.SetDebugListener(listener);
}
unsigned int SourcePawnEngine2::GetAPIVersion()
{
return SOURCEPAWN_ENGINE2_API_VERSION;
}
ICompilation *SourcePawnEngine2::StartCompilation()
{
return g_Jit1.StartCompilation();
}
const char *SourcePawnEngine2::GetErrorString(int err)
{
return g_engine1.GetErrorString(err);
}

35
sourcepawn/jit/engine2.h Normal file
View File

@ -0,0 +1,35 @@
#ifndef _INCLUDE_SOURCEPAWN_ENGINE_2_H_
#define _INCLUDE_SOURCEPAWN_ENGINE_2_H_
#include <sp_vm_api.h>
namespace SourcePawn
{
/**
* @brief Outlines the interface a Virtual Machine (JIT) must expose
*/
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);
void SetProfiler(IProfiler *profiler);
ICompilation *StartCompilation();
const char *GetErrorString(int err);
public:
IProfiler *GetProfiler();
private:
IProfiler *m_Profiler;
};
}
extern SourcePawn::SourcePawnEngine2 g_engine2;
#endif //_INCLUDE_SOURCEPAWN_ENGINE_2_H_

View File

@ -0,0 +1,95 @@
#ifndef _INCLUDE_SOURCEPAWN_JIT_SHARED_H_
#define _INCLUDE_SOURCEPAWN_JIT_SHARED_H_
#include <sp_vm_api.h>
using namespace SourcePawn;
/**
* @brief Information about the core plugin tables. These may or may not be present!
*/
typedef struct sp_plugin_infotab_s
{
const char *stringbase; /**< base of string table */
uint32_t publics_num; /**< number of publics */
sp_file_publics_t *publics; /**< public table */
uint32_t natives_num; /**< number of natives */
sp_file_natives_t *natives; /**< native table */
uint32_t pubvars_num; /**< number of pubvars */
sp_file_pubvars_t *pubvars; /**< pubvars table */
} sp_plugin_infotab_t;
/**
* @brief Information about the plugin's debug tables. These are all present if one is present.
*/
typedef struct sp_plugin_debug_s
{
const char *stringbase; /**< base of string table */
uint32_t files_num; /**< number of files */
sp_fdbg_file_t *files; /**< files table */
uint32_t lines_num; /**< number of lines */
sp_fdbg_line_t *lines; /**< lines table */
uint32_t syms_num; /**< number of symbols */
sp_fdbg_symbol_t *symbols; /**< symbol table */
} sp_plugin_debug_t;
class BaseContext;
/**
* Breaks into a debugger
* Params:
* [0] - plugin context
* [1] - frm
* [2] - cip
*/
typedef int (*SPVM_DEBUGBREAK)(BaseContext *, uint32_t, uint32_t);
/**
* @brief The rebased memory format of a plugin. This differs from the on-disk structure
* to ensure that the format is properly read.
*/
namespace SourcePawn
{
typedef struct sp_plugin_s
{
uint8_t *base; /**< Base of memory for this plugin. */
uint8_t *pcode; /**< P-Code of plugin */
uint32_t pcode_size; /**< Size of p-code */
uint8_t *data; /**< Data/memory layout */
uint32_t data_size; /**< Size of data */
uint32_t mem_size; /**< Required memory space */
uint16_t flags; /**< Code flags */
sp_plugin_infotab_t info; /**< Base info table */
sp_plugin_debug_t debug; /**< Debug info table */
size_t base_size; /**< Size of the entire plugin base */
void *codebase; /**< Base of generated code and memory */
SPVM_DEBUGBREAK dbreak; /**< Debug break function */
uint8_t *memory; /**< Data chunk */
sp_public_t *publics; /**< Public functions table */
sp_pubvar_t *pubvars; /**< Public variables table */
sp_native_t *natives; /**< Natives table */
sp_debug_file_t *files; /**< Files */
sp_debug_line_t *lines; /**< Lines */
sp_debug_symbol_t *symbols; /**< Symbols */
IProfiler *profiler; /**< Pointer to IProfiler */
uint32_t prof_flags; /**< Profiling flags */
uint32_t run_flags; /**< Runtime flags */
size_t jit_codesize; /**< JIT compiled codesize */
size_t jit_memsize; /**< JIT additional memory */
} sp_plugin_t;
}
typedef struct sp_context_s
{
cell_t hp; /**< Heap pointer */
cell_t sp; /**< Stack pointer */
cell_t frm; /**< Frame pointer */
int32_t n_err; /**< Error code set by a native */
uint32_t n_idx; /**< Current native index being executed */
void * vm[8]; /**< VM-specific pointers */
} sp_context_t;
#define SPFLAG_PLUGIN_DEBUG (1<<0)
#define SPFLAG_PLUGIN_PAUSED (1<<1)
#endif //_INCLUDE_SOURCEPAWN_JIT_SHARED_H_

View File

@ -40,7 +40,7 @@
<Tool <Tool
Name="VCCLCompilerTool" Name="VCCLCompilerTool"
Optimization="0" Optimization="0"
AdditionalIncludeDirectories="..\..\..\..\public\jit;..\..\..\..\public\jit\x86;..\..\..\..\public\sourcepawn" AdditionalIncludeDirectories="..\..\..\public\jit;..\..\..\public\jit\x86;..\..\..\public\sourcepawn"
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;JITX86_EXPORTS;_CRT_SECURE_NO_DEPRECATE" PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;JITX86_EXPORTS;_CRT_SECURE_NO_DEPRECATE"
MinimalRebuild="true" MinimalRebuild="true"
BasicRuntimeChecks="3" BasicRuntimeChecks="3"
@ -185,24 +185,44 @@
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
> >
<File
RelativePath="..\BaseRuntime.cpp"
>
</File>
<File <File
RelativePath="..\dll_exports.cpp" RelativePath="..\dll_exports.cpp"
> >
</File>
<File
RelativePath="..\engine2.cpp"
>
</File>
<File
RelativePath="..\x86\jit_x86.cpp"
>
</File>
<File
RelativePath="..\x86\opcode_helpers.cpp"
>
</File>
<File
RelativePath="..\sp_vm_basecontext.cpp"
>
</File>
<File
RelativePath="..\sp_vm_engine.cpp"
>
<FileConfiguration <FileConfiguration
Name="Debug|Win32" Name="Debug|Win32"
> >
<Tool <Tool
Name="VCCLCompilerTool" Name="VCCLCompilerTool"
AdditionalIncludeDirectories="" AdditionalIncludeDirectories="&quot;$(SOURCEMM16)\sourcehook&quot;"
/> />
</FileConfiguration> </FileConfiguration>
</File> </File>
<File <File
RelativePath="..\jit_x86.cpp" RelativePath="..\sp_vm_function.cpp"
>
</File>
<File
RelativePath="..\opcode_helpers.cpp"
> >
</File> </File>
</Filter> </Filter>
@ -211,12 +231,20 @@
Filter="h;hpp;hxx;hm;inl;inc;xsd" Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
> >
<File
RelativePath="..\BaseRuntime.h"
>
</File>
<File <File
RelativePath="..\dll_exports.h" RelativePath="..\dll_exports.h"
> >
</File> </File>
<File <File
RelativePath="..\..\..\..\public\jit\jit_helpers.h" RelativePath="..\engine2.h"
>
</File>
<File
RelativePath="..\jit_shared.h"
> >
</File> </File>
<File <File
@ -224,19 +252,23 @@
> >
</File> </File>
<File <File
RelativePath="..\jit_x86.h" RelativePath="..\x86\jit_x86.h"
> >
</File> </File>
<File <File
RelativePath="..\opcode_helpers.h" RelativePath="..\x86\opcode_helpers.h"
> >
</File> </File>
<File <File
RelativePath="..\ungen_opcodes.h" RelativePath="..\sp_vm_basecontext.h"
> >
</File> </File>
<File <File
RelativePath="..\..\..\..\public\jit\x86\x86_macros.h" RelativePath="..\sp_vm_engine.h"
>
</File>
<File
RelativePath="..\sp_vm_function.h"
> >
</File> </File>
</Filter> </Filter>
@ -245,18 +277,6 @@
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav" 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}" UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
> >
<File
RelativePath="..\jit_version.tpl"
>
</File>
<File
RelativePath="..\opcode_switch.inc"
>
</File>
<File
RelativePath="..\ungen_opcode_switch.inc"
>
</File>
<File <File
RelativePath="..\version.rc" RelativePath="..\version.rc"
> >
@ -266,27 +286,75 @@
Name="SDK" Name="SDK"
> >
<File <File
RelativePath="..\..\jit_helpers.h" RelativePath="..\..\..\public\sourcepawn\sp_file_headers.h"
> >
</File> </File>
<File <File
RelativePath="..\..\..\..\public\sourcepawn\sp_file_headers.h" RelativePath="..\..\..\public\sourcepawn\sp_typeutil.h"
> >
</File> </File>
<File <File
RelativePath="..\..\..\..\public\sourcepawn\sp_typeutil.h" RelativePath="..\..\..\public\sourcepawn\sp_vm_api.h"
> >
</File> </File>
<File <File
RelativePath="..\..\..\..\public\sourcepawn\sp_vm_api.h" RelativePath="..\..\..\public\sourcepawn\sp_vm_base.h"
> >
</File> </File>
<File <File
RelativePath="..\..\..\..\public\sourcepawn\sp_vm_base.h" RelativePath="..\..\..\public\sourcepawn\sp_vm_types.h"
>
</File>
</Filter>
<Filter
Name="zlib"
>
<File
RelativePath="..\zlib\adler32.c"
> >
</File> </File>
<File <File
RelativePath="..\..\..\..\public\sourcepawn\sp_vm_types.h" RelativePath="..\zlib\compress.c"
>
</File>
<File
RelativePath="..\zlib\crc32.c"
>
</File>
<File
RelativePath="..\zlib\deflate.c"
>
</File>
<File
RelativePath="..\zlib\gzio.c"
>
</File>
<File
RelativePath="..\zlib\infback.c"
>
</File>
<File
RelativePath="..\zlib\inffast.c"
>
</File>
<File
RelativePath="..\zlib\inflate.c"
>
</File>
<File
RelativePath="..\zlib\inftrees.c"
>
</File>
<File
RelativePath="..\zlib\trees.c"
>
</File>
<File
RelativePath="..\zlib\uncompr.c"
>
</File>
<File
RelativePath="..\zlib\zutil.c"
> >
</File> </File>
</Filter> </Filter>

View File

@ -0,0 +1,810 @@
/**
* vim: set ts=4 :
* =============================================================================
* SourcePawn
* Copyright (C) 2004-2008 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 <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 <string.h>
#include <stdarg.h>
#include <assert.h>
#include <limits.h>
#include "sp_vm_api.h"
#include "sp_vm_basecontext.h"
#include "sp_vm_engine.h"
#include "x86/jit_x86.h"
using namespace SourcePawn;
#define CELLBOUNDMAX (INT_MAX/sizeof(cell_t))
#define STACKMARGIN ((cell_t)(16*sizeof(cell_t)))
BaseContext::BaseContext(BaseRuntime *pRuntime)
{
m_pRuntime = pRuntime;
m_pPlugin = m_pRuntime->m_pPlugin;
m_InExec = false;
m_CustomMsg = false;
m_pNullVec = NULL;
m_pNullString = NULL;
}
BaseContext::~BaseContext()
{
}
IVirtualMachine *BaseContext::GetVirtualMachine()
{
return NULL;
}
sp_context_t *BaseContext::GetContext()
{
return reinterpret_cast<sp_context_t *>((IPluginContext * )this);
}
sp_context_t *BaseContext::GetCtx()
{
return &m_ctx;
}
bool BaseContext::IsDebugging()
{
return m_pRuntime->IsDebugging();
}
int BaseContext::SetDebugBreak(void *newpfn, void *oldpfn)
{
return SP_ERROR_ABORTED;
}
IPluginDebugInfo *BaseContext::GetDebugInfo()
{
return NULL;
}
int BaseContext::Execute(uint32_t code_addr, cell_t *result)
{
return SP_ERROR_ABORTED;
}
void BaseContext::SetErrorMessage(const char *msg, va_list ap)
{
m_CustomMsg = true;
vsnprintf(m_MsgCache, sizeof(m_MsgCache), msg, ap);
}
void BaseContext::_SetErrorMessage(const char *msg, ...)
{
va_list ap;
va_start(ap, msg);
SetErrorMessage(msg, ap);
va_end(ap);
}
cell_t BaseContext::ThrowNativeErrorEx(int error, const char *msg, ...)
{
if (!m_InExec)
{
return 0;
}
m_ctx.n_err = error;
if (msg)
{
va_list ap;
va_start(ap, msg);
SetErrorMessage(msg, ap);
va_end(ap);
}
return 0;
}
cell_t BaseContext::ThrowNativeError(const char *msg, ...)
{
if (!m_InExec)
{
return 0;
}
m_ctx.n_err = SP_ERROR_NATIVE;
if (msg)
{
va_list ap;
va_start(ap, msg);
SetErrorMessage(msg, ap);
va_end(ap);
}
return 0;
}
int BaseContext::HeapAlloc(unsigned int cells, cell_t *local_addr, cell_t **phys_addr)
{
cell_t *addr;
ucell_t realmem;
#if 0
if (cells > CELLBOUNDMAX)
{
return SP_ERROR_ARAM;
}
#else
assert(cells < CELLBOUNDMAX);
#endif
realmem = cells * sizeof(cell_t);
/**
* Check if the space between the heap and stack is sufficient.
*/
if ((cell_t)(m_ctx.sp - m_ctx.hp - realmem) < STACKMARGIN)
{
return SP_ERROR_HEAPLOW;
}
addr = (cell_t *)(m_pPlugin->memory + m_ctx.hp);
/* store size of allocation in cells */
*addr = (cell_t)cells;
addr++;
m_ctx.hp += sizeof(cell_t);
*local_addr = m_ctx.hp;
if (phys_addr)
{
*phys_addr = addr;
}
m_ctx.hp += realmem;
return SP_ERROR_NONE;
}
int BaseContext::HeapPop(cell_t local_addr)
{
cell_t cellcount;
cell_t *addr;
/* check the bounds of this address */
local_addr -= sizeof(cell_t);
if (local_addr < (cell_t)m_pPlugin->data_size || local_addr >= m_ctx.sp)
{
return SP_ERROR_INVALID_ADDRESS;
}
addr = (cell_t *)(m_pPlugin->memory + local_addr);
cellcount = (*addr) * sizeof(cell_t);
/* check if this memory count looks valid */
if ((signed)(m_ctx.hp - cellcount - sizeof(cell_t)) != local_addr)
{
return SP_ERROR_INVALID_ADDRESS;
}
m_ctx.hp = local_addr;
return SP_ERROR_NONE;
}
int BaseContext::HeapRelease(cell_t local_addr)
{
if (local_addr < (cell_t)m_pPlugin->data_size)
{
return SP_ERROR_INVALID_ADDRESS;
}
m_ctx.hp = local_addr - sizeof(cell_t);
return SP_ERROR_NONE;
}
int BaseContext::FindNativeByName(const char *name, uint32_t *index)
{
return m_pRuntime->FindNativeByName(name, index);
}
int BaseContext::GetNativeByIndex(uint32_t index, sp_native_t **native)
{
return m_pRuntime->GetNativeByIndex(index, native);
}
uint32_t BaseContext::GetNativesNum()
{
return m_pRuntime->GetNativesNum();
}
int BaseContext::FindPublicByName(const char *name, uint32_t *index)
{
return m_pRuntime->FindPublicByName(name, index);
}
int BaseContext::GetPublicByIndex(uint32_t index, sp_public_t **pblic)
{
return m_pRuntime->GetPublicByIndex(index, pblic);
}
uint32_t BaseContext::GetPublicsNum()
{
return m_pRuntime->GetPublicsNum();
}
int BaseContext::GetPubvarByIndex(uint32_t index, sp_pubvar_t **pubvar)
{
return m_pRuntime->GetPubvarByIndex(index, pubvar);
}
int BaseContext::FindPubvarByName(const char *name, uint32_t *index)
{
return m_pRuntime->FindPubvarByName(name, index);
}
int BaseContext::GetPubvarAddrs(uint32_t index, cell_t *local_addr, cell_t **phys_addr)
{
return m_pRuntime->GetPubvarAddrs(index, local_addr, phys_addr);
}
uint32_t BaseContext::GetPubVarsNum()
{
return m_pRuntime->GetPubVarsNum();
}
int BaseContext::BindNatives(const sp_nativeinfo_t *natives, unsigned int num, int overwrite)
{
return SP_ERROR_ABORTED;
}
int BaseContext::BindNative(const sp_nativeinfo_t *native)
{
return SP_ERROR_ABORTED;
}
int BaseContext::BindNativeToIndex(uint32_t index, SPVM_NATIVE_FUNC func)
{
return SP_ERROR_ABORTED;
}
int BaseContext::BindNativeToAny(SPVM_NATIVE_FUNC native)
{
return SP_ERROR_ABORTED;
}
int BaseContext::LocalToPhysAddr(cell_t local_addr, cell_t **phys_addr)
{
if (((local_addr >= m_ctx.hp) && (local_addr < m_ctx.sp))
|| (local_addr < 0) || ((ucell_t)local_addr >= m_pPlugin->mem_size))
{
return SP_ERROR_INVALID_ADDRESS;
}
if (phys_addr)
{
*phys_addr = (cell_t *)(m_pPlugin->memory + local_addr);
}
return SP_ERROR_NONE;
}
int BaseContext::PushCell(cell_t value)
{
return SP_ERROR_ABORTED;
}
int BaseContext::PushCellsFromArray(cell_t array[], unsigned int numcells)
{
return SP_ERROR_ABORTED;
}
int BaseContext::PushCellArray(cell_t *local_addr, cell_t **phys_addr, cell_t array[], unsigned int numcells)
{
return SP_ERROR_ABORTED;
}
int BaseContext::LocalToString(cell_t local_addr, char **addr)
{
if (((local_addr >= m_ctx.hp) && (local_addr < m_ctx.sp))
|| (local_addr < 0) || ((ucell_t)local_addr >= m_pPlugin->mem_size))
{
return SP_ERROR_INVALID_ADDRESS;
}
*addr = (char *)(m_pPlugin->memory + local_addr);
return SP_ERROR_NONE;
}
int BaseContext::PushString(cell_t *local_addr, char **phys_addr, const char *string)
{
return SP_ERROR_ABORTED;
}
int BaseContext::StringToLocal(cell_t local_addr, size_t bytes, const char *source)
{
char *dest;
size_t len;
if (((local_addr >= m_ctx.hp) && (local_addr < m_ctx.sp))
|| (local_addr < 0) || ((ucell_t)local_addr >= m_pPlugin->mem_size))
{
return SP_ERROR_INVALID_ADDRESS;
}
if (bytes == 0)
{
return SP_ERROR_NONE;
}
len = strlen(source);
dest = (char *)(m_pPlugin->memory + local_addr);
if (len >= bytes)
{
len = bytes - 1;
}
memmove(dest, source, len);
dest[len] = '\0';
return SP_ERROR_NONE;
}
inline int __CheckValidChar(char *c)
{
int count;
int bytecount = 0;
for (count=1; (*c & 0xC0) == 0x80; count++)
{
c--;
}
switch (*c & 0xF0)
{
case 0xC0:
case 0xD0:
{
bytecount = 2;
break;
}
case 0xE0:
{
bytecount = 3;
break;
}
case 0xF0:
{
bytecount = 4;
break;
}
}
if (bytecount != count)
{
return count;
}
return 0;
}
int BaseContext::StringToLocalUTF8(cell_t local_addr, size_t maxbytes, const char *source, size_t *wrtnbytes)
{
char *dest;
size_t len;
bool needtocheck = false;
if (((local_addr >= m_ctx.hp) && (local_addr < m_ctx.sp))
|| (local_addr < 0)
|| ((ucell_t)local_addr >= m_pPlugin->mem_size))
{
return SP_ERROR_INVALID_ADDRESS;
}
if (maxbytes == 0)
{
return SP_ERROR_NONE;
}
len = strlen(source);
dest = (char *)(m_pPlugin->memory + local_addr);
if ((size_t)len >= maxbytes)
{
len = maxbytes - 1;
needtocheck = true;
}
memmove(dest, source, len);
if ((dest[len-1] & 1<<7) && needtocheck)
{
len -= __CheckValidChar(dest+len-1);
}
dest[len] = '\0';
if (wrtnbytes)
{
*wrtnbytes = len;
}
return SP_ERROR_NONE;
}
IPluginFunction *BaseContext::GetFunctionById(funcid_t func_id)
{
return m_pRuntime->GetFunctionById(func_id);
}
IPluginFunction *BaseContext::GetFunctionByName(const char *public_name)
{
return m_pRuntime->GetFunctionByName(public_name);
}
int BaseContext::LocalToStringNULL(cell_t local_addr, char **addr)
{
int err;
if ((err = LocalToString(local_addr, addr)) != SP_ERROR_NONE)
{
return err;
}
if ((cell_t *)*addr == m_pNullString)
{
*addr = NULL;
}
return SP_ERROR_NONE;
}
SourceMod::IdentityToken_t *BaseContext::GetIdentity()
{
SourceMod::IdentityToken_t *tok;
if (GetKey(1, (void **)&tok))
{
return tok;
}
return NULL;
}
cell_t *BaseContext::GetNullRef(SP_NULL_TYPE type)
{
if (type == SP_NULL_VECTOR)
{
return m_pNullVec;
}
return NULL;
}
bool BaseContext::IsInExec()
{
return m_InExec;
}
int BaseContext::Execute2(IPluginFunction *function, const cell_t *params, unsigned int num_params, cell_t *result)
{
int ir;
int serial;
cell_t *sp;
funcid_t fnid;
sp_public_t *pubfunc;
cell_t _ignore_result;
fnid = function->GetFunctionID();
if (fnid & 1)
{
unsigned int public_id;
public_id = fnid >> 1;
if (m_pRuntime->GetPublicByIndex(public_id, &pubfunc) != SP_ERROR_NONE)
{
return SP_ERROR_NOT_FOUND;
}
}
else
{
return SP_ERROR_INVALID_ADDRESS;
}
if (m_pRuntime->IsPaused())
{
return SP_ERROR_NOT_RUNNABLE;
}
if ((cell_t)(m_ctx.hp + 16*sizeof(cell_t)) > (cell_t)(m_ctx.sp - (sizeof(cell_t) * (num_params + 1))))
{
return SP_ERROR_STACKLOW;
}
if (result == NULL)
{
result = &_ignore_result;
}
/* We got this far. It's time to start profiling. */
if ((m_pPlugin->prof_flags & SP_PROF_CALLBACKS) == SP_PROF_CALLBACKS)
{
serial = m_pPlugin->profiler->OnCallbackBegin(this, pubfunc);
}
/* Save our previous state. */
bool save_exec;
uint32_t save_n_idx;
cell_t save_sp, save_hp;
save_sp = m_ctx.sp;
save_hp = m_ctx.hp;
save_exec = m_InExec;
save_n_idx = m_ctx.n_idx;
/* Push parameters */
m_ctx.sp -= sizeof(cell_t) * (num_params + 1);
sp = (cell_t *)(m_pPlugin->memory + m_ctx.sp);
sp[0] = num_params;
for (unsigned int i = 0; i < num_params; i++)
{
sp[i + 1] = params[i];
}
/* Clear internal state */
m_ctx.n_err = SP_ERROR_NONE;
m_ctx.n_idx = 0;
m_MsgCache[0] = '\0';
m_CustomMsg = false;
m_InExec = false;
/* Start the tracer */
g_engine1.PushTracer(this);
/* Execute the function */
ir = g_Jit1.ContextExecute(m_pPlugin, &m_ctx, pubfunc->code_offs, result);
/* Restore some states, stop tracing */
m_InExec = save_exec;
if (ir == SP_ERROR_NONE)
{
m_ctx.n_err = SP_ERROR_NONE;
if (m_ctx.sp != save_sp)
{
ir = SP_ERROR_STACKLEAK;
_SetErrorMessage("Stack leak detected: sp:%d should be %d!",
m_ctx.sp,
save_sp);
}
if (m_ctx.hp != save_hp)
{
ir = SP_ERROR_HEAPLEAK;
_SetErrorMessage("Heap leak detected: hp:%d should be %d!",
m_ctx.hp,
save_hp);
}
}
m_ctx.sp = save_sp;
m_ctx.hp = save_hp;
g_engine1.PopTracer(ir, m_CustomMsg ? m_MsgCache : NULL);
if ((m_pPlugin->prof_flags & SP_PROF_CALLBACKS) == SP_PROF_CALLBACKS)
{
m_pPlugin->profiler->OnCallbackEnd(serial);
}
m_ctx.n_idx = save_n_idx;
m_ctx.n_err = SP_ERROR_NONE;
m_MsgCache[0] = '\0';
m_CustomMsg = false;
return ir;
}
IPluginRuntime *BaseContext::GetRuntime()
{
return m_pRuntime;
}
int BaseRuntime::ApplyCompilationOptions(ICompilation *co)
{
int err;
/* The JIT does not destroy anything until it is guaranteed to succeed. */
if (!g_Jit1.Compile(co, this, &err))
{
return err;
}
RefreshFunctionCache();
m_pCtx->Refresh();
return SP_ERROR_NONE;
}
DebugInfo::DebugInfo(sp_plugin_t *plugin) : m_pPlugin(plugin)
{
}
#define USHR(x) ((unsigned int)(x)>>1)
int DebugInfo::LookupFile(ucell_t addr, const char **filename)
{
int high, low, mid;
high = m_pPlugin->debug.files_num;
low = -1;
while (high - low > 1)
{
mid = USHR(low + high);
if (m_pPlugin->files[mid].addr <= addr)
{
low = mid;
} else {
high = mid;
}
}
if (low == -1)
{
return SP_ERROR_NOT_FOUND;
}
*filename = m_pPlugin->files[low].name;
return SP_ERROR_NONE;
}
int DebugInfo::LookupFunction(ucell_t addr, const char **name)
{
uint32_t iter, max = m_pPlugin->debug.syms_num;
for (iter=0; iter<max; iter++)
{
if ((m_pPlugin->symbols[iter].sym->ident == SP_SYM_FUNCTION)
&& (m_pPlugin->symbols[iter].codestart <= addr)
&& (m_pPlugin->symbols[iter].codeend > addr))
{
break;
}
}
if (iter >= max)
{
return SP_ERROR_NOT_FOUND;
}
*name = m_pPlugin->symbols[iter].name;
return SP_ERROR_NONE;
}
int DebugInfo::LookupLine(ucell_t addr, uint32_t *line)
{
int high, low, mid;
high = m_pPlugin->debug.lines_num;
low = -1;
while (high - low > 1)
{
mid = USHR(low + high);
if (m_pPlugin->lines[mid].addr <= addr)
{
low = mid;
} else {
high = mid;
}
}
if (low == -1)
{
return SP_ERROR_NOT_FOUND;
}
/* Since the CIP occurs BEFORE the line, we have to add one */
*line = m_pPlugin->lines[low].line + 1;
return SP_ERROR_NONE;
}
#undef USHR
int BaseContext::GetLastNativeError()
{
return m_ctx.n_err;
}
cell_t *BaseContext::GetLocalParams()
{
return (cell_t *)(m_pPlugin->memory + m_ctx.frm + (2 * sizeof(cell_t)));
}
void BaseContext::SetKey(int k, void *value)
{
if (k < 1 || k > 4)
{
return;
}
m_keys[k - 1] = value;
m_keys_set[k - 1] = true;
}
bool BaseContext::GetKey(int k, void **value)
{
if (k < 1 || k > 4 || m_keys_set[k - 1] == false)
{
return false;
}
*value = m_keys[k - 1];
return true;
}
void BaseContext::Refresh()
{
/* Initialize the null references */
uint32_t index;
if (FindPubvarByName("NULL_VECTOR", &index) == SP_ERROR_NONE)
{
sp_pubvar_t *pubvar;
GetPubvarByIndex(index, &pubvar);
m_pNullVec = pubvar->offs;
}
else
{
m_pNullVec = NULL;
}
if (FindPubvarByName("NULL_STRING", &index) == SP_ERROR_NONE)
{
sp_pubvar_t *pubvar;
GetPubvarByIndex(index, &pubvar);
m_pNullString = pubvar->offs;
}
else
{
m_pNullString = NULL;
}
}

View File

@ -0,0 +1,114 @@
/**
* vim: set ts=4 :
* =============================================================================
* SourcePawn
* Copyright (C) 2004-2008 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 <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_
#define _INCLUDE_SOURCEPAWN_BASECONTEXT_H_
#include "sp_vm_api.h"
#include "sp_vm_function.h"
#include "BaseRuntime.h"
#include "jit_shared.h"
/**
* :TODO: Make functions allocate as a lump instead of individual allocations!
*/
class BaseContext : public IPluginContext
{
public:
BaseContext(BaseRuntime *pRuntime);
~BaseContext();
public: //IPluginContext
IVirtualMachine *GetVirtualMachine();
sp_context_t *GetContext();
sp_context_t *GetCtx();
bool IsDebugging();
int SetDebugBreak(void *newpfn, void *oldpfn);
IPluginDebugInfo *GetDebugInfo();
int HeapAlloc(unsigned int cells, cell_t *local_addr, cell_t **phys_addr);
int HeapPop(cell_t local_addr);
int HeapRelease(cell_t local_addr);
int FindNativeByName(const char *name, uint32_t *index);
int GetNativeByIndex(uint32_t index, sp_native_t **native);
uint32_t GetNativesNum();
int FindPublicByName(const char *name, uint32_t *index);
int GetPublicByIndex(uint32_t index, sp_public_t **publicptr);
uint32_t GetPublicsNum();
int GetPubvarByIndex(uint32_t index, sp_pubvar_t **pubvar);
int FindPubvarByName(const char *name, uint32_t *index);
int GetPubvarAddrs(uint32_t index, cell_t *local_addr, cell_t **phys_addr);
uint32_t GetPubVarsNum();
int LocalToPhysAddr(cell_t local_addr, cell_t **phys_addr);
int LocalToString(cell_t local_addr, char **addr);
int StringToLocal(cell_t local_addr, size_t chars, const char *source);
int StringToLocalUTF8(cell_t local_addr, size_t maxbytes, const char *source, size_t *wrtnbytes);
int PushCell(cell_t value);
int PushCellArray(cell_t *local_addr, cell_t **phys_addr, cell_t array[], unsigned int numcells);
int PushString(cell_t *local_addr, char **phys_addr, const char *string);
int PushCellsFromArray(cell_t array[], unsigned int numcells);
int BindNatives(const sp_nativeinfo_t *natives, unsigned int num, int overwrite);
int BindNative(const sp_nativeinfo_t *native);
int BindNativeToAny(SPVM_NATIVE_FUNC native);
int Execute(uint32_t code_addr, cell_t *result);
cell_t ThrowNativeErrorEx(int error, const char *msg, ...);
cell_t ThrowNativeError(const char *msg, ...);
IPluginFunction *GetFunctionByName(const char *public_name);
IPluginFunction *GetFunctionById(funcid_t func_id);
SourceMod::IdentityToken_t *GetIdentity();
cell_t *GetNullRef(SP_NULL_TYPE type);
int LocalToStringNULL(cell_t local_addr, char **addr);
int BindNativeToIndex(uint32_t index, SPVM_NATIVE_FUNC native);
int Execute2(IPluginFunction *function, const cell_t *params, unsigned int num_params, cell_t *result);
IPluginRuntime *GetRuntime();
int GetLastNativeError();
cell_t *GetLocalParams();
void SetKey(int k, void *value);
bool GetKey(int k, void **value);
void Refresh();
public:
bool IsInExec();
private:
void SetErrorMessage(const char *msg, va_list ap);
void _SetErrorMessage(const char *msg, ...);
private:
sp_plugin_t *m_pPlugin;
cell_t *m_pNullVec;
cell_t *m_pNullString;
char m_MsgCache[1024];
bool m_CustomMsg;
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_

View File

@ -48,6 +48,8 @@
#include "zlib/zlib.h" #include "zlib/zlib.h"
#include "sp_vm_basecontext.h" #include "sp_vm_basecontext.h"
SourcePawnEngine g_engine1;
#if defined WIN32 #if defined WIN32
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#include <windows.h> #include <windows.h>
@ -92,7 +94,7 @@ static const char *g_ErrorMsgTable[] =
"Call was aborted", "Call was aborted",
}; };
const char *GetSourcePawnErrorMessage(int error) const char *SourcePawnEngine::GetErrorString(int error)
{ {
if (error < 1 || error > ERROR_MESSAGE_MAX) if (error < 1 || error > ERROR_MESSAGE_MAX)
{ {
@ -188,281 +190,31 @@ void SourcePawnEngine::BaseFree(void *memory)
free(memory); free(memory);
} }
IPluginContext *SourcePawnEngine::CreateBaseContext(sp_context_t *ctx)
{
return new BaseContext(ctx);
}
void SourcePawnEngine::FreeBaseContext(IPluginContext *ctx)
{
delete ctx;
}
sp_plugin_t *_ReadPlugin(sp_file_hdr_t *hdr, uint8_t *base, sp_plugin_t *plugin, int *err)
{
char *nameptr;
uint8_t sectnum = 0;
sp_file_section_t *secptr = (sp_file_section_t *)(base + sizeof(sp_file_hdr_t));
memset(plugin, 0, sizeof(sp_plugin_t));
plugin->base = base;
while (sectnum < hdr->sections)
{
nameptr = (char *)(base + hdr->stringtab + secptr->nameoffs);
if (!(plugin->pcode) && !strcmp(nameptr, ".code"))
{
sp_file_code_t *cod = (sp_file_code_t *)(base + secptr->dataoffs);
plugin->pcode = base + secptr->dataoffs + cod->code;
plugin->pcode_size = cod->codesize;
plugin->flags = cod->flags;
}
else if (!(plugin->data) && !strcmp(nameptr, ".data"))
{
sp_file_data_t *dat = (sp_file_data_t *)(base + secptr->dataoffs);
plugin->data = base + secptr->dataoffs + dat->data;
plugin->data_size = dat->datasize;
plugin->memory = dat->memsize;
}
else if (!(plugin->info.publics) && !strcmp(nameptr, ".publics"))
{
plugin->info.publics_num = secptr->size / sizeof(sp_file_publics_t);
plugin->info.publics = (sp_file_publics_t *)(base + secptr->dataoffs);
}
else if (!(plugin->info.pubvars) && !strcmp(nameptr, ".pubvars"))
{
plugin->info.pubvars_num = secptr->size / sizeof(sp_file_pubvars_t);
plugin->info.pubvars = (sp_file_pubvars_t *)(base + secptr->dataoffs);
}
else if (!(plugin->info.natives) && !strcmp(nameptr, ".natives"))
{
plugin->info.natives_num = secptr->size / sizeof(sp_file_natives_t);
plugin->info.natives = (sp_file_natives_t *)(base + secptr->dataoffs);
}
else if (!(plugin->info.stringbase) && !strcmp(nameptr, ".names"))
{
plugin->info.stringbase = (const char *)(base + secptr->dataoffs);
}
else if (!(plugin->debug.files) && !strcmp(nameptr, ".dbg.files"))
{
plugin->debug.files = (sp_fdbg_file_t *)(base + secptr->dataoffs);
}
else if (!(plugin->debug.lines) && !strcmp(nameptr, ".dbg.lines"))
{
plugin->debug.lines = (sp_fdbg_line_t *)(base + secptr->dataoffs);
}
else if (!(plugin->debug.symbols) && !strcmp(nameptr, ".dbg.symbols"))
{
plugin->debug.symbols = (sp_fdbg_symbol_t *)(base + secptr->dataoffs);
}
else if (!(plugin->debug.lines_num) && !strcmp(nameptr, ".dbg.info"))
{
sp_fdbg_info_t *inf = (sp_fdbg_info_t *)(base + secptr->dataoffs);
plugin->debug.files_num = inf->num_files;
plugin->debug.lines_num = inf->num_lines;
plugin->debug.syms_num = inf->num_syms;
}
else if (!(plugin->debug.stringbase) && !strcmp(nameptr, ".dbg.strings"))
{
plugin->debug.stringbase = (const char *)(base + secptr->dataoffs);
}
secptr++;
sectnum++;
}
if (!(plugin->pcode) || !(plugin->data) || !(plugin->info.stringbase))
{
goto return_error;
}
if ((plugin->flags & SP_FLAG_DEBUG) && (!(plugin->debug.files) || !(plugin->debug.lines) || !(plugin->debug.symbols)))
{
goto return_error;
}
if (err)
{
*err = SP_ERROR_NONE;
}
return plugin;
return_error:
if (err)
{
*err = SP_ERROR_FILE_FORMAT;
}
return NULL;
}
sp_plugin_t *SourcePawnEngine::LoadFromFilePointer(FILE *fp, int *err) sp_plugin_t *SourcePawnEngine::LoadFromFilePointer(FILE *fp, int *err)
{ {
sp_file_hdr_t hdr; if (err != NULL)
sp_plugin_t *plugin;
uint8_t *base;
int z_result;
int error;
if (!fp)
{ {
error = SP_ERROR_NOT_FOUND; *err = SP_ERROR_ABORTED;
goto return_error;
} }
/* Rewind for safety */
rewind(fp);
fread(&hdr, sizeof(sp_file_hdr_t), 1, fp);
if (hdr.magic != SPFILE_MAGIC)
{
error = SP_ERROR_FILE_FORMAT;
goto return_error;
}
switch (hdr.compression)
{
case SPFILE_COMPRESSION_GZ:
{
uint32_t uncompsize = hdr.imagesize - hdr.dataoffs;
uint32_t compsize = hdr.disksize - hdr.dataoffs;
uint32_t sectsize = hdr.dataoffs - sizeof(sp_file_hdr_t);
uLongf destlen = uncompsize;
char *tempbuf = (char *)malloc(compsize);
void *uncompdata = malloc(uncompsize);
void *sectheader = malloc(sectsize);
fread(sectheader, sectsize, 1, fp);
fread(tempbuf, compsize, 1, fp);
z_result = uncompress((Bytef *)uncompdata, &destlen, (Bytef *)tempbuf, compsize);
free(tempbuf);
if (z_result != Z_OK)
{
free(sectheader);
free(uncompdata);
error = SP_ERROR_DECOMPRESSOR;
goto return_error;
}
base = (uint8_t *)malloc(hdr.imagesize);
memcpy(base, &hdr, sizeof(sp_file_hdr_t));
memcpy(base + sizeof(sp_file_hdr_t), sectheader, sectsize);
free(sectheader);
memcpy(base + hdr.dataoffs, uncompdata, uncompsize);
free(uncompdata);
break;
}
case SPFILE_COMPRESSION_NONE:
{
base = (uint8_t *)malloc(hdr.imagesize);
rewind(fp);
fread(base, hdr.imagesize, 1, fp);
break;
}
default:
{
error = SP_ERROR_DECOMPRESSOR;
goto return_error;
}
}
plugin = (sp_plugin_t *)malloc(sizeof(sp_plugin_t));
if (!_ReadPlugin(&hdr, base, plugin, err))
{
free(plugin);
free(base);
return NULL;
}
plugin->allocflags = 0;
return plugin;
return_error:
if (err)
{
*err = error;
}
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)
{ {
sp_file_hdr_t hdr; if (err != NULL)
uint8_t noptr = 0;
memcpy(&hdr, base, sizeof(sp_file_hdr_t));
if (!plugin)
{ {
plugin = (sp_plugin_t *)malloc(sizeof(sp_plugin_t)); *err = SP_ERROR_ABORTED;
noptr = 1;
} }
if (!_ReadPlugin(&hdr, (uint8_t *)base, plugin, err)) return NULL;
{
if (noptr)
{
free(plugin);
}
return NULL;
}
if (!noptr)
{
plugin->allocflags |= SP_FA_SELF_EXTERNAL;
}
plugin->allocflags |= SP_FA_BASE_EXTERNAL;
return plugin;
} }
int SourcePawnEngine::FreeFromMemory(sp_plugin_t *plugin) int SourcePawnEngine::FreeFromMemory(sp_plugin_t *plugin)
{ {
if (!(plugin->allocflags & SP_FA_BASE_EXTERNAL)) return SP_ERROR_ABORTED;
{
free(plugin->base);
plugin->base = NULL;
}
if (!(plugin->allocflags & SP_FA_SELF_EXTERNAL))
{
free(plugin);
}
return SP_ERROR_NONE;
} }
#if 0
void SourcePawnEngine::ReleaseFunctionToPool(CFunction *func)
{
if (!func)
{
return;
}
func->Cancel();
func->m_pNext = m_pFreeFuncs;
m_pFreeFuncs = func;
}
CFunction *SourcePawnEngine::GetFunctionFromPool(funcid_t f, IPluginContext *plugin)
{
if (!m_pFreeFuncs)
{
return new CFunction(f, plugin);
} else {
CFunction *pFunc = m_pFreeFuncs;
m_pFreeFuncs = m_pFreeFuncs->m_pNext;
pFunc->Set(f, plugin);
return pFunc;
}
}
#endif
IDebugListener *SourcePawnEngine::SetDebugListener(IDebugListener *pListener) IDebugListener *SourcePawnEngine::SetDebugListener(IDebugListener *pListener)
{ {
IDebugListener *old = m_pDebugHook; IDebugListener *old = m_pDebugHook;
@ -529,7 +281,7 @@ void SourcePawnEngine::FreeTracedCall(TracedCall *pCall)
} }
} }
void SourcePawnEngine::PushTracer(sp_context_t *ctx) void SourcePawnEngine::PushTracer(BaseContext *ctx)
{ {
TracedCall *pCall = MakeTracedCall(true); TracedCall *pCall = MakeTracedCall(true);
@ -538,7 +290,7 @@ void SourcePawnEngine::PushTracer(sp_context_t *ctx)
pCall->frm = INVALID_CIP; pCall->frm = INVALID_CIP;
} }
void SourcePawnEngine::RunTracer(sp_context_t *ctx, uint32_t frame, uint32_t codeip) void SourcePawnEngine::RunTracer(BaseContext *ctx, uint32_t frame, uint32_t codeip)
{ {
assert(m_CallStack != NULL); assert(m_CallStack != NULL);
assert(m_CallStack->ctx == ctx); assert(m_CallStack->ctx == ctx);
@ -577,13 +329,13 @@ void SourcePawnEngine::PopTracer(int error, const char *msg)
{ {
uint32_t native = INVALID_CIP; uint32_t native = INVALID_CIP;
if (m_CallStack->ctx->n_err) if (m_CallStack->ctx->GetCtx()->n_err)
{ {
native = m_CallStack->ctx->n_idx; native = m_CallStack->ctx->GetCtx()->n_idx;
} }
CContextTrace trace(m_CallStack, error, msg, native); CContextTrace trace(m_CallStack, error, msg, native);
m_pDebugHook->OnContextExecuteError(m_CallStack->ctx->context, &trace); m_pDebugHook->OnContextExecuteError(m_CallStack->ctx, &trace);
} }
/* Now pop the error chain */ /* Now pop the error chain */
@ -607,7 +359,7 @@ CContextTrace::CContextTrace(TracedCall *pStart, int error, const char *msg, uin
bool CContextTrace::DebugInfoAvailable() bool CContextTrace::DebugInfoAvailable()
{ {
return ((m_pStart->ctx->flags & SP_FLAG_DEBUG) == SP_FLAG_DEBUG); return m_pStart->ctx->IsDebugging();
} }
const char *CContextTrace::GetCustomErrorString() const char *CContextTrace::GetCustomErrorString()
@ -648,7 +400,7 @@ bool CContextTrace::GetTraceInfo(CallStackInfo *trace)
return false; return false;
} }
IPluginContext *pContext = m_pIterator->ctx->context; IPluginContext *pContext = m_pIterator->ctx;
IPluginDebugInfo *pInfo = pContext->GetDebugInfo(); IPluginDebugInfo *pInfo = pContext->GetDebugInfo();
if (!pInfo) if (!pInfo)
@ -690,7 +442,7 @@ const char *CContextTrace::GetLastNative(uint32_t *index)
} }
sp_native_t *native; sp_native_t *native;
if (m_pIterator->ctx->context->GetNativeByIndex(m_Native, &native) != SP_ERROR_NONE) if (m_pIterator->ctx->GetNativeByIndex(m_Native, &native) != SP_ERROR_NONE)
{ {
return NULL; return NULL;
} }

View File

@ -35,11 +35,13 @@
#include "sp_vm_api.h" #include "sp_vm_api.h"
#include "sp_vm_function.h" #include "sp_vm_function.h"
class BaseContext;
struct TracedCall struct TracedCall
{ {
uint32_t cip; uint32_t cip;
uint32_t frm; uint32_t frm;
sp_context_t *ctx; BaseContext *ctx;
TracedCall *next; TracedCall *next;
unsigned int chain; unsigned int chain;
}; };
@ -73,8 +75,6 @@ public: //ISourcePawnEngine
sp_plugin_t *LoadFromFilePointer(FILE *fp, int *err); sp_plugin_t *LoadFromFilePointer(FILE *fp, int *err);
sp_plugin_t *LoadFromMemory(void *base, sp_plugin_t *plugin, int *err); sp_plugin_t *LoadFromMemory(void *base, sp_plugin_t *plugin, int *err);
int FreeFromMemory(sp_plugin_t *plugin); int FreeFromMemory(sp_plugin_t *plugin);
IPluginContext *CreateBaseContext(sp_context_t *ctx);
void FreeBaseContext(IPluginContext *ctx);
void *BaseAlloc(size_t size); void *BaseAlloc(size_t size);
void BaseFree(void *memory); void BaseFree(void *memory);
void *ExecAlloc(size_t size); void *ExecAlloc(size_t size);
@ -86,13 +86,14 @@ public: //ISourcePawnEngine
void SetReadWrite(void *ptr); void SetReadWrite(void *ptr);
void SetReadExecute(void *ptr); void SetReadExecute(void *ptr);
void FreePageMemory(void *ptr); void FreePageMemory(void *ptr);
const char *GetErrorString(int err);
public: //Debugger Stuff public: //Debugger Stuff
/** /**
* @brief Pushes a context onto the top of the call tracer. * @brief Pushes a context onto the top of the call tracer.
* *
* @param ctx Plugin context. * @param ctx Plugin context.
*/ */
void PushTracer(sp_context_t *ctx); void PushTracer(BaseContext *ctx);
/** /**
* @brief Pops a plugin off the call tracer. * @brief Pops a plugin off the call tracer.
@ -102,7 +103,7 @@ public: //Debugger Stuff
/** /**
* @brief Runs tracer from a debug break. * @brief Runs tracer from a debug break.
*/ */
void RunTracer(sp_context_t *ctx, uint32_t frame, uint32_t codeip); void RunTracer(BaseContext *ctx, uint32_t frame, uint32_t codeip);
public: //Plugin function stuff public: //Plugin function stuff
CFunction *GetFunctionFromPool(funcid_t f, IPluginContext *plugin); CFunction *GetFunctionFromPool(funcid_t f, IPluginContext *plugin);
void ReleaseFunctionToPool(CFunction *func); void ReleaseFunctionToPool(CFunction *func);
@ -117,4 +118,6 @@ private:
//CFunction *m_pFreeFuncs; //CFunction *m_pFreeFuncs;
}; };
extern SourcePawnEngine g_engine1;
#endif //_INCLUDE_SOURCEPAWN_VM_ENGINE_H_ #endif //_INCLUDE_SOURCEPAWN_VM_ENGINE_H_

View File

@ -32,76 +32,47 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include "sp_vm_function.h" #include "sp_vm_function.h"
#include "sm_stringutil.h" #include "BaseRuntime.h"
/******************** /********************
* FUNCTION CALLING * * FUNCTION CALLING *
********************/ ********************/
void CFunction::Set(uint32_t code_addr, IPluginContext *plugin, funcid_t id, uint32_t pub_id) void CFunction::Set(uint32_t code_addr, BaseRuntime *runtime, funcid_t fnid, uint32_t pub_id)
{ {
m_codeaddr = code_addr; m_codeaddr = code_addr;
m_pContext = plugin; m_pRuntime = runtime;
m_curparam = 0; m_curparam = 0;
m_errorstate = SP_ERROR_NONE; m_errorstate = SP_ERROR_NONE;
m_Invalid = false; m_Invalid = false;
m_pCtx = plugin ? plugin->GetContext() : NULL; m_FnId = fnid;
m_FnId = id;
m_pContext->GetPublicByIndex(pub_id, &m_pPublic);
} }
bool CFunction::IsRunnable() bool CFunction::IsRunnable()
{ {
return ((m_pCtx->flags & SPFLAG_PLUGIN_PAUSED) != SPFLAG_PLUGIN_PAUSED); 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)
{ {
int ir, serial; return CallFunction2(m_pRuntime->GetDefaultContext(), params, num_params, result);
}
if (!IsRunnable()) int CFunction::CallFunction2(IPluginContext *pContext, const cell_t *params, unsigned int num_params, cell_t *result)
{ {
return SP_ERROR_NOT_RUNNABLE; return pContext->Execute2(this, params, num_params, result);
}
if ((m_pCtx->prof_flags & SP_PROF_CALLBACKS) == SP_PROF_CALLBACKS
&& m_pPublic != NULL)
{
serial = m_pCtx->profiler->OnCallbackBegin(m_pContext, m_pPublic);
}
while (num_params--)
{
m_pContext->PushCell(params[num_params]);
}
ir = m_pContext->Execute(m_codeaddr, result);
if ((m_pCtx->prof_flags & SP_PROF_CALLBACKS) == SP_PROF_CALLBACKS
&& m_pPublic != NULL)
{
m_pCtx->profiler->OnCallbackEnd(serial);
}
return ir;
} }
IPluginContext *CFunction::GetParentContext() IPluginContext *CFunction::GetParentContext()
{ {
return m_pContext; return m_pRuntime->GetDefaultContext();
} }
CFunction::CFunction(uint32_t code_addr, IPluginContext *plugin, funcid_t id, uint32_t pub_id) : CFunction::CFunction(uint32_t code_addr, BaseRuntime *runtime, funcid_t id, uint32_t pub_id) :
m_codeaddr(code_addr), m_pContext(plugin), m_curparam(0), m_codeaddr(code_addr), m_curparam(0), m_errorstate(SP_ERROR_NONE), m_FnId(id)
m_errorstate(SP_ERROR_NONE), m_FnId(id)
{ {
m_Invalid = false; m_Invalid = false;
if (plugin) m_pRuntime = runtime;
{
m_pCtx = plugin->GetContext();
}
m_pContext->GetPublicByIndex(pub_id, &m_pPublic);
} }
int CFunction::PushCell(cell_t cell) int CFunction::PushCell(cell_t cell)
@ -198,6 +169,11 @@ void CFunction::Cancel()
} }
int CFunction::Execute(cell_t *result) int CFunction::Execute(cell_t *result)
{
return Execute2(m_pRuntime->GetDefaultContext(), result);
}
int CFunction::Execute2(IPluginContext *ctx, cell_t *result)
{ {
int err = SP_ERROR_NONE; int err = SP_ERROR_NONE;
@ -236,9 +212,9 @@ int CFunction::Execute(cell_t *result)
if (!temp_info[i].str.is_sz) if (!temp_info[i].str.is_sz)
{ {
/* Allocate a normal/generic array */ /* Allocate a normal/generic array */
if ((err=m_pContext->HeapAlloc(temp_info[i].size, if ((err=ctx->HeapAlloc(temp_info[i].size,
&(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;
@ -254,9 +230,9 @@ int CFunction::Execute(cell_t *result)
size_t cells = (temp_info[i].size + sizeof(cell_t) - 1) / sizeof(cell_t); size_t cells = (temp_info[i].size + sizeof(cell_t) - 1) / sizeof(cell_t);
/* Allocate the buffer */ /* Allocate the buffer */
if ((err=m_pContext->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;
@ -267,10 +243,10 @@ int CFunction::Execute(cell_t *result)
/* 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=m_pContext->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;
@ -284,9 +260,9 @@ int CFunction::Execute(cell_t *result)
/* Copy ASCII characters */ /* Copy ASCII characters */
else else
{ {
if ((err=m_pContext->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;
@ -307,7 +283,7 @@ int CFunction::Execute(cell_t *result)
/* Make the call if we can */ /* Make the call if we can */
if (err == SP_ERROR_NONE) if (err == SP_ERROR_NONE)
{ {
if ((err = CallFunction(temp_params, numparams, result)) != SP_ERROR_NONE) if ((err = CallFunction2(ctx, temp_params, numparams, result)) != SP_ERROR_NONE)
{ {
docopies = false; docopies = false;
} }
@ -350,7 +326,7 @@ int CFunction::Execute(cell_t *result)
} }
} }
if ((err=m_pContext->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;
} }
@ -364,3 +340,16 @@ funcid_t CFunction::GetFunctionID()
return m_FnId; return m_FnId;
} }
int CFunction::SetError(int err)
{
m_errorstate = err;
return err;
}
bool CFunction::IsInvalidated()
{
return m_Invalid;
}

View File

@ -32,7 +32,11 @@
#ifndef _INCLUDE_SOURCEMOD_BASEFUNCTION_H_ #ifndef _INCLUDE_SOURCEMOD_BASEFUNCTION_H_
#define _INCLUDE_SOURCEMOD_BASEFUNCTION_H_ #define _INCLUDE_SOURCEMOD_BASEFUNCTION_H_
#include "sm_globals.h" #include <sp_vm_api.h>
class BaseRuntime;
using namespace SourcePawn;
struct ParamInfo struct ParamInfo
{ {
@ -56,7 +60,7 @@ class CFunction : public IPluginFunction
friend class SourcePawnEngine; friend class SourcePawnEngine;
public: public:
CFunction(uint32_t code_addr, CFunction(uint32_t code_addr,
IPluginContext *pContext, BaseRuntime *pRuntime,
funcid_t fnid, funcid_t fnid,
uint32_t pub_id); uint32_t pub_id);
public: public:
@ -71,29 +75,23 @@ public:
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();
inline bool IsInvalidated() bool IsInvalidated();
{ void Invalidate();
return m_Invalid;
}
inline void Invalidate()
{
m_Invalid = true;
}
bool IsRunnable(); bool IsRunnable();
funcid_t GetFunctionID(); funcid_t GetFunctionID();
int Execute2(IPluginContext *ctx, cell_t *result);
int CallFunction2(IPluginContext *ctx,
const cell_t *params,
unsigned int num_params,
cell_t *result);
public: public:
void Set(uint32_t code_addr, IPluginContext *plugin, funcid_t fnid, uint32_t pub_id); void Set(uint32_t code_addr, BaseRuntime *runtime, funcid_t fnid, uint32_t pub_id);
private: private:
int _PushString(const char *string, int sz_flags, int cp_flags, size_t len); int _PushString(const char *string, int sz_flags, int cp_flags, size_t len);
inline int SetError(int err) int SetError(int err);
{
m_errorstate = err;
return err;
}
private: private:
uint32_t m_codeaddr; uint32_t m_codeaddr;
IPluginContext *m_pContext; BaseRuntime *m_pRuntime;
sp_context_t *m_pCtx;
cell_t m_params[SP_MAX_EXEC_PARAMS]; cell_t m_params[SP_MAX_EXEC_PARAMS];
ParamInfo m_info[SP_MAX_EXEC_PARAMS]; ParamInfo m_info[SP_MAX_EXEC_PARAMS];
unsigned int m_curparam; unsigned int m_curparam;
@ -101,7 +99,6 @@ private:
CFunction *m_pNext; CFunction *m_pNext;
bool m_Invalid; bool m_Invalid;
funcid_t m_FnId; funcid_t m_FnId;
sp_public_t *m_pPublic;
}; };
#endif //_INCLUDE_SOURCEMOD_BASEFUNCTION_H_ #endif //_INCLUDE_SOURCEMOD_BASEFUNCTION_H_

View File

@ -35,12 +35,24 @@
#include "jit_x86.h" #include "jit_x86.h"
#include "opcode_helpers.h" #include "opcode_helpers.h"
#include <x86_macros.h> #include <x86_macros.h>
#include "jit_version.h" #include "../jit_version.h"
#include "../sp_vm_engine.h"
#include "../engine2.h"
#include "../BaseRuntime.h"
#include "../sp_vm_basecontext.h"
#if defined USE_UNGEN_OPCODES #if defined USE_UNGEN_OPCODES
#include "ungen_opcodes.h" #include "ungen_opcodes.h"
#endif #endif
JITX86 g_Jit1;
ISourcePawnEngine *engine = &g_engine1;
inline sp_plugin_t *GETPLUGIN(sp_context_t *ctx)
{
return (sp_plugin_t *)(ctx->vm[JITVARS_PLUGIN]);
}
inline void WriteOp_Move_Pri(JitWriter *jit) inline void WriteOp_Move_Pri(JitWriter *jit)
{ {
//mov eax, edx //mov eax, edx
@ -1318,12 +1330,12 @@ inline void WriteOp_Retn(JitWriter *jit)
void ProfCallGate_Begin(sp_context_t *ctx, const char *name) void ProfCallGate_Begin(sp_context_t *ctx, const char *name)
{ {
ctx->profiler->OnFunctionBegin(ctx->context, name); ((IProfiler *)ctx->vm[JITVARS_PROFILER])->OnFunctionBegin((IPluginContext *)ctx->vm[JITVARS_BASECTX], name);
} }
void ProfCallGate_End(sp_context_t *ctx) void ProfCallGate_End(sp_context_t *ctx)
{ {
ctx->profiler->OnFunctionEnd(); ((IProfiler *)ctx->vm[JITVARS_PROFILER])->OnFunctionEnd();
} }
const char *find_func_name(sp_plugin_t *plugin, uint32_t offs) const char *find_func_name(sp_plugin_t *plugin, uint32_t offs)
@ -2264,8 +2276,11 @@ inline void WriteOp_FloatCompare(JitWriter *jit)
cell_t NativeCallback(sp_context_t *ctx, ucell_t native_idx, cell_t *params) cell_t NativeCallback(sp_context_t *ctx, ucell_t native_idx, cell_t *params)
{ {
sp_native_t *native; sp_native_t *native;
sp_plugin_t *plugin;
native = &ctx->natives[native_idx]; plugin = (sp_plugin_t *)ctx->vm[JITVARS_PLUGIN];
native = &plugin->natives[native_idx];
ctx->n_idx = native_idx; ctx->n_idx = native_idx;
@ -2276,15 +2291,18 @@ cell_t NativeCallback(sp_context_t *ctx, ucell_t native_idx, cell_t *params)
return 0; return 0;
} }
return native->pfn(ctx->context, params); return native->pfn(GET_CONTEXT(ctx), params);
} }
cell_t NativeCallback_Profile(sp_context_t *ctx, ucell_t native_idx, cell_t *params) cell_t NativeCallback_Profile(sp_context_t *ctx, ucell_t native_idx, cell_t *params)
{ {
cell_t val; cell_t val;
sp_native_t *native; sp_native_t *native;
sp_plugin_t *plugin;
native = &ctx->natives[native_idx]; plugin = (sp_plugin_t *)ctx->vm[JITVARS_PLUGIN];
native = &plugin->natives[native_idx];
ctx->n_idx = native_idx; ctx->n_idx = native_idx;
@ -2295,9 +2313,9 @@ cell_t NativeCallback_Profile(sp_context_t *ctx, ucell_t native_idx, cell_t *par
return 0; return 0;
} }
ctx->profiler->OnNativeBegin(ctx->context, native); plugin->profiler->OnNativeBegin(GET_CONTEXT(ctx), native);
val = native->pfn(ctx->context, params); val = native->pfn(GET_CONTEXT(ctx), params);
ctx->profiler->OnNativeEnd(); plugin->profiler->OnNativeEnd();
return val; return val;
} }
@ -2307,9 +2325,11 @@ cell_t NativeCallback_Debug(sp_context_t *ctx, ucell_t native_idx, cell_t *param
cell_t save_sp = ctx->sp; cell_t save_sp = ctx->sp;
cell_t save_hp = ctx->hp; cell_t save_hp = ctx->hp;
sp_plugin_t *pl = GETPLUGIN(ctx);
ctx->n_idx = native_idx; ctx->n_idx = native_idx;
if (ctx->hp < ctx->heap_base) if (ctx->hp < (cell_t)pl->data_size)
{ {
ctx->n_err = SP_ERROR_HEAPMIN; ctx->n_err = SP_ERROR_HEAPMIN;
return 0; return 0;
@ -2321,7 +2341,7 @@ cell_t NativeCallback_Debug(sp_context_t *ctx, ucell_t native_idx, cell_t *param
return 0; return 0;
} }
if ((uint32_t)ctx->sp >= ctx->mem_size) if ((uint32_t)ctx->sp >= pl->mem_size)
{ {
ctx->n_err = SP_ERROR_STACKMIN; ctx->n_err = SP_ERROR_STACKMIN;
return 0; return 0;
@ -2353,9 +2373,11 @@ cell_t NativeCallback_Debug_Profile(sp_context_t *ctx, ucell_t native_idx, cell_
cell_t save_sp = ctx->sp; cell_t save_sp = ctx->sp;
cell_t save_hp = ctx->hp; cell_t save_hp = ctx->hp;
sp_plugin_t *pl = GETPLUGIN(ctx);
ctx->n_idx = native_idx; ctx->n_idx = native_idx;
if (ctx->hp < ctx->heap_base) if (ctx->hp < (cell_t)pl->data_size)
{ {
ctx->n_err = SP_ERROR_HEAPMIN; ctx->n_err = SP_ERROR_HEAPMIN;
return 0; return 0;
@ -2367,7 +2389,7 @@ cell_t NativeCallback_Debug_Profile(sp_context_t *ctx, ucell_t native_idx, cell_
return 0; return 0;
} }
if ((uint32_t)ctx->sp >= ctx->mem_size) if ((uint32_t)ctx->sp >= pl->mem_size)
{ {
ctx->n_err = SP_ERROR_STACKMIN; ctx->n_err = SP_ERROR_STACKMIN;
return 0; return 0;
@ -2396,10 +2418,7 @@ cell_t NativeCallback_Debug_Profile(sp_context_t *ctx, ucell_t native_idx, cell_
static cell_t InvalidNative(IPluginContext *pCtx, const cell_t *params) static cell_t InvalidNative(IPluginContext *pCtx, const cell_t *params)
{ {
sp_context_t *ctx = pCtx->GetContext(); return pCtx->ThrowNativeErrorEx(SP_ERROR_INVALID_NATIVE, "Invalid native");
ctx->n_err = SP_ERROR_INVALID_NATIVE;
return 0;
} }
jitoffs_t RelocLookup(JitWriter *jit, cell_t pcode_offs, bool relative) jitoffs_t RelocLookup(JitWriter *jit, cell_t pcode_offs, bool relative)
@ -2457,11 +2476,27 @@ void WriteErrorRoutines(CompData *data, JitWriter *jit)
Write_GetError(jit); Write_GetError(jit);
} }
sp_context_t *JITX86::CompileToContext(ICompilation *co, int *err) bool JITX86::Compile(ICompilation *co, BaseRuntime *prt, int *err)
{ {
CompData *data = (CompData *)co; CompData *data = (CompData *)co;
sp_plugin_t *plugin = data->plugin; sp_plugin_t *plugin = data->plugin;
if (data->plugin == NULL)
{
if (data->debug && !(prt->m_pPlugin->flags & SP_FLAG_DEBUG))
{
if (err != NULL)
{
*err = SP_ERROR_NOTDEBUGGING;
}
co->Abort();
return false;
}
data->SetRuntime(prt);
plugin = data->plugin;
}
/* The first phase is to browse */ /* The first phase is to browse */
uint8_t *code = plugin->pcode; uint8_t *code = plugin->pcode;
uint8_t *end_cip = plugin->pcode + plugin->pcode_size; uint8_t *end_cip = plugin->pcode + plugin->pcode_size;
@ -2584,8 +2619,8 @@ jit_rewind:
if (data->error_set != SP_ERROR_NONE) if (data->error_set != SP_ERROR_NONE)
{ {
*err = data->error_set; *err = data->error_set;
AbortCompilation(co); co->Abort();
return NULL; return false;
} }
} }
/* Write these last because error jumps should be unpredicted, and thus forward */ /* Write these last because error jumps should be unpredicted, and thus forward */
@ -2627,23 +2662,29 @@ jit_rewind:
* FOURTH PASS - Context Setup * FOURTH PASS - Context Setup
*************/ *************/
sp_context_t *ctx = new sp_context_t;
memset(ctx, 0, sizeof(sp_context_t));
/* setup basics */ /* setup basics */
ctx->codebase = writer.outbase; sp_context_t *ctx = data->runtime->GetBaseContext()->GetCtx();
ctx->plugin = plugin;
ctx->vmbase = this; /* Clear out any old cruft */
ctx->flags = (data->debug ? SPFLAG_PLUGIN_DEBUG : 0); if (plugin->codebase != NULL)
{
FreePluginVars(data->runtime->m_pPlugin);
FreeContextVars(ctx);
}
plugin->codebase = writer.outbase;
plugin->jit_codesize = codemem;
plugin->jit_memsize = 0;
/* setup memory */ /* setup memory */
ctx->memory = new uint8_t[plugin->memory];
memcpy(ctx->memory, plugin->data, plugin->data_size); ctx->hp = plugin->data_size;
ctx->mem_size = plugin->memory; ctx->sp = plugin->mem_size - sizeof(cell_t);
ctx->heap_base = plugin->data_size; ctx->frm = ctx->sp;
ctx->hp = ctx->heap_base; ctx->n_err = SP_ERROR_NONE;
ctx->sp = ctx->mem_size - sizeof(cell_t); ctx->n_idx = SP_ERROR_NONE;
ctx->prof_flags = data->profile; plugin->prof_flags = data->profile;
plugin->flags = data->debug ? SPFLAG_PLUGIN_DEBUG : 0;
const char *strbase = plugin->info.stringbase; const char *strbase = plugin->info.stringbase;
uint32_t max, iter; uint32_t max, iter;
@ -2651,39 +2692,42 @@ jit_rewind:
/* relocate public info */ /* relocate public info */
if ((max = plugin->info.publics_num)) if ((max = plugin->info.publics_num))
{ {
ctx->publics = new sp_public_t[max]; plugin->publics = new sp_public_t[max];
plugin->jit_memsize += sizeof(sp_public_t) * max;
for (iter=0; iter<max; iter++) for (iter=0; iter<max; iter++)
{ {
ctx->publics[iter].name = strbase + plugin->info.publics[iter].name; plugin->publics[iter].name = strbase + plugin->info.publics[iter].name;
ctx->publics[iter].code_offs = RelocLookup(jit, plugin->info.publics[iter].address, false); plugin->publics[iter].code_offs = RelocLookup(jit, plugin->info.publics[iter].address, false);
/* Encode the ID as a straight code offset */ /* Encode the ID as a straight code offset */
ctx->publics[iter].funcid = (ctx->publics[iter].code_offs << 1); plugin->publics[iter].funcid = (plugin->publics[iter].code_offs << 1);
} }
} }
/* relocate pubvar info */ /* relocate pubvar info */
if ((max = plugin->info.pubvars_num)) if ((max = plugin->info.pubvars_num))
{ {
uint8_t *dat = ctx->memory; uint8_t *dat = plugin->memory;
ctx->pubvars = new sp_pubvar_t[max]; plugin->pubvars = new sp_pubvar_t[max];
plugin->jit_memsize += sizeof(sp_pubvar_t) * max;
for (iter=0; iter<max; iter++) for (iter=0; iter<max; iter++)
{ {
ctx->pubvars[iter].name = strbase + plugin->info.pubvars[iter].name; plugin->pubvars[iter].name = strbase + plugin->info.pubvars[iter].name;
ctx->pubvars[iter].offs = (cell_t *)(dat + plugin->info.pubvars[iter].address); plugin->pubvars[iter].offs = (cell_t *)(dat + plugin->info.pubvars[iter].address);
} }
} }
/* relocate native info */ /* relocate native info */
if ((max = plugin->info.natives_num)) if ((max = plugin->info.natives_num))
{ {
ctx->natives = new sp_native_t[max]; plugin->natives = new sp_native_t[max];
plugin->jit_memsize += sizeof(sp_native_t) * max;
for (iter=0; iter<max; iter++) for (iter=0; iter<max; iter++)
{ {
ctx->natives[iter].name = strbase + plugin->info.natives[iter].name; plugin->natives[iter].name = strbase + plugin->info.natives[iter].name;
ctx->natives[iter].pfn = &InvalidNative; plugin->natives[iter].pfn = &InvalidNative;
ctx->natives[iter].status = SP_NATIVE_UNBOUND; plugin->natives[iter].status = SP_NATIVE_UNBOUND;
ctx->natives[iter].flags = 0; plugin->natives[iter].flags = 0;
ctx->natives[iter].user = NULL; plugin->natives[iter].user = NULL;
} }
} }
@ -2696,20 +2740,22 @@ jit_rewind:
/* relocate files */ /* relocate files */
max = plugin->debug.files_num; max = plugin->debug.files_num;
ctx->files = new sp_debug_file_t[max]; plugin->files = new sp_debug_file_t[max];
plugin->jit_memsize += sizeof(sp_debug_file_t) * max;
for (iter=0; iter<max; iter++) for (iter=0; iter<max; iter++)
{ {
ctx->files[iter].addr = RelocLookup(jit, plugin->debug.files[iter].addr, false); plugin->files[iter].addr = RelocLookup(jit, plugin->debug.files[iter].addr, false);
ctx->files[iter].name = strbase + plugin->debug.files[iter].name; plugin->files[iter].name = strbase + plugin->debug.files[iter].name;
} }
/* relocate lines */ /* relocate lines */
max = plugin->debug.lines_num; max = plugin->debug.lines_num;
ctx->lines = new sp_debug_line_t[max]; plugin->lines = new sp_debug_line_t[max];
plugin->jit_memsize += sizeof(sp_debug_line_t) * max;
for (iter=0; iter<max; iter++) for (iter=0; iter<max; iter++)
{ {
ctx->lines[iter].addr = RelocLookup(jit, plugin->debug.lines[iter].addr, false); plugin->lines[iter].addr = RelocLookup(jit, plugin->debug.lines[iter].addr, false);
ctx->lines[iter].line = plugin->debug.lines[iter].line; plugin->lines[iter].line = plugin->debug.lines[iter].line;
} }
/* relocate arrays */ /* relocate arrays */
@ -2718,7 +2764,8 @@ jit_rewind:
uint8_t *cursor = (uint8_t *)(plugin->debug.symbols); uint8_t *cursor = (uint8_t *)(plugin->debug.symbols);
max = plugin->debug.syms_num; max = plugin->debug.syms_num;
ctx->symbols = new sp_debug_symbol_t[max]; plugin->symbols = new sp_debug_symbol_t[max];
plugin->jit_memsize += sizeof(sp_debug_symbol_t) * max;
for (iter=0; iter<max; iter++) for (iter=0; iter<max; iter++)
{ {
sym = (sp_fdbg_symbol_t *)cursor; sym = (sp_fdbg_symbol_t *)cursor;
@ -2730,52 +2777,50 @@ jit_rewind:
*/ */
if (sym->codestart > data->codesize) if (sym->codestart > data->codesize)
{ {
ctx->symbols[iter].codestart = 0; plugin->symbols[iter].codestart = 0;
} else { } else {
ctx->symbols[iter].codestart = RelocLookup(jit, sym->codestart, false); plugin->symbols[iter].codestart = RelocLookup(jit, sym->codestart, false);
} }
if (sym->codeend > data->codesize) if (sym->codeend > data->codesize)
{ {
ctx->symbols[iter].codeend = data->codesize; plugin->symbols[iter].codeend = data->codesize;
} else { } else {
ctx->symbols[iter].codeend = RelocLookup(jit, sym->codeend, false); plugin->symbols[iter].codeend = RelocLookup(jit, sym->codeend, false);
} }
ctx->symbols[iter].name = strbase + sym->name; plugin->symbols[iter].name = strbase + sym->name;
ctx->symbols[iter].sym = sym; plugin->symbols[iter].sym = sym;
if (sym->dimcount > 0) if (sym->dimcount > 0)
{ {
cursor += sizeof(sp_fdbg_symbol_t); cursor += sizeof(sp_fdbg_symbol_t);
arr = (sp_fdbg_arraydim_t *)cursor; arr = (sp_fdbg_arraydim_t *)cursor;
ctx->symbols[iter].dims = arr; plugin->symbols[iter].dims = arr;
cursor += sizeof(sp_fdbg_arraydim_t) * sym->dimcount; cursor += sizeof(sp_fdbg_arraydim_t) * sym->dimcount;
continue; continue;
} }
ctx->symbols[iter].dims = NULL; plugin->symbols[iter].dims = NULL;
cursor += sizeof(sp_fdbg_symbol_t); cursor += sizeof(sp_fdbg_symbol_t);
} }
} }
tracker_t *trk = new tracker_t; tracker_t *trk = new tracker_t;
ctx->vm[JITVARS_TRACKER] = trk; ctx->vm[JITVARS_TRACKER] = trk;
ctx->vm[JITVARS_BASECTX] = data->runtime->GetDefaultContext();
ctx->vm[JITVARS_PROFILER] = g_engine2.GetProfiler();
ctx->vm[JITVARS_PLUGIN] = data->runtime->m_pPlugin;
trk->pBase = (ucell_t *)malloc(1024); trk->pBase = (ucell_t *)malloc(1024);
trk->pCur = trk->pBase; trk->pCur = trk->pBase;
trk->size = 1024 / sizeof(cell_t); trk->size = 1024 / sizeof(cell_t);
functracker_t *fnc = new functracker_t; plugin->jit_memsize += trk->size;
ctx->vm[JITVARS_FUNCINFO] = fnc;
ctx->vm[JITVARS_REBASE] = data->rebase;
fnc->code_size = codemem;
fnc->num_functions = data->func_idx;
/* clean up relocation+compilation memory */ /* clean up relocation+compilation memory */
data->rebase = NULL; co->Abort();
AbortCompilation(co);
*err = SP_ERROR_NONE; *err = SP_ERROR_NONE;
return ctx; return true;
} }
SPVM_NATIVE_FUNC JITX86::CreateFakeNative(SPVM_FAKENATIVE_FUNC callback, void *pData) SPVM_NATIVE_FUNC JITX86::CreateFakeNative(SPVM_FAKENATIVE_FUNC callback, void *pData)
@ -2851,126 +2896,149 @@ void JITX86::DestroyFakeNative(SPVM_NATIVE_FUNC func)
engine->FreePageMemory((void *)func); engine->FreePageMemory((void *)func);
} }
const char *JITX86::GetVMName() int JITX86::ContextExecute(sp_plugin_t *pl, sp_context_t *ctx, uint32_t code_idx, cell_t *result)
{
return "JIT (x86)";
}
int JITX86::ContextExecute(sp_context_t *ctx, uint32_t code_idx, cell_t *result)
{ {
typedef int (*CONTEXT_EXECUTE)(sp_context_t *, uint32_t, cell_t *); typedef int (*CONTEXT_EXECUTE)(sp_context_t *, uint32_t, cell_t *);
CONTEXT_EXECUTE fn = (CONTEXT_EXECUTE)ctx->codebase; CONTEXT_EXECUTE fn = (CONTEXT_EXECUTE)pl->codebase;
return fn(ctx, code_idx, result); return fn(ctx, code_idx, result);
} }
void JITX86::FreeContext(sp_context_t *ctx) ICompilation *JITX86::StartCompilation()
{
engine->FreePageMemory(ctx->codebase);
delete [] ctx->memory;
delete [] ctx->files;
delete [] ctx->lines;
delete [] ctx->natives;
delete [] ctx->publics;
delete [] ctx->pubvars;
delete [] ctx->symbols;
engine->BaseFree(ctx->vm[JITVARS_REBASE]);
free(((tracker_t *)(ctx->vm[JITVARS_TRACKER]))->pBase);
delete (tracker_t *)ctx->vm[JITVARS_TRACKER];
delete (functracker_t *)ctx->vm[JITVARS_FUNCINFO];
delete ctx;
}
ICompilation *JITX86::StartCompilation(sp_plugin_t *plugin)
{ {
CompData *data = new CompData; CompData *data = new CompData;
data->jit_float_table = NULL;
return data;
}
void CompData::SetRuntime(BaseRuntime *runtime)
{
plugin = runtime->m_pPlugin;
uint32_t max_natives = plugin->info.natives_num; uint32_t max_natives = plugin->info.natives_num;
const char *strbase = plugin->info.stringbase; const char *strbase = plugin->info.stringbase;
data->plugin = plugin; this->runtime = runtime;
data->inline_level = JIT_INLINE_ERRORCHECKS|JIT_INLINE_NATIVES;
data->error_set = SP_ERROR_NONE;
data->jit_float_table = new floattbl_t[max_natives]; inline_level = JIT_INLINE_ERRORCHECKS|JIT_INLINE_NATIVES;
error_set = SP_ERROR_NONE;
jit_float_table = new floattbl_t[max_natives];
for (uint32_t i=0; i<max_natives; i++) for (uint32_t i=0; i<max_natives; i++)
{ {
const char *name = strbase + plugin->info.natives[i].name; const char *name = strbase + plugin->info.natives[i].name;
if (!strcmp(name, "FloatAbs")) if (!strcmp(name, "FloatAbs"))
{ {
data->jit_float_table[i].found = true; jit_float_table[i].found = true;
data->jit_float_table[i].index = OP_FABS; jit_float_table[i].index = OP_FABS;
} else if (!strcmp(name, "FloatAdd")) { } else if (!strcmp(name, "FloatAdd")) {
data->jit_float_table[i].found = true; jit_float_table[i].found = true;
data->jit_float_table[i].index = OP_FLOATADD; jit_float_table[i].index = OP_FLOATADD;
} else if (!strcmp(name, "FloatSub")) { } else if (!strcmp(name, "FloatSub")) {
data->jit_float_table[i].found = true; jit_float_table[i].found = true;
data->jit_float_table[i].index = OP_FLOATSUB; jit_float_table[i].index = OP_FLOATSUB;
} else if (!strcmp(name, "FloatMul")) { } else if (!strcmp(name, "FloatMul")) {
data->jit_float_table[i].found = true; jit_float_table[i].found = true;
data->jit_float_table[i].index = OP_FLOATMUL; jit_float_table[i].index = OP_FLOATMUL;
} else if (!strcmp(name, "FloatDiv")) { } else if (!strcmp(name, "FloatDiv")) {
data->jit_float_table[i].found = true; jit_float_table[i].found = true;
data->jit_float_table[i].index = OP_FLOATDIV; jit_float_table[i].index = OP_FLOATDIV;
} else if (!strcmp(name, "float")) { } else if (!strcmp(name, "float")) {
data->jit_float_table[i].found = true; jit_float_table[i].found = true;
data->jit_float_table[i].index = OP_FLOAT; jit_float_table[i].index = OP_FLOAT;
} else if (!strcmp(name, "FloatCompare")) { } else if (!strcmp(name, "FloatCompare")) {
data->jit_float_table[i].found = true; jit_float_table[i].found = true;
data->jit_float_table[i].index = OP_FLOATCMP; jit_float_table[i].index = OP_FLOATCMP;
} else if (!strcmp(name, "RoundToZero")) { } else if (!strcmp(name, "RoundToZero")) {
data->jit_float_table[i].found = true; jit_float_table[i].found = true;
data->jit_float_table[i].index = OP_RND_TO_ZERO; jit_float_table[i].index = OP_RND_TO_ZERO;
} else if (!strcmp(name, "RoundToCeil")) { } else if (!strcmp(name, "RoundToCeil")) {
data->jit_float_table[i].found = true; jit_float_table[i].found = true;
data->jit_float_table[i].index = OP_RND_TO_CEIL; jit_float_table[i].index = OP_RND_TO_CEIL;
} else if (!strcmp(name, "RoundToFloor")) { } else if (!strcmp(name, "RoundToFloor")) {
data->jit_float_table[i].found = true; jit_float_table[i].found = true;
data->jit_float_table[i].index = OP_RND_TO_FLOOR; jit_float_table[i].index = OP_RND_TO_FLOOR;
} else if (!strcmp(name, "RoundToNearest")) { } else if (!strcmp(name, "RoundToNearest")) {
data->jit_float_table[i].found = true; jit_float_table[i].found = true;
data->jit_float_table[i].index = OP_RND_TO_NEAREST; jit_float_table[i].index = OP_RND_TO_NEAREST;
} }
} }
}
ICompilation *JITX86::StartCompilation(BaseRuntime *runtime)
{
CompData *data = new CompData;
data->SetRuntime(runtime);
return data; return data;
} }
void JITX86::AbortCompilation(ICompilation *co) void CompData::Abort()
{ {
if (((CompData *)co)->rebase) if (rebase)
{ {
engine->BaseFree(((CompData *)co)->rebase); engine->BaseFree(rebase);
} }
delete [] ((CompData *)co)->jit_float_table; delete [] jit_float_table;
delete (CompData *)co; delete this;
} }
bool JITX86::SetCompilationOption(ICompilation *co, const char *key, const char *val) void JITX86::FreeContextVars(sp_context_t *ctx)
{ {
CompData *data = (CompData *)co; free(((tracker_t *)(ctx->vm[JITVARS_TRACKER]))->pBase);
delete (tracker_t *)ctx->vm[JITVARS_TRACKER];
}
void JITX86::FreePluginVars(sp_plugin_t *pl)
{
delete [] pl->files;
delete [] pl->lines;
delete [] pl->natives;
delete [] pl->publics;
delete [] pl->pubvars;
delete [] pl->symbols;
if (pl->codebase != NULL)
{
g_engine1.FreePageMemory(pl->codebase);
pl->codebase = NULL;
}
pl->files = NULL;
pl->lines = NULL;
pl->natives = NULL;
pl->publics = NULL;
pl->pubvars = NULL;
pl->symbols = NULL;
}
bool CompData::SetOption(const char *key, const char *val)
{
if (strcmp(key, SP_JITCONF_DEBUG) == 0) if (strcmp(key, SP_JITCONF_DEBUG) == 0)
{ {
if ((atoi(val) == 1) || !strcmp(val, "yes")) if ((atoi(val) == 1) || !strcmp(val, "yes"))
{ {
data->debug = true; debug = true;
} else { } else {
data->debug = false; debug = false;
} }
if (data->debug && !(data->plugin->flags & SP_FLAG_DEBUG)) if (debug && plugin && !(plugin->flags & SP_FLAG_DEBUG))
{ {
data->debug = false; debug = false;
return false; return false;
} }
return true; return true;
} }
else if (strcmp(key, SP_JITCONF_PROFILE) == 0) else if (strcmp(key, SP_JITCONF_PROFILE) == 0)
{ {
data->profile = atoi(val); profile = atoi(val);
/** Callbacks must be profiled to profile functions! */ /** Callbacks must be profiled to profile functions! */
if ((data->profile & SP_PROF_FUNCTIONS) == SP_PROF_FUNCTIONS) if ((profile & SP_PROF_FUNCTIONS) == SP_PROF_FUNCTIONS)
{ {
data->profile |= SP_PROF_CALLBACKS; profile |= SP_PROF_CALLBACKS;
} }
return true; return true;
@ -2979,83 +3047,3 @@ bool JITX86::SetCompilationOption(ICompilation *co, const char *key, const char
return false; return false;
} }
unsigned int JITX86::GetAPIVersion()
{
return SOURCEPAWN_VM_API_VERSION;
}
bool JITX86::FunctionPLookup(const sp_context_t *ctx, uint32_t code_addr, unsigned int *result)
{
uint8_t *rebase = (uint8_t *)ctx->vm[JITVARS_REBASE];
/* Is this within the pcode bounds? */
if (code_addr >= ctx->plugin->pcode_size - sizeof(uint32_t))
{
return false;
}
/* Relocate this */
code_addr = *(jitoffs_t *)(rebase + code_addr);
/* Check if this is in the relocation bounds */
functracker_t *fnc = (functracker_t *)ctx->vm[JITVARS_FUNCINFO];
if (code_addr >= fnc->code_size)
{
return false;
}
/* Get the function info and sanity check */
funcinfo_t *f = (funcinfo_t *)((char *)ctx->codebase + code_addr - sizeof(funcinfo_t));
if (f->magic != JIT_FUNCMAGIC || f->index >= fnc->num_functions)
{
return false;
}
if (result)
{
*result = f->index;
}
return true;
}
bool JITX86::FunctionLookup(const sp_context_t *ctx, uint32_t code_addr, unsigned int *result)
{
/* Check if this is in the relocation bounds */
functracker_t *fnc = (functracker_t *)ctx->vm[JITVARS_FUNCINFO];
if (code_addr >= fnc->code_size)
{
return false;
}
/* Get the function info and sanity check */
funcinfo_t *f = (funcinfo_t *)((char *)ctx->codebase + code_addr - sizeof(funcinfo_t));
if (f->magic != JIT_FUNCMAGIC || f->index >= fnc->num_functions)
{
return false;
}
if (result)
{
*result = f->index;
}
return true;
}
unsigned int JITX86::FunctionCount(const sp_context_t *ctx)
{
functracker_t *fnc = (functracker_t *)ctx->vm[JITVARS_FUNCINFO];
return fnc->num_functions;
}
const char *JITX86::GetVersionString()
{
return SVN_FULL_VERSION;
}
const char *JITX86::GetCPUOptimizations()
{
return "Generic i686";
}

View File

@ -35,6 +35,8 @@
#include <sp_vm_types.h> #include <sp_vm_types.h>
#include <sp_vm_api.h> #include <sp_vm_api.h>
#include <jit_helpers.h> #include <jit_helpers.h>
#include "../jit_shared.h"
#include "../BaseRuntime.h"
using namespace SourcePawn; using namespace SourcePawn;
@ -44,11 +46,14 @@ using namespace SourcePawn;
#define JIT_FUNCMAGIC 0x214D4148 //magic function offset #define JIT_FUNCMAGIC 0x214D4148 //magic function offset
#define JITVARS_TRACKER 0 //important: don't change this to avoid trouble #define JITVARS_TRACKER 0 //important: don't change this to avoid trouble
#define JITVARS_FUNCINFO 1 //important: don't change this aWOAWOGJQG I LIKE HAM #define JITVARS_BASECTX 1 //important: don't change this aWOAWOGJQG I LIKE HAM
#define JITVARS_REBASE 2 //important: hi, i'm bail #define JITVARS_PROFILER 2 //profiler
#define JITVARS_PLUGIN 3 //sp_plugin_t
#define sDIMEN_MAX 5 //this must mirror what the compiler has. #define sDIMEN_MAX 5 //this must mirror what the compiler has.
#define GET_CONTEXT(c) ((IPluginContext *)c->vm[JITVARS_BASECTX])
typedef struct tracker_s typedef struct tracker_s
{ {
size_t size; size_t size;
@ -87,7 +92,11 @@ public:
error_set(SP_ERROR_NONE), func_idx(0) error_set(SP_ERROR_NONE), func_idx(0)
{ {
}; };
bool SetOption(const char *key, const char *val);
void SetRuntime(BaseRuntime *runtime);
void Abort();
public: public:
BaseRuntime *runtime; /* runtime handle */
sp_plugin_t *plugin; /* plugin handle */ sp_plugin_t *plugin; /* plugin handle */
bool debug; /* whether to compile debug mode */ bool debug; /* whether to compile debug mode */
int profile; /* profiling flags */ int profile; /* profiling flags */
@ -116,22 +125,15 @@ public:
uint32_t codesize; /* total codesize */ uint32_t codesize; /* total codesize */
}; };
class JITX86 : public IVirtualMachine class JITX86
{ {
public: public:
const char *GetVMName(); ICompilation *StartCompilation(BaseRuntime *runtime);
ICompilation *StartCompilation(sp_plugin_t *plugin); ICompilation *StartCompilation();
bool SetCompilationOption(ICompilation *co, const char *key, const char *val); bool Compile(ICompilation *co, BaseRuntime *runtime, int *err);
sp_context_t *CompileToContext(ICompilation *co, int *err); void FreePluginVars(sp_plugin_t *pl);
void AbortCompilation(ICompilation *co); void FreeContextVars(sp_context_t *ctx);
void FreeContext(sp_context_t *ctx); int ContextExecute(sp_plugin_t *pl, sp_context_t *ctx, uint32_t code_idx, cell_t *result);
int ContextExecute(sp_context_t *ctx, uint32_t code_idx, cell_t *result);
unsigned int GetAPIVersion();
bool FunctionLookup(const sp_context_t *ctx, uint32_t code_addr, unsigned int *result);
bool FunctionPLookup(const sp_context_t *ctx, uint32_t code_addr, unsigned int *result);
unsigned int FunctionCount(const sp_context_t *ctx);
const char *GetVersionString();
const char *GetCPUOptimizations();
SPVM_NATIVE_FUNC CreateFakeNative(SPVM_FAKENATIVE_FUNC callback, void *pData); SPVM_NATIVE_FUNC CreateFakeNative(SPVM_FAKENATIVE_FUNC callback, void *pData);
void DestroyFakeNative(SPVM_NATIVE_FUNC func); void DestroyFakeNative(SPVM_NATIVE_FUNC func);
}; };
@ -157,6 +159,6 @@ jitoffs_t RelocLookup(JitWriter *jit, cell_t pcode_offs, bool relative=false);
#define AMX_INFO_CONTEXT 12 //physical #define AMX_INFO_CONTEXT 12 //physical
#define AMX_INFO_STACKTOP 16 //relocated #define AMX_INFO_STACKTOP 16 //relocated
extern ISourcePawnEngine *engine; extern JITX86 g_Jit1;
#endif //_INCLUDE_SOURCEPAWN_JIT_X86_H_ #endif //_INCLUDE_SOURCEPAWN_JIT_X86_H_

View File

@ -40,6 +40,7 @@
jitoffs_t Write_Execute_Function(JitWriter *jit) jitoffs_t Write_Execute_Function(JitWriter *jit)
{ {
CompData *co = (CompData *)jit->data;
/** /**
* The variables we're passed in: * The variables we're passed in:
* sp_context_t *ctx, uint32_t code_idx, cell_t *result * sp_context_t *ctx, uint32_t code_idx, cell_t *result
@ -76,14 +77,14 @@ jitoffs_t Write_Execute_Function(JitWriter *jit)
//mov [esi+12], eax - store context into info pointer //mov [esi+12], eax - store context into info pointer
//mov ecx, [eax+<offs>] - get heap pointer //mov ecx, [eax+<offs>] - get heap pointer
//mov [esi+4], ecx - store heap into info pointer //mov [esi+4], ecx - store heap into info pointer
//mov ebp, [eax+<offs>] - get data pointer //mov ebp, <addr> - get data pointer
IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, REG_EBP, 16); IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, REG_EBP, 16);
IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_EAX, AMX_INFO_RETVAL); IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_EAX, AMX_INFO_RETVAL);
IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, REG_EBP, 8); IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, REG_EBP, 8);
IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_EAX, AMX_INFO_CONTEXT); IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_EAX, AMX_INFO_CONTEXT);
IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, REG_EAX, offsetof(sp_context_t, hp)); IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, REG_EAX, offsetof(sp_context_t, hp));
IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_ECX, AMX_INFO_HEAP); IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_ECX, AMX_INFO_HEAP);
IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_DAT, REG_EAX, offsetof(sp_context_t, memory)); IA32_Mov_Reg_Imm32(jit, AMX_REG_DAT, jit_int32_t(co->plugin->memory));
/* Frame setup */ /* Frame setup */
//mov edi, [eax+<offs>] - get stack pointer //mov edi, [eax+<offs>] - get stack pointer
@ -97,15 +98,23 @@ jitoffs_t Write_Execute_Function(JitWriter *jit)
//mov ecx, [eax+<offs>] - copy memsize to temp var //mov ecx, [eax+<offs>] - copy memsize to temp var
//add ecx, ebp - relocate //add ecx, ebp - relocate
//mov [esi+x], ecx - store relocated //mov [esi+x], ecx - store relocated
IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, REG_EAX, offsetof(sp_context_t, mem_size)); IA32_Mov_Reg_Imm32(jit, REG_ECX, co->plugin->mem_size);
IA32_Add_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_DAT, MOD_REG); IA32_Add_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_DAT, MOD_REG);
IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_ECX, AMX_INFO_STACKTOP); IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_ECX, AMX_INFO_STACKTOP);
/* Remaining needed vars */ /* Remaining needed vars */
//mov ecx, [esp+(4*(NUM_INFO_PARAMS+3))+12] - get code index (normally esp+12, but we have another array on the stack) //mov ecx, [esp+(4*(NUM_INFO_PARAMS+3))+12] - get code index (normally esp+12, but we have another array on the stack)
//add ecx, [eax+<offs>] - add code base to index //push eax
//mov eax, <addr of addr of code>
//mov eax, [eax]
//add ecx, eax
//pop eax
IA32_Mov_Reg_Esp_Disp8(jit, REG_ECX, 12+(4*(NUM_INFO_PARAMS+3))); IA32_Mov_Reg_Esp_Disp8(jit, REG_ECX, 12+(4*(NUM_INFO_PARAMS+3)));
IA32_Add_Reg_Rm_Disp8(jit, REG_ECX, REG_EAX, offsetof(sp_context_t, codebase)); IA32_Push_Reg(jit, REG_EAX);
IA32_Mov_Reg_Imm32(jit, REG_EAX, jit_int32_t(&co->plugin->codebase));
IA32_Mov_Reg_Rm(jit, REG_EAX, REG_EAX, MOD_MEM_REG);
IA32_Add_Reg_Rm(jit, REG_ECX, REG_EAX, MOD_REG);
IA32_Pop_Reg(jit, REG_EAX);
/* by now, everything is set up, so we can call into the plugin */ /* by now, everything is set up, so we can call into the plugin */
//call ecx //call ecx
@ -161,36 +170,30 @@ void Write_BreakDebug(JitWriter *jit)
//push edi //push edi
//mov edi, ecx //mov edi, ecx
//mov ecx, [esi+ctx] //mov ecx, [esi+ctx]
//cmp [ecx+dbreak], 0
//jnz :nocall
IA32_Push_Reg(jit, REG_EDI); IA32_Push_Reg(jit, REG_EDI);
IA32_Mov_Reg_Rm(jit, REG_EDI, REG_ECX, MOD_REG); IA32_Mov_Reg_Rm(jit, REG_EDI, REG_ECX, MOD_REG);
IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_CONTEXT); IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_CONTEXT);
IA32_Cmp_Rm_Disp8_Imm8(jit, AMX_REG_TMP, offsetof(sp_context_t, dbreak), 0);
jitoffs_t jmp = IA32_Jump_Cond_Imm8(jit, CC_Z, 0);
//:TODO: align the stack to 16bytes like in sysreq.x //:TODO: align the stack to 16bytes like in sysreq.x
/* NOTE, Hack! PUSHAD pushes EDI last which still has the CIP */ /* NOTE, Hack! PUSHAD pushes EDI last which still has the CIP */
//pushad //pushad
//push [esi+frm] //push [esi+frm]
//push ctx //push [ctx+basectx]
//mov ecx, [ecx+dbreak] //mov ecx, <dbreak>
//call ecx //call ecx
//add esp, 8 //add esp, 8
//popad //popad
IA32_Pushad(jit); IA32_Pushad(jit);
IA32_Push_Rm_Disp8(jit, AMX_REG_INFO, AMX_INFO_FRAME); //:TODO: move to regs and push? and dont disp for 0 IA32_Push_Rm_Disp8(jit, AMX_REG_INFO, AMX_INFO_FRAME); //:TODO: move to regs and push? and dont disp for 0
IA32_Push_Reg(jit, AMX_REG_TMP); IA32_Push_Rm_Disp8(jit, AMX_REG_TMP, offsetof(sp_context_t, vm[JITVARS_BASECTX]));
IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_TMP, offsetof(sp_context_t, dbreak)); IA32_Mov_Reg_Imm32(jit, AMX_REG_TMP, jit_int32_t(((CompData *)jit->data)->plugin->dbreak));
IA32_Call_Reg(jit, AMX_REG_TMP); IA32_Call_Reg(jit, AMX_REG_TMP);
IA32_Add_Rm_Imm8(jit, REG_ESP, 4*2, MOD_REG); IA32_Add_Rm_Imm8(jit, REG_ESP, 4*2, MOD_REG);
IA32_Popad(jit); IA32_Popad(jit);
//:nocall
//pop edi //pop edi
//ret //ret
IA32_Pop_Reg(jit, REG_EDI); IA32_Pop_Reg(jit, REG_EDI);
IA32_Send_Jump8_Here(jit, jmp);
IA32_Return(jit); IA32_Return(jit);
} }
@ -314,7 +317,7 @@ void Write_Check_VerifyAddr(JitWriter *jit, jit_uint8_t reg)
/* Part 1: Check if we're in the memory bounds */ /* Part 1: Check if we're in the memory bounds */
//cmp <reg>, <stpu> //cmp <reg>, <stpu>
//jae :error //jae :error
IA32_Cmp_Rm_Imm32(jit, MOD_REG, reg, ((CompData *)jit->data)->plugin->memory); IA32_Cmp_Rm_Imm32(jit, MOD_REG, reg, ((CompData *)jit->data)->plugin->mem_size);
IA32_Jump_Cond_Imm32_Abs(jit, CC_AE, ((CompData *)jit->data)->jit_error_memaccess); IA32_Jump_Cond_Imm32_Abs(jit, CC_AE, ((CompData *)jit->data)->jit_error_memaccess);
/* Part 2: Check if we're in the invalid region between HP and SP */ /* Part 2: Check if we're in the invalid region between HP and SP */