From 1a156deca5d0636ebff692dd2e1292dfa97cac4d Mon Sep 17 00:00:00 2001 From: David Anderson Date: Fri, 11 Jul 2008 08:18:43 +0000 Subject: [PATCH] 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 --- core/DebugReporter.cpp | 9 +- core/Makefile | 16 +- core/msvc8/sourcemod_mm.vcproj | 208 +-- core/sm_globals.h | 2 +- core/sm_srvcmds.cpp | 4 +- core/smn_console.cpp | 12 +- core/smn_core.cpp | 16 +- core/smn_fakenatives.cpp | 9 +- core/smn_filesystem.cpp | 10 +- core/smn_halflife.cpp | 6 +- core/smn_hudtext.cpp | 4 +- core/smn_player.cpp | 20 +- core/smn_string.cpp | 3 +- core/sourcemod.cpp | 113 +- core/systems/HandleSys.cpp | 2 +- core/systems/PluginSys.cpp | 269 ++-- core/systems/PluginSys.h | 38 +- core/systems/ShareSys.cpp | 2 +- core/vm/sp_vm_basecontext.cpp | 1120 ----------------- core/vm/sp_vm_basecontext.h | 124 -- public/IPluginSys.h | 19 +- public/ISourceMod.h | 4 +- public/sourcepawn/sp_vm_api.h | 651 ++++++---- public/sourcepawn/sp_vm_base.h | 3 - public/sourcepawn/sp_vm_types.h | 98 +- sourcepawn/jit/BaseRuntime.cpp | 357 ++++++ sourcepawn/jit/BaseRuntime.h | 60 + sourcepawn/jit/{x86 => }/Makefile | 33 +- sourcepawn/jit/{x86 => }/dll_exports.cpp | 39 +- sourcepawn/jit/{x86 => }/dll_exports.h | 0 sourcepawn/jit/engine2.cpp | 278 ++++ sourcepawn/jit/engine2.h | 35 + sourcepawn/jit/jit_shared.h | 95 ++ sourcepawn/jit/{x86 => }/jit_version.h | 0 sourcepawn/jit/{x86 => }/jit_version.tpl | 0 sourcepawn/jit/{x86 => }/msvc8/jit-x86.sln | 0 sourcepawn/jit/{x86 => }/msvc8/jit-x86.vcproj | 128 +- sourcepawn/jit/sp_vm_basecontext.cpp | 810 ++++++++++++ sourcepawn/jit/sp_vm_basecontext.h | 114 ++ {core/vm => sourcepawn/jit}/sp_vm_engine.cpp | 282 +---- {core/vm => sourcepawn/jit}/sp_vm_engine.h | 13 +- .../vm => sourcepawn/jit}/sp_vm_function.cpp | 105 +- {core/vm => sourcepawn/jit}/sp_vm_function.h | 35 +- sourcepawn/jit/{x86 => }/version.rc | 0 sourcepawn/jit/x86/jit_x86.cpp | 420 +++---- sourcepawn/jit/x86/jit_x86.h | 36 +- sourcepawn/jit/x86/opcode_helpers.cpp | 35 +- {core => sourcepawn/jit}/zlib/adler32.c | 0 {core => sourcepawn/jit}/zlib/compress.c | 0 {core => sourcepawn/jit}/zlib/crc32.c | 0 {core => sourcepawn/jit}/zlib/crc32.h | 0 {core => sourcepawn/jit}/zlib/deflate.c | 0 {core => sourcepawn/jit}/zlib/deflate.h | 0 {core => sourcepawn/jit}/zlib/gzio.c | 0 {core => sourcepawn/jit}/zlib/infback.c | 0 {core => sourcepawn/jit}/zlib/inffast.c | 0 {core => sourcepawn/jit}/zlib/inffast.h | 0 {core => sourcepawn/jit}/zlib/inffixed.h | 0 {core => sourcepawn/jit}/zlib/inflate.c | 0 {core => sourcepawn/jit}/zlib/inflate.h | 0 {core => sourcepawn/jit}/zlib/inftrees.c | 0 {core => sourcepawn/jit}/zlib/inftrees.h | 0 {core => sourcepawn/jit}/zlib/trees.c | 0 {core => sourcepawn/jit}/zlib/trees.h | 0 {core => sourcepawn/jit}/zlib/uncompr.c | 0 {core => sourcepawn/jit}/zlib/zconf.h | 0 {core => sourcepawn/jit}/zlib/zlib.h | 0 {core => sourcepawn/jit}/zlib/zutil.c | 0 {core => sourcepawn/jit}/zlib/zutil.h | 0 69 files changed, 2836 insertions(+), 2801 deletions(-) delete mode 100644 core/vm/sp_vm_basecontext.cpp delete mode 100644 core/vm/sp_vm_basecontext.h create mode 100644 sourcepawn/jit/BaseRuntime.cpp create mode 100644 sourcepawn/jit/BaseRuntime.h rename sourcepawn/jit/{x86 => }/Makefile (70%) rename sourcepawn/jit/{x86 => }/dll_exports.cpp (71%) rename sourcepawn/jit/{x86 => }/dll_exports.h (100%) create mode 100644 sourcepawn/jit/engine2.cpp create mode 100644 sourcepawn/jit/engine2.h create mode 100644 sourcepawn/jit/jit_shared.h rename sourcepawn/jit/{x86 => }/jit_version.h (100%) rename sourcepawn/jit/{x86 => }/jit_version.tpl (100%) rename sourcepawn/jit/{x86 => }/msvc8/jit-x86.sln (100%) rename sourcepawn/jit/{x86 => }/msvc8/jit-x86.vcproj (68%) create mode 100644 sourcepawn/jit/sp_vm_basecontext.cpp create mode 100644 sourcepawn/jit/sp_vm_basecontext.h rename {core/vm => sourcepawn/jit}/sp_vm_engine.cpp (55%) rename {core/vm => sourcepawn/jit}/sp_vm_engine.h (91%) rename {core/vm => sourcepawn/jit}/sp_vm_function.cpp (74%) rename {core/vm => sourcepawn/jit}/sp_vm_function.h (85%) rename sourcepawn/jit/{x86 => }/version.rc (100%) rename {core => sourcepawn/jit}/zlib/adler32.c (100%) rename {core => sourcepawn/jit}/zlib/compress.c (100%) rename {core => sourcepawn/jit}/zlib/crc32.c (100%) rename {core => sourcepawn/jit}/zlib/crc32.h (100%) rename {core => sourcepawn/jit}/zlib/deflate.c (100%) rename {core => sourcepawn/jit}/zlib/deflate.h (100%) rename {core => sourcepawn/jit}/zlib/gzio.c (100%) rename {core => sourcepawn/jit}/zlib/infback.c (100%) rename {core => sourcepawn/jit}/zlib/inffast.c (100%) rename {core => sourcepawn/jit}/zlib/inffast.h (100%) rename {core => sourcepawn/jit}/zlib/inffixed.h (100%) rename {core => sourcepawn/jit}/zlib/inflate.c (100%) rename {core => sourcepawn/jit}/zlib/inflate.h (100%) rename {core => sourcepawn/jit}/zlib/inftrees.c (100%) rename {core => sourcepawn/jit}/zlib/inftrees.h (100%) rename {core => sourcepawn/jit}/zlib/trees.c (100%) rename {core => sourcepawn/jit}/zlib/trees.h (100%) rename {core => sourcepawn/jit}/zlib/uncompr.c (100%) rename {core => sourcepawn/jit}/zlib/zconf.h (100%) rename {core => sourcepawn/jit}/zlib/zlib.h (100%) rename {core => sourcepawn/jit}/zlib/zutil.c (100%) rename {core => sourcepawn/jit}/zlib/zutil.h (100%) diff --git a/core/DebugReporter.cpp b/core/DebugReporter.cpp index d86fa111..ed8a6bd2 100644 --- a/core/DebugReporter.cpp +++ b/core/DebugReporter.cpp @@ -36,11 +36,6 @@ 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() { g_pSourcePawn->SetDebugListener(this); @@ -56,7 +51,7 @@ void DebugReport::GenerateError(IPluginContext *ctx, cell_t func_idx, int err, c va_end(ap); const char *plname = g_PluginSys.FindPluginByContext(ctx->GetContext())->GetFilename(); - const char *error = GetSourcePawnErrorMessage(err); + const char *error = g_pSourcePawn2->GetErrorString(err); if (error) { @@ -91,7 +86,7 @@ void DebugReport::GenerateCodeError(IPluginContext *pContext, uint32_t code_addr va_end(ap); const char *plname = g_PluginSys.FindPluginByContext(pContext->GetContext())->GetFilename(); - const char *error = GetSourcePawnErrorMessage(err); + const char *error = g_pSourcePawn2->GetErrorString(err); if (error) { diff --git a/core/Makefile b/core/Makefile index ef2e9d9e..b31c3e2d 100644 --- a/core/Makefile +++ b/core/Makefile @@ -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 OBJECTS += systems/ExtensionSys.cpp systems/ForwardSys.cpp systems/HandleSys.cpp \ systems/LibrarySys.cpp systems/PluginInfoDatabase.cpp systems/PluginSys.cpp \ - systems/ShareSys.cpp vm/sp_vm_basecontext.cpp vm/sp_vm_engine.cpp \ - vm/sp_vm_function.cpp + systems/ShareSys.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 ### @@ -103,13 +99,9 @@ ifeq "$(GCC_VERSION)" "4" CPPFLAGS += $(CPP_GCC4_FLAGS) endif -OBJ_LINUX := $(OBJECTS:%vm_engine.cpp=$(BIN_DIR)/%vm_engine.o) -OBJ_LINUX := $(OBJ_LINUX:%.cpp=$(BIN_DIR)/%.o) +OBJ_LINUX := $(OBJECTS:%.cpp=$(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 $(CPP) $(INCLUDE) $(CFLAGS) $(CPPFLAGS) -o $@ -c $< @@ -118,8 +110,6 @@ $(BIN_DIR)/%.o: %.c all: check mkdir -p $(BIN_DIR)/systems - mkdir -p $(BIN_DIR)/vm - mkdir -p $(BIN_DIR)/zlib mkdir -p $(BIN_DIR)/thread ln -sf $(SRCDS)/bin/vstdlib_i486.so vstdlib_i486.so; ln -sf $(SRCDS)/bin/tier0_i486.so tier0_i486.so; @@ -142,7 +132,5 @@ default: all clean: check rm -rf $(BIN_DIR)/*.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)/$(BINARY) diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index a935712f..fcfc7357 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -1358,204 +1358,26 @@ Name="SourcePawn" UniqueIdentifier="{C3C3DC6E-E392-4916-B893-7ACB92192DE0}" > - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - + GetVMName(), g_pVM->GetVersionString()); - ConsolePrint(" JIT Settings: %s", g_pVM->GetCPUOptimizations()); + ConsolePrint(" SourcePawn Engine: %s (build %s)", g_pSourcePawn2->GetEngineName(), g_pSourcePawn2->GetVersionString()); + ConsolePrint(" SourcePawn API: v1 = %d, v2 = %d", g_pSourcePawn->GetEngineAPIVersion(), g_pSourcePawn2->GetAPIVersion()); ConsolePrint(" Compiled on: %s %s", __DATE__, __TIME__); ConsolePrint(" http://www.sourcemod.net/"); } diff --git a/core/smn_console.cpp b/core/smn_console.cpp index c635a339..7dded75e 100644 --- a/core/smn_console.cpp +++ b/core/smn_console.cpp @@ -833,7 +833,7 @@ static cell_t sm_ServerCommand(IPluginContext *pContext, const cell_t *params) char buffer[1024]; 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; } @@ -854,7 +854,7 @@ static cell_t sm_InsertServerCommand(IPluginContext *pContext, const cell_t *par char buffer[1024]; 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; } @@ -894,7 +894,7 @@ static cell_t sm_ClientCommand(IPluginContext *pContext, const cell_t *params) char buffer[256]; 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; } @@ -921,7 +921,7 @@ static cell_t FakeClientCommand(IPluginContext *pContext, const cell_t *params) char buffer[256]; 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; } @@ -948,7 +948,7 @@ static cell_t FakeClientCommandEx(IPluginContext *pContext, const cell_t *params char buffer[256]; 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; } @@ -966,7 +966,7 @@ static cell_t ReplyToCommand(IPluginContext *pContext, const cell_t *params) char buffer[1024]; 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; } diff --git a/core/smn_core.cpp b/core/smn_core.cpp index 78d18ebd..84692bca 100644 --- a/core/smn_core.cpp +++ b/core/smn_core.cpp @@ -130,7 +130,7 @@ static cell_t ThrowError(IPluginContext *pContext, const cell_t *params) 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); } @@ -387,7 +387,7 @@ static cell_t SetFailState(IPluginContext *pContext, const cell_t *params) char buffer[2048]; 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); 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; uint32_t idx; - sp_context_t *ctx = pContext->GetContext(); + sp_native_t *native; pContext->LocalToString(params[1], &name); if (pContext->FindNativeByName(name, &idx) != SP_ERROR_NONE) @@ -464,7 +464,9 @@ static cell_t MarkNativeAsOptional(IPluginContext *pContext, const cell_t *param return 0; } - ctx->natives[idx].flags |= SP_NTVFLAG_OPTIONAL; + pContext->GetNativeByIndex(idx, &native); + + native->flags |= SP_NTVFLAG_OPTIONAL; 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.FormatString(buffer, sizeof(buffer), pContext, params, 3); - if (pContext->GetContext()->n_err != SP_ERROR_NONE) + if (pContext->GetLastNativeError() != SP_ERROR_NONE) { return 0; } @@ -535,7 +537,7 @@ static cell_t LogToFile(IPluginContext *pContext, const cell_t *params) g_SourceMod.SetGlobalTarget(SOURCEMOD_SERVER_LANGUAGE); 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); return 0; @@ -568,7 +570,7 @@ static cell_t LogToFileEx(IPluginContext *pContext, const cell_t *params) g_SourceMod.SetGlobalTarget(SOURCEMOD_SERVER_LANGUAGE); 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); return 0; diff --git a/core/smn_fakenatives.cpp b/core/smn_fakenatives.cpp index 5e1fd71b..f5c3c24c 100644 --- a/core/smn_fakenatives.cpp +++ b/core/smn_fakenatives.cpp @@ -54,8 +54,7 @@ cell_t FakeNativeRouter(IPluginContext *pContext, const cell_t *params, void *pD } /* Check if the native is paused */ - sp_context_t *pNativeCtx = native->ctx->GetContext(); - if ((pNativeCtx->flags & SPFLAG_PLUGIN_PAUSED) == SPFLAG_PLUGIN_PAUSED) + if (native->ctx->GetRuntime()->IsPaused()) { 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; 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"); } @@ -146,7 +145,7 @@ static cell_t ThrowNativeError(IPluginContext *pContext, const cell_t *params) 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"); } else { @@ -434,7 +433,7 @@ static cell_t FormatNativeString(IPluginContext *pContext, const cell_t *params) pContext->LocalToPhysAddr(params[5], &addr); *addr = (cell_t)written; - return s_curcaller->GetContext()->n_err; + return s_curcaller->GetLastNativeError(); } //tee hee diff --git a/core/smn_filesystem.cpp b/core/smn_filesystem.cpp index 9870d6a6..74f3aa8c 100644 --- a/core/smn_filesystem.cpp +++ b/core/smn_filesystem.cpp @@ -573,7 +573,7 @@ static cell_t sm_LogToGame(IPluginContext *pContext, const cell_t *params) char buffer[1024]; 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; } @@ -599,7 +599,7 @@ static cell_t sm_LogMessage(IPluginContext *pContext, const cell_t *params) char buffer[1024]; 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; } @@ -617,7 +617,7 @@ static cell_t sm_LogError(IPluginContext *pContext, const cell_t *params) char buffer[1024]; 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; } @@ -670,7 +670,7 @@ static cell_t sm_LogToOpenFile(IPluginContext *pContext, const cell_t *params) g_SourceMod.SetGlobalTarget(SOURCEMOD_SERVER_LANGUAGE); 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; } @@ -701,7 +701,7 @@ static cell_t sm_LogToOpenFileEx(IPluginContext *pContext, const cell_t *params) g_SourceMod.SetGlobalTarget(SOURCEMOD_SERVER_LANGUAGE); 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; } diff --git a/core/smn_halflife.cpp b/core/smn_halflife.cpp index d34d6732..40590d94 100644 --- a/core/smn_halflife.cpp +++ b/core/smn_halflife.cpp @@ -289,7 +289,7 @@ static cell_t PrintToChat(IPluginContext *pContext, const cell_t *params) g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2); /* 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; } @@ -323,7 +323,7 @@ static cell_t PrintCenterText(IPluginContext *pContext, const cell_t *params) g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2); /* 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; } @@ -357,7 +357,7 @@ static cell_t PrintHintText(IPluginContext *pContext, const cell_t *params) g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2); /* 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; } diff --git a/core/smn_hudtext.cpp b/core/smn_hudtext.cpp index 01426830..a5d98769 100644 --- a/core/smn_hudtext.cpp +++ b/core/smn_hudtext.cpp @@ -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); - if (pContext->GetContext()->n_err != SP_ERROR_NONE) + if (pContext->GetLastNativeError() != SP_ERROR_NONE) { 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); - if (pContext->GetContext()->n_err != SP_ERROR_NONE) + if (pContext->GetLastNativeError() != SP_ERROR_NONE) { return 0; } diff --git a/core/smn_player.cpp b/core/smn_player.cpp index ed185f09..33b5b826 100644 --- a/core/smn_player.cpp +++ b/core/smn_player.cpp @@ -1000,7 +1000,7 @@ static cell_t _ShowActivity(IPluginContext *pContext, g_SourceMod.SetGlobalTarget(client); 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; } @@ -1015,7 +1015,7 @@ static cell_t _ShowActivity(IPluginContext *pContext, g_SourceMod.SetGlobalTarget(SOURCEMOD_SERVER_LANGUAGE); 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; } @@ -1054,7 +1054,7 @@ static cell_t _ShowActivity(IPluginContext *pContext, } 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; } @@ -1078,7 +1078,7 @@ static cell_t _ShowActivity(IPluginContext *pContext, } 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; } @@ -1123,7 +1123,7 @@ static cell_t _ShowActivity2(IPluginContext *pContext, g_SourceMod.SetGlobalTarget(client); 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; } @@ -1152,7 +1152,7 @@ static cell_t _ShowActivity2(IPluginContext *pContext, g_SourceMod.SetGlobalTarget(SOURCEMOD_SERVER_LANGUAGE); 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; } @@ -1191,7 +1191,7 @@ static cell_t _ShowActivity2(IPluginContext *pContext, } 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; } @@ -1215,7 +1215,7 @@ static cell_t _ShowActivity2(IPluginContext *pContext, } 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; } @@ -1286,7 +1286,7 @@ static cell_t KickClient(IPluginContext *pContext, const cell_t *params) char buffer[256]; 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; } @@ -1332,7 +1332,7 @@ static cell_t KickClientEx(IPluginContext *pContext, const cell_t *params) char buffer[256]; 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; } diff --git a/core/smn_string.cpp b/core/smn_string.cpp index e9d7b647..f9ba1140 100644 --- a/core/smn_string.cpp +++ b/core/smn_string.cpp @@ -233,8 +233,7 @@ static cell_t sm_vformat(IPluginContext *pContext, const cell_t *params) int vargPos = static_cast(params[4]); /* Get the parent parameter array */ - sp_context_t *ctx = pContext->GetContext(); - cell_t *local_params = (cell_t *)(ctx->memory + ctx->frm + (2 * sizeof(cell_t))); + cell_t *local_params = pContext->GetLocalParams(); cell_t max = local_params[0]; if (vargPos > (int)max + 1) diff --git a/core/sourcemod.cpp b/core/sourcemod.cpp index 8cf5fbbd..52e6f3aa 100644 --- a/core/sourcemod.cpp +++ b/core/sourcemod.cpp @@ -33,7 +33,6 @@ #include "sourcemod.h" #include "sourcemm_api.h" #include "systems/LibrarySys.h" -#include "vm/sp_vm_engine.h" #include #include "PluginSys.h" #include "ShareSys.h" @@ -47,27 +46,26 @@ #include "ForwardSys.h" #include "TimerSys.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_HOOK0_void(IServerGameDLL, LevelShutdown, SH_NOATTRIB, false); SH_DECL_HOOK1_void(IServerGameDLL, GameFrame, SH_NOATTRIB, false, bool); SH_DECL_HOOK1_void(IVEngineServer, ServerCommand, SH_NOATTRIB, false, const char *); -SourcePawnEngine g_SourcePawn; SourceModBase g_SourceMod; ILibrary *g_pJIT = NULL; SourceHook::String g_BaseDir; -ISourcePawnEngine *g_pSourcePawn = &g_SourcePawn; -IVirtualMachine *g_pVM; +ISourcePawnEngine *g_pSourcePawn = NULL; +ISourcePawnEngine2 *g_pSourcePawn2 = NULL; IdentityToken_t *g_pCoreIdent = NULL; IForward *g_pOnMapEnd = NULL; bool g_Loaded = false; -typedef int (*GIVEENGINEPOINTER)(ISourcePawnEngine *); -typedef int (*GIVEENGINEPOINTER2)(ISourcePawnEngine *, unsigned int api_version); -typedef unsigned int (*GETEXPORTCOUNT)(); -typedef IVirtualMachine *(*GETEXPORT)(unsigned int); +typedef ISourcePawnEngine *(*GET_SP_V1)(); +typedef ISourcePawnEngine2 *(*GET_SP_V2)(); typedef void (*NOTIFYSHUTDOWN)(); void ShutdownJIT() @@ -165,105 +163,34 @@ bool SourceModBase::InitializeSourceMod(char *error, size_t maxlength, bool late return false; } - int err; - - GIVEENGINEPOINTER2 jit_init2 = (GIVEENGINEPOINTER2)g_pJIT->GetSymbolAddress("GiveEnginePointer2"); - 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; - } + GET_SP_V1 getv1 = (GET_SP_V1)g_pJIT->GetSymbolAddress("GetSourcePawnEngine1"); + GET_SP_V2 getv2 = (GET_SP_V2)g_pJIT->GetSymbolAddress("GetSourcePawnEngine2"); - if ((err=jit_init(g_pSourcePawn)) != 0) - { - ShutdownJIT(); - if (error && maxlength) - { - snprintf(error, maxlength, "GiveEnginePointer returned %d in the JIT", err); - } - return false; - } - } - else + if (getv1 == NULL) { - /* 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) { - snprintf(error, maxlength, "JIT is missing a necessary export!"); + snprintf(error, maxlength, "JIT is too old; upgrade SourceMod"); } + ShutdownJIT(); return false; } - - unsigned int num = jit_getnum(); - if (!num) + else if (getv2 == NULL) { - ShutdownJIT(); 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; iAlso refuse anything < 3 because we need fake natives. - * 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(); 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() */ SH_ADD_HOOK_MEMFUNC(IServerGameDLL, LevelInit, gamedll, this, &SourceModBase::LevelInit, false); @@ -663,7 +590,7 @@ ISourcePawnEngine *SourceModBase::GetScriptingEngine() IVirtualMachine *SourceModBase::GetScriptingVM() { - return g_pVM; + return NULL; } void SourceModBase::AllPluginsLoaded() diff --git a/core/systems/HandleSys.cpp b/core/systems/HandleSys.cpp index 897a5ff9..71b41fa9 100644 --- a/core/systems/HandleSys.cpp +++ b/core/systems/HandleSys.cpp @@ -990,7 +990,7 @@ bool HandleSystem::TryAndFreeSomeHandles() 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); - highest_owner->GetContext()->n_err = SP_ERROR_MEMACCESS; + highest_owner->GetBaseContext()->ThrowNativeErrorEx(SP_ERROR_MEMACCESS, "Memory leak"); return g_PluginSys.UnloadPlugin(highest_owner); } diff --git a/core/systems/PluginSys.cpp b/core/systems/PluginSys.cpp index bf6c7e0e..c9196d68 100644 --- a/core/systems/PluginSys.cpp +++ b/core/systems/PluginSys.cpp @@ -58,7 +58,7 @@ CPlugin::CPlugin(const char *file) m_type = PluginType_Private; m_status = Plugin_Uncompiled; m_serial = ++MySerial; - m_plugin = NULL; + m_pRuntime = NULL; m_errormsg[256] = '\0'; snprintf(m_filename, sizeof(m_filename), "%s", file); m_handle = 0; @@ -82,27 +82,12 @@ CPlugin::~CPlugin() g_ShareSys.DestroyIdentity(m_ident); } - if (m_ctx.base) + if (m_pRuntime != NULL) { - delete m_ctx.base; - m_ctx.base = 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; + delete m_pRuntime; + m_pRuntime = NULL; } - if (m_plugin) - { - g_pSourcePawn->FreeFromMemory(m_plugin); - m_plugin = NULL; - } if (m_pProps) { sm_trie_destroy(m_pProps); @@ -125,7 +110,8 @@ void CPlugin::InitIdentity() { m_ident = g_ShareSys.CreateIdentity(g_PluginIdent, this); 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(); } - 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; } @@ -214,23 +169,6 @@ CPlugin *CPlugin::CreatePlugin(const char *file, char *error, size_t maxlength) 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; } @@ -251,69 +189,9 @@ bool CPlugin::SetProperty(const char *prop, void *ptr) return sm_trie_insert(m_pProps, prop, ptr); } -ICompilation *CPlugin::StartMyCompile(IVirtualMachine *vm) +IPluginRuntime *CPlugin::GetRuntime() { - if (!m_plugin) - { - 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; + return m_pRuntime; } 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); 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; cell_t result; - IPluginFunction *pFunction = m_ctx.base->GetFunctionByName("OnPluginStart"); + IPluginFunction *pFunction = m_pRuntime->GetFunctionByName("OnPluginStart"); if (!pFunction) { return; @@ -436,7 +314,7 @@ void CPlugin::Call_OnPluginEnd() } cell_t result; - IPluginFunction *pFunction = m_ctx.base->GetFunctionByName("OnPluginEnd"); + IPluginFunction *pFunction = m_pRuntime->GetFunctionByName("OnPluginEnd"); if (!pFunction) { return; @@ -460,7 +338,7 @@ void CPlugin::Call_OnAllPluginsLoaded() m_bGotAllLoaded = true; cell_t result; - IPluginFunction *pFunction = m_ctx.base->GetFunctionByName("OnAllPluginsLoaded"); + IPluginFunction *pFunction = m_pRuntime->GetFunctionByName("OnAllPluginsLoaded"); if (pFunction != NULL) { pFunction->Execute(&result); @@ -468,7 +346,7 @@ void CPlugin::Call_OnAllPluginsLoaded() if (g_OnMapStarted) { - if ((pFunction = m_ctx.base->GetFunctionByName("OnMapStart")) != NULL) + if ((pFunction = m_pRuntime->GetFunctionByName("OnMapStart")) != NULL) { pFunction->Execute(NULL); } @@ -491,7 +369,7 @@ bool CPlugin::Call_AskPluginLoad(char *error, size_t maxlength) int err; cell_t result; - IPluginFunction *pFunction = m_ctx.base->GetFunctionByName("AskPluginLoad"); + IPluginFunction *pFunction = m_pRuntime->GetFunctionByName("AskPluginLoad"); if (!pFunction) { @@ -515,19 +393,24 @@ bool CPlugin::Call_AskPluginLoad(char *error, size_t maxlength) return true; } -const sp_plugin_t *CPlugin::GetPluginStructure() +void *CPlugin::GetPluginStructure() { - return m_plugin; + return NULL; } IPluginContext *CPlugin::GetBaseContext() { - return m_ctx.base; + if (m_pRuntime == NULL) + { + return NULL; + } + + return m_pRuntime->GetDefaultContext(); } sp_context_t *CPlugin::GetContext() { - return m_ctx.ctx; + return NULL; } const char *CPlugin::GetFilename() @@ -557,12 +440,12 @@ PluginStatus CPlugin::GetStatus() bool CPlugin::IsDebugging() { - if (!m_ctx.ctx) + if (m_pRuntime == NULL) { return false; } - return ((m_ctx.ctx->flags & SP_FLAG_DEBUG) == SP_FLAG_DEBUG); + return m_pRuntime->IsDebugging(); } void CPlugin::LibraryActions(bool dropping) @@ -590,7 +473,7 @@ bool CPlugin::SetPauseState(bool paused) LibraryActions(true); } - IPluginFunction *pFunction = m_ctx.base->GetFunctionByName("OnPluginPauseChange"); + IPluginFunction *pFunction = m_pRuntime->GetFunctionByName("OnPluginPauseChange"); if (pFunction) { cell_t result; @@ -601,10 +484,10 @@ bool CPlugin::SetPauseState(bool paused) if (paused) { m_status = Plugin_Paused; - m_ctx.ctx->flags |= SPFLAG_PLUGIN_PAUSED; + m_pRuntime->SetPauseState(true); } else { m_status = Plugin_Running; - m_ctx.ctx->flags &= ~SPFLAG_PLUGIN_PAUSED; + m_pRuntime->SetPauseState(false); } g_PluginSys._SetPauseState(this, paused); @@ -652,8 +535,9 @@ bool CPlugin::ToggleDebugMode(bool debug, char *error, size_t maxlength) return false; } - ICompilation *co = g_pVM->StartCompilation(m_ctx.ctx->plugin); - if (!g_pVM->SetCompilationOption(co, "debug", (debug) ? "1" : "0")) + ICompilation *co = g_pSourcePawn2->StartCompilation(); + + if (!co->SetOption("debug", (debug) ? "1" : "0")) { if (error) { @@ -662,32 +546,7 @@ bool CPlugin::ToggleDebugMode(bool debug, char *error, size_t maxlength) return false; } - sp_context_t *new_ctx = g_pVM->CompileToContext(co, &err); - - 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; inatives[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 ((err = m_pRuntime->ApplyCompilationOptions(co)) != SP_ERROR_NONE) { if (error) { @@ -696,6 +555,8 @@ bool CPlugin::ToggleDebugMode(bool debug, char *error, size_t maxlength) return false; } + UpdateInfo(); + return true; } @@ -741,7 +602,7 @@ IPhraseCollection *CPlugin::GetPhrases() void CPlugin::DependencyDropped(CPlugin *pOwner) { - if (!m_ctx.ctx) + if (!m_pRuntime) { return; } @@ -771,12 +632,12 @@ void CPlugin::DependencyDropped(CPlugin *pOwner) { pNative = (*iter); /* 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; } /* Unbind it */ - m_ctx.base->GetNativeByIndex(idx, &native); + m_pRuntime->GetNativeByIndex(idx, &native); native->pfn = NULL; native->status = SP_NATIVE_UNBOUND; unbound++; @@ -1047,6 +908,7 @@ LoadRes CPluginManager::_LoadPlugin(CPlugin **_plugin, const char *path, bool de return LoadRes_NeverLoad; } + int err; bool no_load = false; PluginSettings *pset; 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) { - co = pPlugin->StartMyCompile(g_pVM); + co = g_pSourcePawn2->StartCompilation(); } for (unsigned int i=0; iSetCompilationOption(co, key, val)) + if ((err = co->SetOption(key, val)) == SP_ERROR_NONE) { if (error) { snprintf(error, maxlength, "Unable to set JIT option (key \"%s\") (value \"%s\")", key, val); } - pPlugin->CancelMyCompile(); + co->Abort(); co = NULL; break; } @@ -1137,10 +999,25 @@ LoadRes CPluginManager::_LoadPlugin(CPlugin **_plugin, const char *path, bool de } /* Do the actual compiling */ - if (co) + if (co != NULL) { - pPlugin->FinishMyCompile(error, maxlength); - co = NULL; + char fullpath[PLATFORM_MAX_PATH]; + 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 */ @@ -1321,7 +1198,7 @@ bool CPluginManager::FindOrRequirePluginDeps(CPlugin *pPlugin, char *error, size { cell_t res; pFunc->Execute(&res); - if (pPlugin->GetContext()->n_err != SP_ERROR_NONE) + if (pPlugin->GetBaseContext()->GetLastNativeError() != SP_ERROR_NONE) { if (error) { @@ -1448,7 +1325,7 @@ bool CPluginManager::LoadOrRequireExtensions(CPlugin *pPlugin, unsigned int pass { cell_t res; pFunc->Execute(&res); - if (pPlugin->GetContext()->n_err != SP_ERROR_NONE) + if (pPlugin->GetBaseContext()->GetLastNativeError() != SP_ERROR_NONE) { if (error) { @@ -1615,9 +1492,9 @@ void CPluginManager::TryRefreshDependencies(CPlugin *pPlugin) { /* If we got here, all natives are okay again! */ 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); } } @@ -1687,8 +1564,22 @@ bool CPluginManager::UnloadPlugin(IPlugin *plugin) IPlugin *CPluginManager::FindPluginByContext(const sp_context_t *ctx) { - IPlugin *pl = (IPlugin *)ctx->user[SM_CONTEXTVAR_MYSELF]; - return pl; + IPlugin *pPlugin; + IPluginContext *pContext; + + pContext = reinterpret_cast(const_cast(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() diff --git a/core/systems/PluginSys.h b/core/systems/PluginSys.h index 7e79871a..1bb41141 100644 --- a/core/systems/PluginSys.h +++ b/core/systems/PluginSys.h @@ -43,7 +43,6 @@ #include #include #include "sm_globals.h" -#include "vm/sp_vm_basecontext.h" #include "PluginInfoDatabase.h" #include "sm_trie.h" #include "sourcemod.h" @@ -109,19 +108,6 @@ using namespace SourceHook; * 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 { LoadRes_Successful, @@ -152,18 +138,19 @@ public: PluginType GetType(); SourcePawn::IPluginContext *GetBaseContext(); sp_context_t *GetContext(); - const sm_plugininfo_t *GetPublicInfo(); + void *GetPluginStructure(); const char *GetFilename(); bool IsDebugging(); PluginStatus GetStatus(); + const sm_plugininfo_t *GetPublicInfo(); bool SetPauseState(bool paused); unsigned int GetSerial(); - const sp_plugin_t *GetPluginStructure(); IdentityToken_t *GetIdentity(); unsigned int CalcMemUsage(); bool SetProperty(const char *prop, void *ptr); bool GetProperty(const char *prop, void **ptr, bool remove=false); void DropEverything(); + SourcePawn::IPluginRuntime *GetRuntime(); public: /** * Creates a plugin object with default values. @@ -174,16 +161,6 @@ public: */ static CPlugin *CreatePlugin(const char *file, char *error, size_t maxlength); 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 @@ -267,13 +244,11 @@ protected: void SetTimeStamp(time_t t); void DependencyDropped(CPlugin *pOwner); private: - ContextPair m_ctx; PluginType m_type; char m_filename[PLATFORM_MAX_PATH]; PluginStatus m_status; unsigned int m_serial; sm_plugininfo_t m_info; - sp_plugin_t *m_plugin; char m_errormsg[256]; time_t m_LastAccess; IdentityToken_t *m_ident; @@ -289,6 +264,8 @@ private: bool m_bGotAllLoaded; int m_FileVersion; char m_DateTime[256]; + IPluginRuntime *m_pRuntime; + IPluginContext *m_pContext; }; class CPluginManager : @@ -382,10 +359,7 @@ public: /** * Internal version of FindPluginByContext() */ - inline CPlugin *GetPluginByCtx(const sp_context_t *ctx) - { - return reinterpret_cast(ctx->user[SM_CONTEXTVAR_MYSELF]); - } + CPlugin *GetPluginByCtx(const sp_context_t *ctx); /** * Gets status text for a status code diff --git a/core/systems/ShareSys.cpp b/core/systems/ShareSys.cpp index 391a9c7c..3d04f7fa 100644 --- a/core/systems/ShareSys.cpp +++ b/core/systems/ShareSys.cpp @@ -488,7 +488,7 @@ NativeEntry *ShareSystem::AddFakeNative(IPluginFunction *pFunc, const char *name pFake = new FakeNative; - if ((gate = g_pVM->CreateFakeNative(func, pFake)) == NULL) + if ((gate = g_pSourcePawn2->CreateFakeNative(func, pFake)) == NULL) { delete pFake; return NULL; diff --git a/core/vm/sp_vm_basecontext.cpp b/core/vm/sp_vm_basecontext.cpp deleted file mode 100644 index b963d523..00000000 --- a/core/vm/sp_vm_basecontext.cpp +++ /dev/null @@ -1,1120 +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 . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -#include -#include -#include -#include -#include "sp_vm_api.h" -#include "sp_vm_basecontext.h" -#include "sp_vm_engine.h" - -#ifdef SOURCEMOD_BUILD -#include "Logger.h" -#include "DebugReporter.h" -#endif - -using namespace SourcePawn; - -extern SourcePawnEngine g_SourcePawn; - -#define CELLBOUNDMAX (INT_MAX/sizeof(cell_t)) -#define STACKMARGIN ((cell_t)(16*sizeof(cell_t))) - -int GlobalDebugBreak(sp_context_t *ctx, uint32_t frm, uint32_t cip) -{ - g_SourcePawn.RunTracer(ctx, frm, cip); - - return SP_ERROR_NONE; -} - -BaseContext::BaseContext(sp_context_t *_ctx) -{ - ctx = _ctx; - ctx->context = this; - ctx->dbreak = GlobalDebugBreak; - - if (ctx->prof_flags != 0) - { - ctx->profiler = sm_profiler; - } - - m_InExec = false; - m_CustomMsg = false; - m_funcsnum = ctx->vmbase->FunctionCount(ctx); -#if 0 - m_priv_funcs = NULL; -#endif - m_pub_funcs = NULL; - -#if 0 - /** - * Note: Since the m_plugin member will never change, - * it is safe to assume the function count will never change - */ - if (m_funcsnum && m_priv_funcs == NULL) - { - m_priv_funcs = new CFunction *[m_funcsnum]; - memset(m_priv_funcs, 0, sizeof(CFunction *) * m_funcsnum); - } else { - m_priv_funcs = NULL; - } -#endif - - if (ctx->plugin->info.publics_num && m_pub_funcs == NULL) - { - m_pub_funcs = new CFunction *[ctx->plugin->info.publics_num]; - memset(m_pub_funcs, 0, sizeof(CFunction *) * ctx->plugin->info.publics_num); - } else { - m_pub_funcs = NULL; - } - - /* 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; - } -} - -void BaseContext::FlushFunctionCache() -{ - if (m_pub_funcs) - { - for (uint32_t i=0; iplugin->info.publics_num; i++) - { - delete m_pub_funcs[i]; - m_pub_funcs[i] = NULL; - } - } - -#if 0 - if (m_priv_funcs) - { - for (unsigned int i=0; iplugin->info.publics_num; i++) - { - if (!m_pub_funcs[i]) - { - continue; - } - if (GetPublicByIndex(i, &pub) != SP_ERROR_NONE) - { - continue; - } - m_pub_funcs[i]->Set(pub->code_offs, this, pub->funcid, i); - } - } - -#if 0 - if (m_priv_funcs) - { - for (unsigned int i=0; i - } - } -#endif -} - -BaseContext::~BaseContext() -{ - FlushFunctionCache(); - delete [] m_pub_funcs; - m_pub_funcs = NULL; -#if 0 - delete [] m_priv_funcs; - m_priv_funcs = NULL; -#endif -} - -void BaseContext::SetContext(sp_context_t *_ctx) -{ - if (!_ctx) - { - return; - } - - ctx = _ctx; - ctx->context = this; - ctx->dbreak = GlobalDebugBreak; - - if (ctx->prof_flags != 0) - { - ctx->profiler = sm_profiler; - } - - RefreshFunctionCache(); -} - -IVirtualMachine *BaseContext::GetVirtualMachine() -{ - return (IVirtualMachine *)ctx->vmbase; -} - -sp_context_t *BaseContext::GetContext() -{ - return ctx; -} - -bool BaseContext::IsDebugging() -{ - return (ctx->flags & SPFLAG_PLUGIN_DEBUG); -} - -int BaseContext::SetDebugBreak(SPVM_DEBUGBREAK newpfn, SPVM_DEBUGBREAK *oldpfn) -{ - if (!IsDebugging()) - { - return SP_ERROR_NOTDEBUGGING; - } - - *oldpfn = ctx->dbreak; - ctx->dbreak = newpfn; - - return SP_ERROR_NONE; -} - -IPluginDebugInfo *BaseContext::GetDebugInfo() -{ - if (!IsDebugging()) - { - return NULL; - } - return this; -} - -int BaseContext::Execute(uint32_t code_addr, cell_t *result) -{ - if ((ctx->flags & SPFLAG_PLUGIN_PAUSED) == SPFLAG_PLUGIN_PAUSED) - { - return SP_ERROR_NOT_RUNNABLE; - } - - /* tada, prevent a crash */ - cell_t _ignore_result; - if (!result) - { - result = &_ignore_result; - } - - IVirtualMachine *vm = (IVirtualMachine *)ctx->vmbase; - - uint32_t pushcount = ctx->pushcount; - int err; - - if ((err = PushCell(pushcount++)) != SP_ERROR_NONE) - { -#if defined SOURCEMOD_BUILD - g_DbgReporter.GenerateCodeError(this, code_addr, err, "Stack error; cannot complete execution!"); -#endif - return SP_ERROR_NOT_RUNNABLE; - } - ctx->pushcount = 0; - - cell_t save_sp = ctx->sp + (pushcount * sizeof(cell_t)); - cell_t save_hp = ctx->hp; - uint32_t n_idx = ctx->n_idx; - - bool wasExec = m_InExec; - - /* Clear the error state, if any */ - ctx->n_err = SP_ERROR_NONE; - ctx->n_idx = 0; - m_InExec = true; - m_MsgCache[0] = '\0'; - m_CustomMsg = false; - - g_SourcePawn.PushTracer(ctx); - - err = vm->ContextExecute(ctx, code_addr, result); - - m_InExec = wasExec; - - /** - * :TODO: Calling from a plugin in here will erase the cached message... - * Should that be documented? - */ - g_SourcePawn.PopTracer(err, m_CustomMsg ? m_MsgCache : NULL); - -#if defined SOURCEMOD_BUILD - if (err == SP_ERROR_NONE) - { - if (ctx->sp != save_sp) - { - g_DbgReporter.GenerateCodeError(this, - code_addr, - SP_ERROR_STACKLEAK, - "Stack leak detected: sp:%d should be %d!", - ctx->sp, - save_sp); - } - if (ctx->hp != save_hp) - { - g_DbgReporter.GenerateCodeError(this, - code_addr, - SP_ERROR_HEAPLEAK, - "Heap leak detected: sp:%d should be %d!", - ctx->hp, - save_hp); - } - } -#endif - - if (err != SP_ERROR_NONE) - { - ctx->sp = save_sp; - ctx->hp = save_hp; - } - - ctx->n_idx = n_idx; - ctx->n_err = SP_ERROR_NONE; - m_MsgCache[0] = '\0'; - m_CustomMsg = false; - - return err; -} - -void BaseContext::SetErrorMessage(const char *msg, va_list ap) -{ - m_CustomMsg = true; - - vsnprintf(m_MsgCache, sizeof(m_MsgCache), msg, ap); -} - -cell_t BaseContext::ThrowNativeErrorEx(int error, const char *msg, ...) -{ - if (!m_InExec) - { - return 0; - } - - 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; - } - - 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)(ctx->sp - ctx->hp - realmem) < STACKMARGIN) - { - return SP_ERROR_HEAPLOW; - } - - addr = (cell_t *)(ctx->memory + ctx->hp); - /* store size of allocation in cells */ - *addr = (cell_t)cells; - addr++; - ctx->hp += sizeof(cell_t); - - *local_addr = ctx->hp; - - if (phys_addr) - { - *phys_addr = addr; - } - - 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 < ctx->heap_base || local_addr >= ctx->sp) - { - return SP_ERROR_INVALID_ADDRESS; - } - - addr = (cell_t *)(ctx->memory + local_addr); - cellcount = (*addr) * sizeof(cell_t); - /* check if this memory count looks valid */ - if ((signed)(ctx->hp - cellcount - sizeof(cell_t)) != local_addr) - { - return SP_ERROR_INVALID_ADDRESS; - } - - ctx->hp = local_addr; - - return SP_ERROR_NONE; -} - - -int BaseContext::HeapRelease(cell_t local_addr) -{ - if (local_addr < ctx->heap_base) - { - return SP_ERROR_INVALID_ADDRESS; - } - - ctx->hp = local_addr - sizeof(cell_t); - - return SP_ERROR_NONE; -} - -int BaseContext::FindNativeByName(const char *name, uint32_t *index) -{ - int high; - - high = ctx->plugin->info.natives_num - 1; - - for (uint32_t i=0; iplugin->info.natives_num; i++) - { - if (strcmp(ctx->natives[i].name, name) == 0) - { - if (index) - { - *index = i; - } - return SP_ERROR_NONE; - } - } - - return SP_ERROR_NOT_FOUND; -} - -int BaseContext::GetNativeByIndex(uint32_t index, sp_native_t **native) -{ - if (index >= ctx->plugin->info.natives_num) - { - return SP_ERROR_INDEX; - } - - if (native) - { - *native = &(ctx->natives[index]); - } - - return SP_ERROR_NONE; -} - - -uint32_t BaseContext::GetNativesNum() -{ - return ctx->plugin->info.natives_num; -} - -int BaseContext::FindPublicByName(const char *name, uint32_t *index) -{ - int diff, high, low; - uint32_t mid; - - high = ctx->plugin->info.publics_num - 1; - low = 0; - - while (low <= high) - { - mid = (low + high) / 2; - diff = strcmp(ctx->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 BaseContext::GetPublicByIndex(uint32_t index, sp_public_t **pblic) -{ - if (index >= ctx->plugin->info.publics_num) - { - return SP_ERROR_INDEX; - } - - if (pblic) - { - *pblic = &(ctx->publics[index]); - } - - return SP_ERROR_NONE; -} - -uint32_t BaseContext::GetPublicsNum() -{ - return ctx->plugin->info.publics_num; -} - -int BaseContext::GetPubvarByIndex(uint32_t index, sp_pubvar_t **pubvar) -{ - if (index >= ctx->plugin->info.pubvars_num) - { - return SP_ERROR_INDEX; - } - - if (pubvar) - { - *pubvar = &(ctx->pubvars[index]); - } - - return SP_ERROR_NONE; -} - -int BaseContext::FindPubvarByName(const char *name, uint32_t *index) -{ - int diff, high, low; - uint32_t mid; - - high = ctx->plugin->info.pubvars_num - 1; - low = 0; - - while (low <= high) - { - mid = (low + high) / 2; - diff = strcmp(ctx->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 BaseContext::GetPubvarAddrs(uint32_t index, cell_t *local_addr, cell_t **phys_addr) -{ - if (index >= ctx->plugin->info.pubvars_num) - { - return SP_ERROR_INDEX; - } - - *local_addr = ctx->plugin->info.pubvars[index].address; - *phys_addr = ctx->pubvars[index].offs; - - return SP_ERROR_NONE; -} - -uint32_t BaseContext::GetPubVarsNum() -{ - return ctx->plugin->info.pubvars_num; -} - -int BaseContext::BindNatives(const sp_nativeinfo_t *natives, unsigned int num, int overwrite) -{ - uint32_t i, j, max; - - max = ctx->plugin->info.natives_num; - - for (i=0; inatives[i].status == SP_NATIVE_BOUND) && !overwrite) - { - continue; - } - - for (j=0; (natives[j].name) && (!num || jnatives[i].name, natives[j].name)) - { - ctx->natives[i].pfn = natives[j].func; - ctx->natives[i].status = SP_NATIVE_BOUND; - } - } - } - - return SP_ERROR_NONE; -} - -int BaseContext::BindNative(const sp_nativeinfo_t *native) -{ - uint32_t index; - int err; - - if ((err = FindNativeByName(native->name, &index)) != SP_ERROR_NONE) - { - return err; - } - - ctx->natives[index].pfn = native->func; - ctx->natives[index].status = SP_NATIVE_BOUND; - - return SP_ERROR_NONE; -} - -int BaseContext::BindNativeToIndex(uint32_t index, SPVM_NATIVE_FUNC func) -{ - int err; - sp_native_t *native; - - if ((err = GetNativeByIndex(index, &native)) != SP_ERROR_NONE) - { - return err; - } - - ctx->natives[index].pfn = func; - ctx->natives[index].status = SP_NATIVE_BOUND; - - return SP_ERROR_NONE; -} - -int BaseContext::BindNativeToAny(SPVM_NATIVE_FUNC native) -{ - uint32_t nativesnum, i; - - nativesnum = ctx->plugin->info.natives_num; - - for (i=0; inatives[i].status == SP_NATIVE_UNBOUND) - { - ctx->natives[i].pfn = native; - ctx->natives[i].status = SP_NATIVE_BOUND; - } - } - - return SP_ERROR_NONE; -} - -int BaseContext::LocalToPhysAddr(cell_t local_addr, cell_t **phys_addr) -{ - if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->mem_size)) - { - return SP_ERROR_INVALID_ADDRESS; - } - - if (phys_addr) - { - *phys_addr = (cell_t *)(ctx->memory + local_addr); - } - - return SP_ERROR_NONE; -} - -int BaseContext::PushCell(cell_t value) -{ - if ((ctx->hp + STACKMARGIN) > (cell_t)(ctx->sp - sizeof(cell_t))) - { - return SP_ERROR_STACKLOW; - } - - ctx->sp -= sizeof(cell_t); - *(cell_t *)(ctx->memory + ctx->sp) = value; - ctx->pushcount++; - - return SP_ERROR_NONE; -} - -int BaseContext::PushCellsFromArray(cell_t array[], unsigned int numcells) -{ - unsigned int i; - int err; - - for (i=0; isp += (cell_t)(i * sizeof(cell_t)); - ctx->pushcount -= i; - return err; - } - } - - return SP_ERROR_NONE; -} - -int BaseContext::PushCellArray(cell_t *local_addr, cell_t **phys_addr, cell_t array[], unsigned int numcells) -{ - cell_t *ph_addr; - int err; - - if ((err = HeapAlloc(numcells, local_addr, &ph_addr)) != SP_ERROR_NONE) - { - return err; - } - - memcpy(ph_addr, array, numcells * sizeof(cell_t)); - - if ((err = PushCell(*local_addr)) != SP_ERROR_NONE) - { - HeapRelease(*local_addr); - return err; - } - - if (phys_addr) - { - *phys_addr = ph_addr; - } - - return SP_ERROR_NONE; -} - -int BaseContext::LocalToString(cell_t local_addr, char **addr) -{ - if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->mem_size)) - { - return SP_ERROR_INVALID_ADDRESS; - } - *addr = (char *)(ctx->memory + local_addr); - - return SP_ERROR_NONE; -} - -int BaseContext::PushString(cell_t *local_addr, char **phys_addr, const char *string) -{ - char *ph_addr; - int err; - unsigned int len, numcells = ((len=strlen(string)) + sizeof(cell_t)) / sizeof(cell_t); - - if ((err = HeapAlloc(numcells, local_addr, (cell_t **)&ph_addr)) != SP_ERROR_NONE) - { - return err; - } - - memcpy(ph_addr, string, len); - ph_addr[len] = '\0'; - - if ((err = PushCell(*local_addr)) != SP_ERROR_NONE) - { - HeapRelease(*local_addr); - return err; - } - - if (phys_addr) - { - *phys_addr = ph_addr; - } - - return SP_ERROR_NONE; -} - -int BaseContext::StringToLocal(cell_t local_addr, size_t bytes, const char *source) -{ - char *dest; - size_t len; - - if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->mem_size)) - { - return SP_ERROR_INVALID_ADDRESS; - } - - if (bytes == 0) - { - return SP_ERROR_NONE; - } - - len = strlen(source); - dest = (char *)(ctx->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 >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->mem_size)) - { - return SP_ERROR_INVALID_ADDRESS; - } - - if (maxbytes == 0) - { - return SP_ERROR_NONE; - } - - len = strlen(source); - dest = (char *)(ctx->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; -} - -#define USHR(x) ((unsigned int)(x)>>1) - -int BaseContext::LookupFile(ucell_t addr, const char **filename) -{ - int high, low, mid; - - high = ctx->plugin->debug.files_num; - low = -1; - - while (high - low > 1) - { - mid = USHR(low + high); - if (ctx->files[mid].addr <= addr) - { - low = mid; - } else { - high = mid; - } - } - - if (low == -1) - { - return SP_ERROR_NOT_FOUND; - } - - *filename = ctx->files[low].name; - - return SP_ERROR_NONE; -} - -int BaseContext::LookupFunction(ucell_t addr, const char **name) -{ - uint32_t iter, max = ctx->plugin->debug.syms_num; - - for (iter=0; itersymbols[iter].sym->ident == SP_SYM_FUNCTION) - && (ctx->symbols[iter].codestart <= addr) - && (ctx->symbols[iter].codeend > addr)) - { - break; - } - } - - if (iter >= max) - { - return SP_ERROR_NOT_FOUND; - } - - *name = ctx->symbols[iter].name; - - return SP_ERROR_NONE; -} - -int BaseContext::LookupLine(ucell_t addr, uint32_t *line) -{ - int high, low, mid; - - high = ctx->plugin->debug.lines_num; - low = -1; - - while (high - low > 1) - { - mid = USHR(low + high); - if (ctx->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 = ctx->lines[low].line + 1; - - return SP_ERROR_NONE; -} - -IPluginFunction *BaseContext::GetFunctionById(funcid_t func_id) -{ - CFunction *pFunc = NULL; - - if (func_id & 1) - { - func_id >>= 1; - if (func_id >= ctx->plugin->info.publics_num) - { - return NULL; - } - pFunc = m_pub_funcs[func_id]; - if (!pFunc) - { - m_pub_funcs[func_id] = new CFunction(ctx->publics[func_id].code_offs, - this, - ctx->publics[func_id].funcid, - func_id); - pFunc = m_pub_funcs[func_id]; - } - else if (pFunc->IsInvalidated()) - { - pFunc->Set(ctx->publics[func_id].code_offs, - this, - ctx->publics[func_id].funcid, - func_id); - } - } else { - /* :TODO: currently not used */ -#if 0 - func_id >>= 1; - unsigned int index; - if (!g_pVM->FunctionLookup(ctx, func_id, &index)) - { - return NULL; - } - pFunc = m_priv_funcs[func_id]; - if (!pFunc) - { - m_priv_funcs[func_id] = new CFunction(save, this); - pFunc = m_priv_funcs[func_id]; - } -#endif - } - - return pFunc; -} - -IPluginFunction *BaseContext::GetFunctionByName(const char *public_name) -{ - uint32_t index; - - if (FindPublicByName(public_name, &index) != SP_ERROR_NONE) - { - return NULL; - } - - CFunction *pFunc = m_pub_funcs[index]; - if (!pFunc) - { - sp_public_t *pub = NULL; - GetPublicByIndex(index, &pub); - if (pub) - { - m_pub_funcs[index] = new CFunction(pub->code_offs, this, pub->funcid, index); - } - pFunc = m_pub_funcs[index]; - } - else if (pFunc->IsInvalidated()) - { - sp_public_t *pub = NULL; - GetPublicByIndex(index, &pub); - if (pub) - { - pFunc->Set(pub->code_offs, this, pub->funcid, index); - } - else - { - pFunc = NULL; - } - } - - return pFunc; -} - -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; -} - -#if defined SOURCEMOD_BUILD -SourceMod::IdentityToken_t *BaseContext::GetIdentity() -{ - return m_pToken; -} - -void BaseContext::SetIdentity(SourceMod::IdentityToken_t *token) -{ - m_pToken = token; -} - -cell_t *BaseContext::GetNullRef(SP_NULL_TYPE type) -{ - if (type == SP_NULL_VECTOR) - { - return m_pNullVec; - } - - return NULL; -} -#endif - -bool BaseContext::IsInExec() -{ - return m_InExec; -} diff --git a/core/vm/sp_vm_basecontext.h b/core/vm/sp_vm_basecontext.h deleted file mode 100644 index 4b58937e..00000000 --- a/core/vm/sp_vm_basecontext.h +++ /dev/null @@ -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 . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -#ifndef _INCLUDE_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_ diff --git a/public/IPluginSys.h b/public/IPluginSys.h index c6dd0313..6c0d9d46 100644 --- a/public/IPluginSys.h +++ b/public/IPluginSys.h @@ -109,25 +109,25 @@ namespace SourceMod 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. */ 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; /** - * @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. @@ -189,6 +189,13 @@ namespace SourceMod * @return True if the property existed, false otherwise. */ 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; }; diff --git a/public/ISourceMod.h b/public/ISourceMod.h index 80fa1d05..e9ec4ac9 100644 --- a/public/ISourceMod.h +++ b/public/ISourceMod.h @@ -203,9 +203,9 @@ namespace SourceMod 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; diff --git a/public/sourcepawn/sp_vm_api.h b/public/sourcepawn/sp_vm_api.h index ee9db35a..6de6f6ee 100644 --- a/public/sourcepawn/sp_vm_api.h +++ b/public/sourcepawn/sp_vm_api.h @@ -41,10 +41,8 @@ #include "sp_vm_types.h" /** SourcePawn Engine API Version */ -#define SOURCEPAWN_ENGINE_API_VERSION 3 - -/** SourcePawn VM API Version */ -#define SOURCEPAWN_VM_API_VERSION 7 +#define SOURCEPAWN_ENGINE_API_VERSION 4 +#define SOURCEPAWN_ENGINE2_API_VERSION 1 #if !defined SOURCEMOD_BUILD #define SOURCEMOD_BUILD @@ -57,6 +55,9 @@ namespace SourceMod }; #endif +struct sp_context_s; +typedef struct sp_context_s sp_context_t; + namespace SourcePawn { class IVirtualMachine; @@ -185,7 +186,8 @@ namespace SourcePawn { 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. * @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; /** - * @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; @@ -227,6 +229,37 @@ namespace SourcePawn * @return Function id. */ 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: - /** 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: - /** - * @brief Returns the parent IVirtualMachine. - * - * @return Parent virtual machine pointer. - */ - virtual IVirtualMachine *GetVirtualMachine() =0; - /** - * @brief Returns the child sp_context_t structure. - * - * @return Child sp_context_t structure. + * @brief Virtual destructor (you may call delete). */ - 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; + virtual ~IPluginRuntime() + { + } /** * @brief Returns debug info. @@ -307,39 +335,6 @@ namespace SourcePawn */ 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. * @@ -419,7 +414,227 @@ namespace SourcePawn 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 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. - * This function is the same as the ANSI version, except it will copy the maximum number of characters possible - * without accidentally chopping a multi-byte character. + * This function is the same as the ANSI version, except it will copy the maximum number + * of characters possible without accidentally chopping a multi-byte character. * * @param local_addr Local address in plugin. * @param maxbytes Number of bytes to write, including NULL terminator. @@ -459,48 +674,41 @@ namespace SourcePawn 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; /** - * @brief Pushes an array of cells onto the stack. Increases the parameter count by one. - * 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(). + * @brief Deprecated, does nothing. * - * @param local_addr Filled with local address to release. - * @param phys_addr Optionally filled with physical address of new array. - * @param array Cell array to copy. - * @param numcells Number of cells in the array to copy. + * @param local_addr Unused. + * @param phys_addr Unused. + * @param array Unused. + * @param numcells Unused. */ 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. - * Note that this does not release the heap, so you should release it after - * calling Execute(). + * @brief Deprecated, does nothing. * - * @param local_addr Filled with local address to release. - * @param phys_addr Optionally filled with physical address of new array. - * @param string Source string to push. + * @param local_addr Unused. + * @param phys_addr Unused. + * @param string Unused. */ 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 - * parameter count by the number of cells pushed. - * If the function returns an error it will fail entirely, releasing anything allocated in the process. + * @brief Deprecated, does nothing. * - * @param array Array of cells to read from. - * @param numcells Number of cells to read. + * @param array Unused. + * @param numcells Unused. */ 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 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; /** - * @brief Deprecated; do not use. + * @brief Deprecated, does nothing. * * @param native Deprecated; do not use. */ 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; /** - * @brief Executes a function ID located in this context. + * @brief Deprecated, does nothing. * - * @param code_addr Address to execute at. - * @param result Pointer to store the return value (required). - * @return Error code (if any) from the VM. + * @param code_addr Unused. + * @param result Unused. + * @return SP_ERROR_ABORTED. */ 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; -#if defined SOURCEMOD_BUILD /** * @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. */ @@ -592,7 +800,6 @@ namespace SourcePawn * @param addr Destination output pointer. */ virtual int LocalToStringNULL(cell_t local_addr, char **addr) =0; -#endif /** * @brief Deprecated; do not use. @@ -608,6 +815,67 @@ namespace SourcePawn * @return True if in exec, false otherwise. */ 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; }; + struct sp_plugin_s; + typedef struct sp_plugin_s sp_plugin_t; + /** * @brief Contains helper functions used by VMs and the host app */ @@ -755,30 +1026,29 @@ namespace SourcePawn { public: /** - * @brief Loads a named file from a file pointer. - * Note: Using this means the memory will be allocated by the VM. + * @brief Deprecated, do not use. * - * @param fp File pointer. May be at any offset. Not closed on return. - * @param err Optional error code pointer. - * @return A new plugin structure. + * @param fp Unused. + * @param err Unused. + * @return NULL. */ 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 plugin If NULL, a new plugin pointer is returned. - * Otherwise, the passed pointer is used. - * @param err Optional error code pointer. - * @return The resulting plugin pointer. + * @param base Unused. + * @param plugin Unused. + * @param err Unused. + * @return NULL. */ virtual sp_plugin_t *LoadFromMemory(void *base, sp_plugin_t *plugin, int *err) =0; /** - * Frees all of the memory associated with a plugin file. - * If allocated using SP_LoadFromMemory, the base and plugin pointer - * itself are not freed (so this may end up doing nothing). + * @brief Deprecated, do not use. + * + * @param plugin Unused. + * @return SP_ERROR_ABORTED. */ virtual int FreeFromMemory(sp_plugin_t *plugin) =0; @@ -826,9 +1096,9 @@ namespace SourcePawn 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; @@ -869,103 +1139,23 @@ namespace SourcePawn 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 */ - class IVirtualMachine + class ISourcePawnEngine2 { public: /** - * @brief Returns the current API version. + * @brief Returns the second engine API version. + * + * @return API version. */ virtual unsigned int GetAPIVersion() =0; /** * @brief Returns the string name of a VM implementation. */ - virtual const char *GetVMName() =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; + virtual const char *GetEngineName() =0; /** * @brief Returns a version string. @@ -975,21 +1165,24 @@ namespace SourcePawn 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. + * + * If a compilation object is supplied, it is destroyed upon + * the function's return. * - * @param ctx Context to search. - * @param code_addr Index into the p-code section. - * @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. @@ -1006,6 +1199,32 @@ namespace SourcePawn * @param func Pointer to the fake native created by CreateFakeNative. */ 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; }; }; diff --git a/public/sourcepawn/sp_vm_base.h b/public/sourcepawn/sp_vm_base.h index e94b18cb..dfcba8a8 100644 --- a/public/sourcepawn/sp_vm_base.h +++ b/public/sourcepawn/sp_vm_base.h @@ -47,8 +47,5 @@ #define EXPORT_LINK extern "C" __attribute__((visibility("default"))) #endif -/** No longer used */ -typedef SourcePawn::IVirtualMachine *(*SP_GETVM_FUNC)(SourcePawn::ISourcePawnEngine *); - #endif //_INCLUDE_SOURCEPAWN_VM_BASE_H_ diff --git a/public/sourcepawn/sp_vm_types.h b/public/sourcepawn/sp_vm_types.h index 4eb57fd6..32fdedee 100644 --- a/public/sourcepawn/sp_vm_types.h +++ b/public/sourcepawn/sp_vm_types.h @@ -92,56 +92,6 @@ typedef uint32_t funcid_t; /**< Function index code */ *** 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 { class IPluginContext; @@ -251,51 +201,7 @@ typedef struct sp_debug_symbol_s sp_fdbg_symbol_t *sym; /**< Pointer to original symbol */ } sp_debug_symbol_t; -/** - * Breaks into a debugger - * 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; +//#define SPFLAG_PLUGIN_DEBUG (1<<0) /**< plugin is in debug mode */ +//#define SPFLAG_PLUGIN_PAUSED (1<<1) /**< plugin is "paused" (blocked from executing) */ #endif //_INCLUDE_SOURCEPAWN_VM_TYPES_H diff --git a/sourcepawn/jit/BaseRuntime.cpp b/sourcepawn/jit/BaseRuntime.cpp new file mode 100644 index 00000000..3d7cc402 --- /dev/null +++ b/sourcepawn/jit/BaseRuntime.cpp @@ -0,0 +1,357 @@ +#include +#include +#include +#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; iinfo.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; +} + diff --git a/sourcepawn/jit/BaseRuntime.h b/sourcepawn/jit/BaseRuntime.h new file mode 100644 index 00000000..5ff75601 --- /dev/null +++ b/sourcepawn/jit/BaseRuntime.h @@ -0,0 +1,60 @@ +#ifndef _INCLUDE_SOURCEPAWN_JIT_RUNTIME_H_ +#define _INCLUDE_SOURCEPAWN_JIT_RUNTIME_H_ + +#include +#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_ diff --git a/sourcepawn/jit/x86/Makefile b/sourcepawn/jit/Makefile similarity index 70% rename from sourcepawn/jit/x86/Makefile rename to sourcepawn/jit/Makefile index d8966966..fdc1358b 100644 --- a/sourcepawn/jit/x86/Makefile +++ b/sourcepawn/jit/Makefile @@ -1,7 +1,8 @@ # (C)2004-2008 SourceMod Development Team # Makefile written by David "BAILOPAN" Anderson -SMSDK = ../../.. +SMSDK = ../.. +SOURCEHOOK = ../../../sourcemm-1.6/sourcehook ##################################### ### EDIT BELOW FOR OTHER PROJECTS ### @@ -9,7 +10,26 @@ SMSDK = ../../.. 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 ### @@ -24,7 +44,7 @@ CPP = gcc-4.1 LINK = -static-libgcc 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 \ -D_snprintf=snprintf -D_vsnprintf=vsnprintf -D_alloca=alloca -Dstrcmpi=strcasecmp -Wall -DHAVE_STDINT_H \ @@ -52,12 +72,17 @@ endif BINARY = $(PROJECT).so 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 $(CPP) $(INCLUDE) $(CFLAGS) $(CPPFLAGS) -o $@ -c $< all: - mkdir -p $(BIN_DIR) + mkdir -p $(BIN_DIR)/x86 + mkdir -p $(BIN_DIR)/zlib $(MAKE) -f Makefile jit jit: $(OBJ_LINUX) diff --git a/sourcepawn/jit/x86/dll_exports.cpp b/sourcepawn/jit/dll_exports.cpp similarity index 71% rename from sourcepawn/jit/x86/dll_exports.cpp rename to sourcepawn/jit/dll_exports.cpp index 522eabe3..91a80743 100644 --- a/sourcepawn/jit/x86/dll_exports.cpp +++ b/sourcepawn/jit/dll_exports.cpp @@ -31,44 +31,21 @@ #include #include -#include "jit_x86.h" +#include "x86/jit_x86.h" #include "dll_exports.h" +#include "sp_vm_engine.h" +#include "engine2.h" -SourcePawn::ISourcePawnEngine *engine = NULL; -JITX86 g_jit; +SourcePawnEngine2 g_engine2; -EXPORTFUNC int GiveEnginePointer2(SourcePawn::ISourcePawnEngine *engine_p, unsigned int api_version) +EXPORTFUNC ISourcePawnEngine *GetSourcePawnEngine1() { - engine = engine_p; - - if (api_version > SOURCEPAWN_ENGINE_API_VERSION || api_version < 2) - { - return SP_ERROR_PARAM; - } - - return SP_ERROR_NONE; + return &g_engine1; } -EXPORTFUNC unsigned int GetExportCount() +EXPORTFUNC ISourcePawnEngine2 *GetSourcePawnEngine2() { - return 1; -} - -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; + return &g_engine2; } #if defined __linux__ diff --git a/sourcepawn/jit/x86/dll_exports.h b/sourcepawn/jit/dll_exports.h similarity index 100% rename from sourcepawn/jit/x86/dll_exports.h rename to sourcepawn/jit/dll_exports.h diff --git a/sourcepawn/jit/engine2.cpp b/sourcepawn/jit/engine2.cpp new file mode 100644 index 00000000..aa69bbc1 --- /dev/null +++ b/sourcepawn/jit/engine2.cpp @@ -0,0 +1,278 @@ +#include +#include +#include +#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); +} diff --git a/sourcepawn/jit/engine2.h b/sourcepawn/jit/engine2.h new file mode 100644 index 00000000..09de29d5 --- /dev/null +++ b/sourcepawn/jit/engine2.h @@ -0,0 +1,35 @@ +#ifndef _INCLUDE_SOURCEPAWN_ENGINE_2_H_ +#define _INCLUDE_SOURCEPAWN_ENGINE_2_H_ + +#include + +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_ diff --git a/sourcepawn/jit/jit_shared.h b/sourcepawn/jit/jit_shared.h new file mode 100644 index 00000000..11f4f573 --- /dev/null +++ b/sourcepawn/jit/jit_shared.h @@ -0,0 +1,95 @@ +#ifndef _INCLUDE_SOURCEPAWN_JIT_SHARED_H_ +#define _INCLUDE_SOURCEPAWN_JIT_SHARED_H_ + +#include + +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_ diff --git a/sourcepawn/jit/x86/jit_version.h b/sourcepawn/jit/jit_version.h similarity index 100% rename from sourcepawn/jit/x86/jit_version.h rename to sourcepawn/jit/jit_version.h diff --git a/sourcepawn/jit/x86/jit_version.tpl b/sourcepawn/jit/jit_version.tpl similarity index 100% rename from sourcepawn/jit/x86/jit_version.tpl rename to sourcepawn/jit/jit_version.tpl diff --git a/sourcepawn/jit/x86/msvc8/jit-x86.sln b/sourcepawn/jit/msvc8/jit-x86.sln similarity index 100% rename from sourcepawn/jit/x86/msvc8/jit-x86.sln rename to sourcepawn/jit/msvc8/jit-x86.sln diff --git a/sourcepawn/jit/x86/msvc8/jit-x86.vcproj b/sourcepawn/jit/msvc8/jit-x86.vcproj similarity index 68% rename from sourcepawn/jit/x86/msvc8/jit-x86.vcproj rename to sourcepawn/jit/msvc8/jit-x86.vcproj index 3e75a734..a1d74a10 100644 --- a/sourcepawn/jit/x86/msvc8/jit-x86.vcproj +++ b/sourcepawn/jit/msvc8/jit-x86.vcproj @@ -40,7 +40,7 @@ + + + + + + + + + + + + - - @@ -211,12 +231,20 @@ Filter="h;hpp;hxx;hm;inl;inc;xsd" UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" > + + + + + + @@ -245,18 +277,6 @@ 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}" > - - - - - - @@ -266,27 +286,75 @@ Name="SDK" > + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sourcepawn/jit/sp_vm_basecontext.cpp b/sourcepawn/jit/sp_vm_basecontext.cpp new file mode 100644 index 00000000..5ac58d41 --- /dev/null +++ b/sourcepawn/jit/sp_vm_basecontext.cpp @@ -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 . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#include +#include +#include +#include +#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((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; itersymbols[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; + } +} diff --git a/sourcepawn/jit/sp_vm_basecontext.h b/sourcepawn/jit/sp_vm_basecontext.h new file mode 100644 index 00000000..b92b33df --- /dev/null +++ b/sourcepawn/jit/sp_vm_basecontext.h @@ -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 . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#ifndef _INCLUDE_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_ diff --git a/core/vm/sp_vm_engine.cpp b/sourcepawn/jit/sp_vm_engine.cpp similarity index 55% rename from core/vm/sp_vm_engine.cpp rename to sourcepawn/jit/sp_vm_engine.cpp index 6a28014b..944170b5 100644 --- a/core/vm/sp_vm_engine.cpp +++ b/sourcepawn/jit/sp_vm_engine.cpp @@ -48,6 +48,8 @@ #include "zlib/zlib.h" #include "sp_vm_basecontext.h" +SourcePawnEngine g_engine1; + #if defined WIN32 #define WIN32_LEAN_AND_MEAN #include @@ -92,7 +94,7 @@ static const char *g_ErrorMsgTable[] = "Call was aborted", }; -const char *GetSourcePawnErrorMessage(int error) +const char *SourcePawnEngine::GetErrorString(int error) { if (error < 1 || error > ERROR_MESSAGE_MAX) { @@ -188,281 +190,31 @@ void SourcePawnEngine::BaseFree(void *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_file_hdr_t hdr; - sp_plugin_t *plugin; - uint8_t *base; - int z_result; - int error; - - if (!fp) + if (err != NULL) { - error = SP_ERROR_NOT_FOUND; - goto return_error; + *err = SP_ERROR_ABORTED; } - /* 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; } sp_plugin_t *SourcePawnEngine::LoadFromMemory(void *base, sp_plugin_t *plugin, int *err) { - sp_file_hdr_t hdr; - uint8_t noptr = 0; - - memcpy(&hdr, base, sizeof(sp_file_hdr_t)); - - if (!plugin) + if (err != NULL) { - plugin = (sp_plugin_t *)malloc(sizeof(sp_plugin_t)); - noptr = 1; + *err = SP_ERROR_ABORTED; } - if (!_ReadPlugin(&hdr, (uint8_t *)base, plugin, err)) - { - if (noptr) - { - free(plugin); - } - return NULL; - } - - if (!noptr) - { - plugin->allocflags |= SP_FA_SELF_EXTERNAL; - } - plugin->allocflags |= SP_FA_BASE_EXTERNAL; - - return plugin; + return NULL; } int SourcePawnEngine::FreeFromMemory(sp_plugin_t *plugin) { - if (!(plugin->allocflags & SP_FA_BASE_EXTERNAL)) - { - free(plugin->base); - plugin->base = NULL; - } - if (!(plugin->allocflags & SP_FA_SELF_EXTERNAL)) - { - free(plugin); - } - - return SP_ERROR_NONE; + return SP_ERROR_ABORTED; } -#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 *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); @@ -538,7 +290,7 @@ void SourcePawnEngine::PushTracer(sp_context_t *ctx) 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->ctx == ctx); @@ -577,13 +329,13 @@ void SourcePawnEngine::PopTracer(int error, const char *msg) { 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); - m_pDebugHook->OnContextExecuteError(m_CallStack->ctx->context, &trace); + m_pDebugHook->OnContextExecuteError(m_CallStack->ctx, &trace); } /* Now pop the error chain */ @@ -607,7 +359,7 @@ CContextTrace::CContextTrace(TracedCall *pStart, int error, const char *msg, uin bool CContextTrace::DebugInfoAvailable() { - return ((m_pStart->ctx->flags & SP_FLAG_DEBUG) == SP_FLAG_DEBUG); + return m_pStart->ctx->IsDebugging(); } const char *CContextTrace::GetCustomErrorString() @@ -648,7 +400,7 @@ bool CContextTrace::GetTraceInfo(CallStackInfo *trace) return false; } - IPluginContext *pContext = m_pIterator->ctx->context; + IPluginContext *pContext = m_pIterator->ctx; IPluginDebugInfo *pInfo = pContext->GetDebugInfo(); if (!pInfo) @@ -690,7 +442,7 @@ const char *CContextTrace::GetLastNative(uint32_t *index) } 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; } diff --git a/core/vm/sp_vm_engine.h b/sourcepawn/jit/sp_vm_engine.h similarity index 91% rename from core/vm/sp_vm_engine.h rename to sourcepawn/jit/sp_vm_engine.h index c50f8267..08e5c79a 100644 --- a/core/vm/sp_vm_engine.h +++ b/sourcepawn/jit/sp_vm_engine.h @@ -35,11 +35,13 @@ #include "sp_vm_api.h" #include "sp_vm_function.h" +class BaseContext; + struct TracedCall { uint32_t cip; uint32_t frm; - sp_context_t *ctx; + BaseContext *ctx; TracedCall *next; unsigned int chain; }; @@ -73,8 +75,6 @@ public: //ISourcePawnEngine sp_plugin_t *LoadFromFilePointer(FILE *fp, int *err); sp_plugin_t *LoadFromMemory(void *base, sp_plugin_t *plugin, int *err); int FreeFromMemory(sp_plugin_t *plugin); - IPluginContext *CreateBaseContext(sp_context_t *ctx); - void FreeBaseContext(IPluginContext *ctx); void *BaseAlloc(size_t size); void BaseFree(void *memory); void *ExecAlloc(size_t size); @@ -86,13 +86,14 @@ public: //ISourcePawnEngine void SetReadWrite(void *ptr); void SetReadExecute(void *ptr); void FreePageMemory(void *ptr); + const char *GetErrorString(int err); public: //Debugger Stuff /** * @brief Pushes a context onto the top of the call tracer. * * @param ctx Plugin context. */ - void PushTracer(sp_context_t *ctx); + void PushTracer(BaseContext *ctx); /** * @brief Pops a plugin off the call tracer. @@ -102,7 +103,7 @@ public: //Debugger Stuff /** * @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 CFunction *GetFunctionFromPool(funcid_t f, IPluginContext *plugin); void ReleaseFunctionToPool(CFunction *func); @@ -117,4 +118,6 @@ private: //CFunction *m_pFreeFuncs; }; +extern SourcePawnEngine g_engine1; + #endif //_INCLUDE_SOURCEPAWN_VM_ENGINE_H_ diff --git a/core/vm/sp_vm_function.cpp b/sourcepawn/jit/sp_vm_function.cpp similarity index 74% rename from core/vm/sp_vm_function.cpp rename to sourcepawn/jit/sp_vm_function.cpp index cfc080ab..6a52ea02 100644 --- a/core/vm/sp_vm_function.cpp +++ b/sourcepawn/jit/sp_vm_function.cpp @@ -32,76 +32,47 @@ #include #include #include "sp_vm_function.h" -#include "sm_stringutil.h" +#include "BaseRuntime.h" /******************** * 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_pContext = plugin; + m_pRuntime = runtime; m_curparam = 0; m_errorstate = SP_ERROR_NONE; m_Invalid = false; - m_pCtx = plugin ? plugin->GetContext() : NULL; - m_FnId = id; - - m_pContext->GetPublicByIndex(pub_id, &m_pPublic); + m_FnId = fnid; } 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 ir, serial; + return CallFunction2(m_pRuntime->GetDefaultContext(), params, num_params, result); +} - if (!IsRunnable()) - { - return SP_ERROR_NOT_RUNNABLE; - } - - 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; +int CFunction::CallFunction2(IPluginContext *pContext, const cell_t *params, unsigned int num_params, cell_t *result) +{ + return pContext->Execute2(this, params, num_params, result); } 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) : - m_codeaddr(code_addr), m_pContext(plugin), m_curparam(0), - m_errorstate(SP_ERROR_NONE), m_FnId(id) +CFunction::CFunction(uint32_t code_addr, BaseRuntime *runtime, funcid_t id, uint32_t pub_id) : + m_codeaddr(code_addr), m_curparam(0), m_errorstate(SP_ERROR_NONE), m_FnId(id) { m_Invalid = false; - if (plugin) - { - m_pCtx = plugin->GetContext(); - } - m_pContext->GetPublicByIndex(pub_id, &m_pPublic); + m_pRuntime = runtime; } int CFunction::PushCell(cell_t cell) @@ -198,6 +169,11 @@ void CFunction::Cancel() } 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; @@ -236,9 +212,9 @@ int CFunction::Execute(cell_t *result) if (!temp_info[i].str.is_sz) { /* Allocate a normal/generic array */ - if ((err=m_pContext->HeapAlloc(temp_info[i].size, - &(temp_info[i].local_addr), - &(temp_info[i].phys_addr))) + if ((err=ctx->HeapAlloc(temp_info[i].size, + &(temp_info[i].local_addr), + &(temp_info[i].phys_addr))) != SP_ERROR_NONE) { 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); /* Allocate the buffer */ - if ((err=m_pContext->HeapAlloc(cells, - &(temp_info[i].local_addr), - &(temp_info[i].phys_addr))) + if ((err=ctx->HeapAlloc(cells, + &(temp_info[i].local_addr), + &(temp_info[i].phys_addr))) != SP_ERROR_NONE) { break; @@ -267,10 +243,10 @@ int CFunction::Execute(cell_t *result) /* Cut off UTF-8 properly */ if (temp_info[i].str.sz_flags & SM_PARAM_STRING_UTF8) { - if ((err=m_pContext->StringToLocalUTF8(temp_info[i].local_addr, - temp_info[i].size, - (const char *)temp_info[i].orig_addr, - NULL)) + if ((err=ctx->StringToLocalUTF8(temp_info[i].local_addr, + temp_info[i].size, + (const char *)temp_info[i].orig_addr, + NULL)) != SP_ERROR_NONE) { break; @@ -284,9 +260,9 @@ int CFunction::Execute(cell_t *result) /* Copy ASCII characters */ else { - if ((err=m_pContext->StringToLocal(temp_info[i].local_addr, - temp_info[i].size, - (const char *)temp_info[i].orig_addr)) + if ((err=ctx->StringToLocal(temp_info[i].local_addr, + temp_info[i].size, + (const char *)temp_info[i].orig_addr)) != SP_ERROR_NONE) { break; @@ -307,7 +283,7 @@ int CFunction::Execute(cell_t *result) /* Make the call if we can */ 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; } @@ -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; } @@ -364,3 +340,16 @@ funcid_t CFunction::GetFunctionID() return m_FnId; } +int CFunction::SetError(int err) +{ + m_errorstate = err; + + return err; +} + +bool CFunction::IsInvalidated() +{ + return m_Invalid; +} + + diff --git a/core/vm/sp_vm_function.h b/sourcepawn/jit/sp_vm_function.h similarity index 85% rename from core/vm/sp_vm_function.h rename to sourcepawn/jit/sp_vm_function.h index 275143c9..c9f9c610 100644 --- a/core/vm/sp_vm_function.h +++ b/sourcepawn/jit/sp_vm_function.h @@ -32,7 +32,11 @@ #ifndef _INCLUDE_SOURCEMOD_BASEFUNCTION_H_ #define _INCLUDE_SOURCEMOD_BASEFUNCTION_H_ -#include "sm_globals.h" +#include + +class BaseRuntime; + +using namespace SourcePawn; struct ParamInfo { @@ -56,7 +60,7 @@ class CFunction : public IPluginFunction friend class SourcePawnEngine; public: CFunction(uint32_t code_addr, - IPluginContext *pContext, + BaseRuntime *pRuntime, funcid_t fnid, uint32_t pub_id); public: @@ -71,29 +75,23 @@ public: virtual void Cancel(); virtual int CallFunction(const cell_t *params, unsigned int num_params, cell_t *result); virtual IPluginContext *GetParentContext(); - inline bool IsInvalidated() - { - return m_Invalid; - } - inline void Invalidate() - { - m_Invalid = true; - } + bool IsInvalidated(); + void Invalidate(); bool IsRunnable(); 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: - 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: int _PushString(const char *string, int sz_flags, int cp_flags, size_t len); - inline int SetError(int err) - { - m_errorstate = err; - return err; - } + int SetError(int err); private: uint32_t m_codeaddr; - IPluginContext *m_pContext; - sp_context_t *m_pCtx; + BaseRuntime *m_pRuntime; cell_t m_params[SP_MAX_EXEC_PARAMS]; ParamInfo m_info[SP_MAX_EXEC_PARAMS]; unsigned int m_curparam; @@ -101,7 +99,6 @@ private: CFunction *m_pNext; bool m_Invalid; funcid_t m_FnId; - sp_public_t *m_pPublic; }; #endif //_INCLUDE_SOURCEMOD_BASEFUNCTION_H_ diff --git a/sourcepawn/jit/x86/version.rc b/sourcepawn/jit/version.rc similarity index 100% rename from sourcepawn/jit/x86/version.rc rename to sourcepawn/jit/version.rc diff --git a/sourcepawn/jit/x86/jit_x86.cpp b/sourcepawn/jit/x86/jit_x86.cpp index 8d68c91d..f8bb89ee 100644 --- a/sourcepawn/jit/x86/jit_x86.cpp +++ b/sourcepawn/jit/x86/jit_x86.cpp @@ -35,12 +35,24 @@ #include "jit_x86.h" #include "opcode_helpers.h" #include -#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 #include "ungen_opcodes.h" #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) { //mov eax, edx @@ -1318,12 +1330,12 @@ inline void WriteOp_Retn(JitWriter *jit) 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) { - ctx->profiler->OnFunctionEnd(); + ((IProfiler *)ctx->vm[JITVARS_PROFILER])->OnFunctionEnd(); } 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) { sp_native_t *native; + sp_plugin_t *plugin; + + plugin = (sp_plugin_t *)ctx->vm[JITVARS_PLUGIN]; - native = &ctx->natives[native_idx]; + native = &plugin->natives[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 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 val; 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; @@ -2295,9 +2313,9 @@ cell_t NativeCallback_Profile(sp_context_t *ctx, ucell_t native_idx, cell_t *par return 0; } - ctx->profiler->OnNativeBegin(ctx->context, native); - val = native->pfn(ctx->context, params); - ctx->profiler->OnNativeEnd(); + plugin->profiler->OnNativeBegin(GET_CONTEXT(ctx), native); + val = native->pfn(GET_CONTEXT(ctx), params); + plugin->profiler->OnNativeEnd(); 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_hp = ctx->hp; + sp_plugin_t *pl = GETPLUGIN(ctx); + 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; return 0; @@ -2321,7 +2341,7 @@ cell_t NativeCallback_Debug(sp_context_t *ctx, ucell_t native_idx, cell_t *param return 0; } - if ((uint32_t)ctx->sp >= ctx->mem_size) + if ((uint32_t)ctx->sp >= pl->mem_size) { ctx->n_err = SP_ERROR_STACKMIN; 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_hp = ctx->hp; + sp_plugin_t *pl = GETPLUGIN(ctx); + 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; return 0; @@ -2367,7 +2389,7 @@ cell_t NativeCallback_Debug_Profile(sp_context_t *ctx, ucell_t native_idx, cell_ return 0; } - if ((uint32_t)ctx->sp >= ctx->mem_size) + if ((uint32_t)ctx->sp >= pl->mem_size) { ctx->n_err = SP_ERROR_STACKMIN; 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) { - sp_context_t *ctx = pCtx->GetContext(); - ctx->n_err = SP_ERROR_INVALID_NATIVE; - - return 0; + return pCtx->ThrowNativeErrorEx(SP_ERROR_INVALID_NATIVE, "Invalid native"); } jitoffs_t RelocLookup(JitWriter *jit, cell_t pcode_offs, bool relative) @@ -2457,11 +2476,27 @@ void WriteErrorRoutines(CompData *data, JitWriter *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; 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 */ uint8_t *code = plugin->pcode; uint8_t *end_cip = plugin->pcode + plugin->pcode_size; @@ -2584,8 +2619,8 @@ jit_rewind: if (data->error_set != SP_ERROR_NONE) { *err = data->error_set; - AbortCompilation(co); - return NULL; + co->Abort(); + return false; } } /* Write these last because error jumps should be unpredicted, and thus forward */ @@ -2627,23 +2662,29 @@ jit_rewind: * FOURTH PASS - Context Setup *************/ - sp_context_t *ctx = new sp_context_t; - memset(ctx, 0, sizeof(sp_context_t)); - /* setup basics */ - ctx->codebase = writer.outbase; - ctx->plugin = plugin; - ctx->vmbase = this; - ctx->flags = (data->debug ? SPFLAG_PLUGIN_DEBUG : 0); + sp_context_t *ctx = data->runtime->GetBaseContext()->GetCtx(); + + /* Clear out any old cruft */ + 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 */ - ctx->memory = new uint8_t[plugin->memory]; - memcpy(ctx->memory, plugin->data, plugin->data_size); - ctx->mem_size = plugin->memory; - ctx->heap_base = plugin->data_size; - ctx->hp = ctx->heap_base; - ctx->sp = ctx->mem_size - sizeof(cell_t); - ctx->prof_flags = data->profile; + + ctx->hp = plugin->data_size; + ctx->sp = plugin->mem_size - sizeof(cell_t); + ctx->frm = ctx->sp; + ctx->n_err = SP_ERROR_NONE; + ctx->n_idx = SP_ERROR_NONE; + plugin->prof_flags = data->profile; + plugin->flags = data->debug ? SPFLAG_PLUGIN_DEBUG : 0; const char *strbase = plugin->info.stringbase; uint32_t max, iter; @@ -2651,39 +2692,42 @@ jit_rewind: /* relocate public info */ 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; iterpublics[iter].name = strbase + plugin->info.publics[iter].name; - ctx->publics[iter].code_offs = RelocLookup(jit, plugin->info.publics[iter].address, false); + plugin->publics[iter].name = strbase + plugin->info.publics[iter].name; + plugin->publics[iter].code_offs = RelocLookup(jit, plugin->info.publics[iter].address, false); /* 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 */ if ((max = plugin->info.pubvars_num)) { - uint8_t *dat = ctx->memory; - ctx->pubvars = new sp_pubvar_t[max]; + uint8_t *dat = plugin->memory; + plugin->pubvars = new sp_pubvar_t[max]; + plugin->jit_memsize += sizeof(sp_pubvar_t) * max; for (iter=0; iterpubvars[iter].name = strbase + plugin->info.pubvars[iter].name; - ctx->pubvars[iter].offs = (cell_t *)(dat + plugin->info.pubvars[iter].address); + plugin->pubvars[iter].name = strbase + plugin->info.pubvars[iter].name; + plugin->pubvars[iter].offs = (cell_t *)(dat + plugin->info.pubvars[iter].address); } } /* relocate native info */ 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; iternatives[iter].name = strbase + plugin->info.natives[iter].name; - ctx->natives[iter].pfn = &InvalidNative; - ctx->natives[iter].status = SP_NATIVE_UNBOUND; - ctx->natives[iter].flags = 0; - ctx->natives[iter].user = NULL; + plugin->natives[iter].name = strbase + plugin->info.natives[iter].name; + plugin->natives[iter].pfn = &InvalidNative; + plugin->natives[iter].status = SP_NATIVE_UNBOUND; + plugin->natives[iter].flags = 0; + plugin->natives[iter].user = NULL; } } @@ -2696,20 +2740,22 @@ jit_rewind: /* relocate files */ 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; iterfiles[iter].addr = RelocLookup(jit, plugin->debug.files[iter].addr, false); - ctx->files[iter].name = strbase + plugin->debug.files[iter].name; + plugin->files[iter].addr = RelocLookup(jit, plugin->debug.files[iter].addr, false); + plugin->files[iter].name = strbase + plugin->debug.files[iter].name; } /* relocate lines */ 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; iterlines[iter].addr = RelocLookup(jit, plugin->debug.lines[iter].addr, false); - ctx->lines[iter].line = plugin->debug.lines[iter].line; + plugin->lines[iter].addr = RelocLookup(jit, plugin->debug.lines[iter].addr, false); + plugin->lines[iter].line = plugin->debug.lines[iter].line; } /* relocate arrays */ @@ -2718,7 +2764,8 @@ jit_rewind: uint8_t *cursor = (uint8_t *)(plugin->debug.symbols); 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; itercodestart > data->codesize) { - ctx->symbols[iter].codestart = 0; + plugin->symbols[iter].codestart = 0; } else { - ctx->symbols[iter].codestart = RelocLookup(jit, sym->codestart, false); + plugin->symbols[iter].codestart = RelocLookup(jit, sym->codestart, false); } if (sym->codeend > data->codesize) { - ctx->symbols[iter].codeend = data->codesize; + plugin->symbols[iter].codeend = data->codesize; } 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; - ctx->symbols[iter].sym = sym; + plugin->symbols[iter].name = strbase + sym->name; + plugin->symbols[iter].sym = sym; if (sym->dimcount > 0) { cursor += sizeof(sp_fdbg_symbol_t); arr = (sp_fdbg_arraydim_t *)cursor; - ctx->symbols[iter].dims = arr; + plugin->symbols[iter].dims = arr; cursor += sizeof(sp_fdbg_arraydim_t) * sym->dimcount; continue; } - ctx->symbols[iter].dims = NULL; + plugin->symbols[iter].dims = NULL; cursor += sizeof(sp_fdbg_symbol_t); } } tracker_t *trk = new tracker_t; 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->pCur = trk->pBase; trk->size = 1024 / sizeof(cell_t); - functracker_t *fnc = new functracker_t; - ctx->vm[JITVARS_FUNCINFO] = fnc; - ctx->vm[JITVARS_REBASE] = data->rebase; - fnc->code_size = codemem; - fnc->num_functions = data->func_idx; + plugin->jit_memsize += trk->size; /* clean up relocation+compilation memory */ - data->rebase = NULL; - AbortCompilation(co); + co->Abort(); *err = SP_ERROR_NONE; - return ctx; + return true; } 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); } -const char *JITX86::GetVMName() -{ - return "JIT (x86)"; -} - -int JITX86::ContextExecute(sp_context_t *ctx, uint32_t code_idx, cell_t *result) +int JITX86::ContextExecute(sp_plugin_t *pl, sp_context_t *ctx, uint32_t code_idx, cell_t *result) { 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); } -void JITX86::FreeContext(sp_context_t *ctx) -{ - 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) +ICompilation *JITX86::StartCompilation() { 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; const char *strbase = plugin->info.stringbase; - data->plugin = plugin; - data->inline_level = JIT_INLINE_ERRORCHECKS|JIT_INLINE_NATIVES; - data->error_set = SP_ERROR_NONE; + this->runtime = runtime; - 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; iinfo.natives[i].name; if (!strcmp(name, "FloatAbs")) { - data->jit_float_table[i].found = true; - data->jit_float_table[i].index = OP_FABS; + jit_float_table[i].found = true; + jit_float_table[i].index = OP_FABS; } else if (!strcmp(name, "FloatAdd")) { - data->jit_float_table[i].found = true; - data->jit_float_table[i].index = OP_FLOATADD; + jit_float_table[i].found = true; + jit_float_table[i].index = OP_FLOATADD; } else if (!strcmp(name, "FloatSub")) { - data->jit_float_table[i].found = true; - data->jit_float_table[i].index = OP_FLOATSUB; + jit_float_table[i].found = true; + jit_float_table[i].index = OP_FLOATSUB; } else if (!strcmp(name, "FloatMul")) { - data->jit_float_table[i].found = true; - data->jit_float_table[i].index = OP_FLOATMUL; + jit_float_table[i].found = true; + jit_float_table[i].index = OP_FLOATMUL; } else if (!strcmp(name, "FloatDiv")) { - data->jit_float_table[i].found = true; - data->jit_float_table[i].index = OP_FLOATDIV; + jit_float_table[i].found = true; + jit_float_table[i].index = OP_FLOATDIV; } else if (!strcmp(name, "float")) { - data->jit_float_table[i].found = true; - data->jit_float_table[i].index = OP_FLOAT; + jit_float_table[i].found = true; + jit_float_table[i].index = OP_FLOAT; } else if (!strcmp(name, "FloatCompare")) { - data->jit_float_table[i].found = true; - data->jit_float_table[i].index = OP_FLOATCMP; + jit_float_table[i].found = true; + jit_float_table[i].index = OP_FLOATCMP; } else if (!strcmp(name, "RoundToZero")) { - data->jit_float_table[i].found = true; - data->jit_float_table[i].index = OP_RND_TO_ZERO; + jit_float_table[i].found = true; + jit_float_table[i].index = OP_RND_TO_ZERO; } else if (!strcmp(name, "RoundToCeil")) { - data->jit_float_table[i].found = true; - data->jit_float_table[i].index = OP_RND_TO_CEIL; + jit_float_table[i].found = true; + jit_float_table[i].index = OP_RND_TO_CEIL; } else if (!strcmp(name, "RoundToFloor")) { - data->jit_float_table[i].found = true; - data->jit_float_table[i].index = OP_RND_TO_FLOOR; + jit_float_table[i].found = true; + jit_float_table[i].index = OP_RND_TO_FLOOR; } else if (!strcmp(name, "RoundToNearest")) { - data->jit_float_table[i].found = true; - data->jit_float_table[i].index = OP_RND_TO_NEAREST; + jit_float_table[i].found = true; + jit_float_table[i].index = OP_RND_TO_NEAREST; } } +} + +ICompilation *JITX86::StartCompilation(BaseRuntime *runtime) +{ + CompData *data = new CompData; + + data->SetRuntime(runtime); 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 (CompData *)co; + delete [] jit_float_table; + 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 ((atoi(val) == 1) || !strcmp(val, "yes")) { - data->debug = true; + debug = true; } 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 true; } else if (strcmp(key, SP_JITCONF_PROFILE) == 0) { - data->profile = atoi(val); + profile = atoi(val); /** 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; @@ -2979,83 +3047,3 @@ bool JITX86::SetCompilationOption(ICompilation *co, const char *key, const char 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"; -} diff --git a/sourcepawn/jit/x86/jit_x86.h b/sourcepawn/jit/x86/jit_x86.h index 9e093831..7b8bdf31 100644 --- a/sourcepawn/jit/x86/jit_x86.h +++ b/sourcepawn/jit/x86/jit_x86.h @@ -35,6 +35,8 @@ #include #include #include +#include "../jit_shared.h" +#include "../BaseRuntime.h" using namespace SourcePawn; @@ -44,11 +46,14 @@ using namespace SourcePawn; #define JIT_FUNCMAGIC 0x214D4148 //magic function offset #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_REBASE 2 //important: hi, i'm bail +#define JITVARS_BASECTX 1 //important: don't change this aWOAWOGJQG I LIKE HAM +#define JITVARS_PROFILER 2 //profiler +#define JITVARS_PLUGIN 3 //sp_plugin_t #define sDIMEN_MAX 5 //this must mirror what the compiler has. +#define GET_CONTEXT(c) ((IPluginContext *)c->vm[JITVARS_BASECTX]) + typedef struct tracker_s { size_t size; @@ -87,7 +92,11 @@ public: error_set(SP_ERROR_NONE), func_idx(0) { }; + bool SetOption(const char *key, const char *val); + void SetRuntime(BaseRuntime *runtime); + void Abort(); public: + BaseRuntime *runtime; /* runtime handle */ sp_plugin_t *plugin; /* plugin handle */ bool debug; /* whether to compile debug mode */ int profile; /* profiling flags */ @@ -116,22 +125,15 @@ public: uint32_t codesize; /* total codesize */ }; -class JITX86 : public IVirtualMachine +class JITX86 { public: - const char *GetVMName(); - ICompilation *StartCompilation(sp_plugin_t *plugin); - bool SetCompilationOption(ICompilation *co, const char *key, const char *val); - sp_context_t *CompileToContext(ICompilation *co, int *err); - void AbortCompilation(ICompilation *co); - void FreeContext(sp_context_t *ctx); - 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(); + ICompilation *StartCompilation(BaseRuntime *runtime); + ICompilation *StartCompilation(); + bool Compile(ICompilation *co, BaseRuntime *runtime, int *err); + void FreePluginVars(sp_plugin_t *pl); + void FreeContextVars(sp_context_t *ctx); + int ContextExecute(sp_plugin_t *pl, sp_context_t *ctx, uint32_t code_idx, cell_t *result); SPVM_NATIVE_FUNC CreateFakeNative(SPVM_FAKENATIVE_FUNC callback, void *pData); 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_STACKTOP 16 //relocated -extern ISourcePawnEngine *engine; +extern JITX86 g_Jit1; #endif //_INCLUDE_SOURCEPAWN_JIT_X86_H_ diff --git a/sourcepawn/jit/x86/opcode_helpers.cpp b/sourcepawn/jit/x86/opcode_helpers.cpp index 8ec41cb6..2b12036c 100644 --- a/sourcepawn/jit/x86/opcode_helpers.cpp +++ b/sourcepawn/jit/x86/opcode_helpers.cpp @@ -40,6 +40,7 @@ jitoffs_t Write_Execute_Function(JitWriter *jit) { + CompData *co = (CompData *)jit->data; /** * The variables we're passed in: * 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 ecx, [eax+] - get heap pointer //mov [esi+4], ecx - store heap into info pointer - //mov ebp, [eax+] - get data pointer + //mov ebp, - get data pointer 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_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_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_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 */ //mov edi, [eax+] - get stack pointer @@ -97,15 +98,23 @@ jitoffs_t Write_Execute_Function(JitWriter *jit) //mov ecx, [eax+] - copy memsize to temp var //add ecx, ebp - relocate //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_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_ECX, AMX_INFO_STACKTOP); /* 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) - //add ecx, [eax+] - add code base to index + //push eax + //mov eax, + //mov eax, [eax] + //add ecx, eax + //pop eax 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 */ //call ecx @@ -161,36 +170,30 @@ void Write_BreakDebug(JitWriter *jit) //push edi //mov edi, ecx //mov ecx, [esi+ctx] - //cmp [ecx+dbreak], 0 - //jnz :nocall IA32_Push_Reg(jit, REG_EDI); 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_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 /* NOTE, Hack! PUSHAD pushes EDI last which still has the CIP */ //pushad //push [esi+frm] - //push ctx - //mov ecx, [ecx+dbreak] + //push [ctx+basectx] + //mov ecx, //call ecx //add esp, 8 //popad 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_Reg(jit, AMX_REG_TMP); - IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_TMP, offsetof(sp_context_t, dbreak)); + IA32_Push_Rm_Disp8(jit, AMX_REG_TMP, offsetof(sp_context_t, vm[JITVARS_BASECTX])); + IA32_Mov_Reg_Imm32(jit, AMX_REG_TMP, jit_int32_t(((CompData *)jit->data)->plugin->dbreak)); IA32_Call_Reg(jit, AMX_REG_TMP); IA32_Add_Rm_Imm8(jit, REG_ESP, 4*2, MOD_REG); IA32_Popad(jit); - //:nocall //pop edi //ret IA32_Pop_Reg(jit, REG_EDI); - IA32_Send_Jump8_Here(jit, jmp); 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 */ //cmp , //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); /* Part 2: Check if we're in the invalid region between HP and SP */ diff --git a/core/zlib/adler32.c b/sourcepawn/jit/zlib/adler32.c similarity index 100% rename from core/zlib/adler32.c rename to sourcepawn/jit/zlib/adler32.c diff --git a/core/zlib/compress.c b/sourcepawn/jit/zlib/compress.c similarity index 100% rename from core/zlib/compress.c rename to sourcepawn/jit/zlib/compress.c diff --git a/core/zlib/crc32.c b/sourcepawn/jit/zlib/crc32.c similarity index 100% rename from core/zlib/crc32.c rename to sourcepawn/jit/zlib/crc32.c diff --git a/core/zlib/crc32.h b/sourcepawn/jit/zlib/crc32.h similarity index 100% rename from core/zlib/crc32.h rename to sourcepawn/jit/zlib/crc32.h diff --git a/core/zlib/deflate.c b/sourcepawn/jit/zlib/deflate.c similarity index 100% rename from core/zlib/deflate.c rename to sourcepawn/jit/zlib/deflate.c diff --git a/core/zlib/deflate.h b/sourcepawn/jit/zlib/deflate.h similarity index 100% rename from core/zlib/deflate.h rename to sourcepawn/jit/zlib/deflate.h diff --git a/core/zlib/gzio.c b/sourcepawn/jit/zlib/gzio.c similarity index 100% rename from core/zlib/gzio.c rename to sourcepawn/jit/zlib/gzio.c diff --git a/core/zlib/infback.c b/sourcepawn/jit/zlib/infback.c similarity index 100% rename from core/zlib/infback.c rename to sourcepawn/jit/zlib/infback.c diff --git a/core/zlib/inffast.c b/sourcepawn/jit/zlib/inffast.c similarity index 100% rename from core/zlib/inffast.c rename to sourcepawn/jit/zlib/inffast.c diff --git a/core/zlib/inffast.h b/sourcepawn/jit/zlib/inffast.h similarity index 100% rename from core/zlib/inffast.h rename to sourcepawn/jit/zlib/inffast.h diff --git a/core/zlib/inffixed.h b/sourcepawn/jit/zlib/inffixed.h similarity index 100% rename from core/zlib/inffixed.h rename to sourcepawn/jit/zlib/inffixed.h diff --git a/core/zlib/inflate.c b/sourcepawn/jit/zlib/inflate.c similarity index 100% rename from core/zlib/inflate.c rename to sourcepawn/jit/zlib/inflate.c diff --git a/core/zlib/inflate.h b/sourcepawn/jit/zlib/inflate.h similarity index 100% rename from core/zlib/inflate.h rename to sourcepawn/jit/zlib/inflate.h diff --git a/core/zlib/inftrees.c b/sourcepawn/jit/zlib/inftrees.c similarity index 100% rename from core/zlib/inftrees.c rename to sourcepawn/jit/zlib/inftrees.c diff --git a/core/zlib/inftrees.h b/sourcepawn/jit/zlib/inftrees.h similarity index 100% rename from core/zlib/inftrees.h rename to sourcepawn/jit/zlib/inftrees.h diff --git a/core/zlib/trees.c b/sourcepawn/jit/zlib/trees.c similarity index 100% rename from core/zlib/trees.c rename to sourcepawn/jit/zlib/trees.c diff --git a/core/zlib/trees.h b/sourcepawn/jit/zlib/trees.h similarity index 100% rename from core/zlib/trees.h rename to sourcepawn/jit/zlib/trees.h diff --git a/core/zlib/uncompr.c b/sourcepawn/jit/zlib/uncompr.c similarity index 100% rename from core/zlib/uncompr.c rename to sourcepawn/jit/zlib/uncompr.c diff --git a/core/zlib/zconf.h b/sourcepawn/jit/zlib/zconf.h similarity index 100% rename from core/zlib/zconf.h rename to sourcepawn/jit/zlib/zconf.h diff --git a/core/zlib/zlib.h b/sourcepawn/jit/zlib/zlib.h similarity index 100% rename from core/zlib/zlib.h rename to sourcepawn/jit/zlib/zlib.h diff --git a/core/zlib/zutil.c b/sourcepawn/jit/zlib/zutil.c similarity index 100% rename from core/zlib/zutil.c rename to sourcepawn/jit/zlib/zutil.c diff --git a/core/zlib/zutil.h b/sourcepawn/jit/zlib/zutil.h similarity index 100% rename from core/zlib/zutil.h rename to sourcepawn/jit/zlib/zutil.h