From b406c3d03d40a934555aef3a2671329869849d51 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 23 Feb 2015 22:36:10 -0800 Subject: [PATCH 1/6] Merge sp_vm_engine and engine2. --- sourcepawn/jit/compiled-function.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/sourcepawn/jit/compiled-function.cpp b/sourcepawn/jit/compiled-function.cpp index 9bf9e8fd..3e1a5b0d 100644 --- a/sourcepawn/jit/compiled-function.cpp +++ b/sourcepawn/jit/compiled-function.cpp @@ -11,6 +11,7 @@ // SourcePawn. If not, see http://www.gnu.org/licenses/. // #include "compiled-function.h" +#include "x86/jit_x86.h" #include "environment.h" using namespace sp; From 8c95919b32970ea1cd1926a8af896e5cc3e08b94 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 23 Feb 2015 23:49:39 -0800 Subject: [PATCH 2/6] Move watchdog/runtime interaction into Environment. --- sourcepawn/jit/environment.cpp | 53 +++++++++++++++++++++++++++- sourcepawn/jit/environment.h | 34 +++++++++++++++++- sourcepawn/jit/plugin-runtime.cpp | 9 ++--- sourcepawn/jit/watchdog_timer.cpp | 30 ++++++++-------- sourcepawn/jit/watchdog_timer.h | 6 +++- sourcepawn/jit/x86/jit_x86.cpp | 57 ++----------------------------- sourcepawn/jit/x86/jit_x86.h | 23 +++---------- 7 files changed, 118 insertions(+), 94 deletions(-) diff --git a/sourcepawn/jit/environment.cpp b/sourcepawn/jit/environment.cpp index 34ce296d..ea779f96 100644 --- a/sourcepawn/jit/environment.cpp +++ b/sourcepawn/jit/environment.cpp @@ -63,7 +63,7 @@ Environment::Initialize() { api_v1_ = new SourcePawnEngine(); api_v2_ = new SourcePawnEngine2(); - watchdog_timer_ = new WatchdogTimer(); + watchdog_timer_ = new WatchdogTimer(this); if ((code_pool_ = Knight::KE_CreateCodeCache()) == nullptr) return false; @@ -181,3 +181,54 @@ Environment::FreeCode(void *code) { Knight::KE_FreeCode(code_pool_, code); } + +void +Environment::RegisterRuntime(PluginRuntime *rt) +{ + mutex_.AssertCurrentThreadOwns(); + runtimes_.append(rt); +} + +void +Environment::DeregisterRuntime(PluginRuntime *rt) +{ + mutex_.AssertCurrentThreadOwns(); + runtimes_.remove(rt); +} + +void +Environment::PatchAllJumpsForTimeout() +{ + mutex_.AssertCurrentThreadOwns(); + for (ke::InlineList::iterator iter = runtimes_.begin(); iter != runtimes_.end(); iter++) { + PluginRuntime *rt = *iter; + for (size_t i = 0; i < rt->NumJitFunctions(); i++) { + CompiledFunction *fun = rt->GetJitFunction(i); + uint8_t *base = reinterpret_cast(fun->GetEntryAddress()); + + for (size_t j = 0; j < fun->NumLoopEdges(); j++) { + const LoopEdge &e = fun->GetLoopEdge(j); + int32_t diff = intptr_t(g_Jit.TimeoutStub()) - intptr_t(base + e.offset); + *reinterpret_cast(base + e.offset - 4) = diff; + } + } + } +} + +void +Environment::UnpatchAllJumpsFromTimeout() +{ + mutex_.AssertCurrentThreadOwns(); + for (ke::InlineList::iterator iter = runtimes_.begin(); iter != runtimes_.end(); iter++) { + PluginRuntime *rt = *iter; + for (size_t i = 0; i < rt->NumJitFunctions(); i++) { + CompiledFunction *fun = rt->GetJitFunction(i); + uint8_t *base = reinterpret_cast(fun->GetEntryAddress()); + + for (size_t j = 0; j < fun->NumLoopEdges(); j++) { + const LoopEdge &e = fun->GetLoopEdge(j); + *reinterpret_cast(base + e.offset - 4) = e.disp32; + } + } + } +} diff --git a/sourcepawn/jit/environment.h b/sourcepawn/jit/environment.h index 94b094f4..40ddd46d 100644 --- a/sourcepawn/jit/environment.h +++ b/sourcepawn/jit/environment.h @@ -15,7 +15,10 @@ #include #include // Replace with am-cxx later. +#include +#include #include "code-allocator.h" +#include "plugin-runtime.h" class PluginRuntime; @@ -59,6 +62,15 @@ class Environment : public ISourcePawnEnvironment void *AllocateCode(size_t size); void FreeCode(void *code); + // Runtime management. + void RegisterRuntime(PluginRuntime *rt); + void DeregisterRuntime(PluginRuntime *rt); + void PatchAllJumpsForTimeout(); + void UnpatchAllJumpsFromTimeout(); + ke::Mutex *lock() { + return &mutex_; + } + // Helpers. void SetProfiler(IProfilingTool *profiler) { profiler_ = profiler; @@ -89,6 +101,21 @@ class Environment : public ISourcePawnEnvironment return watchdog_timer_; } + // These are indicators used for the watchdog timer. + uintptr_t FrameId() const { + return frame_id_; + } + bool RunningCode() const { + return invoke_depth_ != 0; + } + void EnterInvoke() { + if (invoke_depth_++ == 0) + frame_id_++; + } + void LeaveInvoke() { + invoke_depth_--; + } + private: bool Initialize(); @@ -96,6 +123,7 @@ class Environment : public ISourcePawnEnvironment ke::AutoPtr api_v1_; ke::AutoPtr api_v2_; ke::AutoPtr watchdog_timer_; + ke::Mutex mutex_; IDebugListener *debugger_; IProfilingTool *profiler_; @@ -103,6 +131,10 @@ class Environment : public ISourcePawnEnvironment bool profiling_enabled_; Knight::KeCodeCache *code_pool_; + ke::InlineList runtimes_; + + uintptr_t frame_id_; + uintptr_t invoke_depth_; }; class EnterProfileScope @@ -121,6 +153,6 @@ class EnterProfileScope } }; -} +} // namespace sp #endif // _include_sourcepawn_vm_environment_h_ diff --git a/sourcepawn/jit/plugin-runtime.cpp b/sourcepawn/jit/plugin-runtime.cpp index 1aa0962b..7afe77b3 100644 --- a/sourcepawn/jit/plugin-runtime.cpp +++ b/sourcepawn/jit/plugin-runtime.cpp @@ -17,6 +17,7 @@ #include "plugin-runtime.h" #include "x86/jit_x86.h" #include "sp_vm_basecontext.h" +#include "environment.h" #include "md5/md5.h" @@ -48,8 +49,8 @@ PluginRuntime::PluginRuntime() memset(m_CodeHash, 0, sizeof(m_CodeHash)); memset(m_DataHash, 0, sizeof(m_DataHash)); - ke::AutoLock lock(g_Jit.Mutex()); - g_Jit.RegisterRuntime(this); + ke::AutoLock lock(Environment::get()->lock()); + Environment::get()->RegisterRuntime(this); } PluginRuntime::~PluginRuntime() @@ -58,9 +59,9 @@ PluginRuntime::~PluginRuntime() // runtimes. It is not enough to ensure that the unlinking of the runtime is // protected; we cannot delete functions or code while the watchdog might be // executing. Therefore, the entire destructor is guarded. - ke::AutoLock lock(g_Jit.Mutex()); + ke::AutoLock lock(Environment::get()->lock()); - g_Jit.DeregisterRuntime(this); + Environment::get()->DeregisterRuntime(this); for (uint32_t i = 0; i < m_plugin.num_publics; i++) delete m_PubFuncs[i]; diff --git a/sourcepawn/jit/watchdog_timer.cpp b/sourcepawn/jit/watchdog_timer.cpp index f1d2a81b..54373b73 100644 --- a/sourcepawn/jit/watchdog_timer.cpp +++ b/sourcepawn/jit/watchdog_timer.cpp @@ -15,15 +15,17 @@ // You should have received a copy of the GNU General Public License // along with SourcePawn. If not, see . #include "watchdog_timer.h" -#include "x86/jit_x86.h" #include +#include "environment.h" +//#include "x86/jit_x86.h" -WatchdogTimer::WatchdogTimer() - : terminate_(false), - mainthread_(ke::GetCurrentThreadId()), - last_frame_id_(0), - second_timeout_(false), - timedout_(false) +WatchdogTimer::WatchdogTimer(Environment *env) + : env_(env), + terminate_(false), + mainthread_(ke::GetCurrentThreadId()), + last_frame_id_(0), + second_timeout_(false), + timedout_(false) { } @@ -68,7 +70,7 @@ WatchdogTimer::Run() ke::AutoLock lock(&cv_); // Initialize the frame id, so we don't have to wait longer on startup. - last_frame_id_ = g_Jit.FrameId(); + last_frame_id_ = env_->FrameId(); while (!terminate_) { ke::WaitResult rv = cv_.Wait(timeout_ms_ / 2); @@ -89,8 +91,8 @@ WatchdogTimer::Run() // Note that it's okay if these two race: it's just a heuristic, and // worst case, we'll miss something that might have timed out but // ended up resuming. - uintptr_t frame_id = g_Jit.FrameId(); - if (frame_id != last_frame_id_ || !g_Jit.RunningCode()) { + uintptr_t frame_id = env_->FrameId(); + if (frame_id != last_frame_id_ || !env_->RunningCode()) { last_frame_id_ = frame_id; second_timeout_ = false; continue; @@ -105,7 +107,7 @@ WatchdogTimer::Run() { // Prevent the JIT from linking or destroying runtimes and functions. - ke::AutoLock lock(g_Jit.Mutex()); + ke::AutoLock lock(env_->lock()); // Set the timeout notification bit. If this is detected before any patched // JIT backedges are reached, the main thread will attempt to acquire the @@ -115,7 +117,7 @@ WatchdogTimer::Run() // Patch all jumps. This can race with the main thread's execution since // all code writes are 32-bit integer instruction operands, which are // guaranteed to be atomic on x86. - g_Jit.PatchAllJumpsForTimeout(); + env_->PatchAllJumpsForTimeout(); } // The JIT will be free to compile new functions while we wait, but it will @@ -141,8 +143,8 @@ WatchdogTimer::NotifyTimeoutReceived() // notification, and is therefore blocked. We take the JIT lock // anyway for sanity. { - ke::AutoLock lock(g_Jit.Mutex()); - g_Jit.UnpatchAllJumpsFromTimeout(); + ke::AutoLock lock(env_->lock()); + env_->UnpatchAllJumpsFromTimeout(); } timedout_ = false; diff --git a/sourcepawn/jit/watchdog_timer.h b/sourcepawn/jit/watchdog_timer.h index 7891bc22..e7242241 100644 --- a/sourcepawn/jit/watchdog_timer.h +++ b/sourcepawn/jit/watchdog_timer.h @@ -23,12 +23,14 @@ namespace sp { +class Environment; + typedef bool (*WatchdogCallback)(); class WatchdogTimer : public ke::IRunnable { public: - WatchdogTimer(); + WatchdogTimer(Environment *env); ~WatchdogTimer(); bool Initialize(size_t timeout_ms); @@ -43,6 +45,8 @@ class WatchdogTimer : public ke::IRunnable void Run(); private: + Environment *env_; + bool terminate_; size_t timeout_ms_; ke::ThreadId mainthread_; diff --git a/sourcepawn/jit/x86/jit_x86.cpp b/sourcepawn/jit/x86/jit_x86.cpp index 09c5c698..9c362e9a 100644 --- a/sourcepawn/jit/x86/jit_x86.cpp +++ b/sourcepawn/jit/x86/jit_x86.cpp @@ -1928,7 +1928,7 @@ JITX86::CompileFunction(PluginRuntime *prt, cell_t pcode_offs, int *err) // Grab the lock before linking code in, since the watchdog timer will look // at this list on another thread. - ke::AutoLock lock(g_Jit.Mutex()); + ke::AutoLock lock(Environment::get()->lock()); prt->AddJittedFunction(fun); return fun; @@ -2031,62 +2031,11 @@ JITX86::InvokeFunction(PluginRuntime *runtime, CompiledFunction *fn, cell_t *res JIT_EXECUTE pfn = (JIT_EXECUTE)m_pJitEntry; - if (level_++ == 0) - frame_id_++; + Environment::get()->EnterInvoke(); int err = pfn(ctx, runtime->plugin()->memory, fn->GetEntryAddress()); - level_--; + Environment::get()->LeaveInvoke(); *result = ctx->rval; return err; } -void -JITX86::RegisterRuntime(PluginRuntime *rt) -{ - mutex_.AssertCurrentThreadOwns(); - runtimes_.append(rt); -} - -void -JITX86::DeregisterRuntime(PluginRuntime *rt) -{ - mutex_.AssertCurrentThreadOwns(); - runtimes_.remove(rt); -} - -void -JITX86::PatchAllJumpsForTimeout() -{ - mutex_.AssertCurrentThreadOwns(); - for (ke::InlineList::iterator iter = runtimes_.begin(); iter != runtimes_.end(); iter++) { - PluginRuntime *rt = *iter; - for (size_t i = 0; i < rt->NumJitFunctions(); i++) { - CompiledFunction *fun = rt->GetJitFunction(i); - uint8_t *base = reinterpret_cast(fun->GetEntryAddress()); - - for (size_t j = 0; j < fun->NumLoopEdges(); j++) { - const LoopEdge &e = fun->GetLoopEdge(j); - int32_t diff = intptr_t(m_pJitTimeout) - intptr_t(base + e.offset); - *reinterpret_cast(base + e.offset - 4) = diff; - } - } - } -} - -void -JITX86::UnpatchAllJumpsFromTimeout() -{ - mutex_.AssertCurrentThreadOwns(); - for (ke::InlineList::iterator iter = runtimes_.begin(); iter != runtimes_.end(); iter++) { - PluginRuntime *rt = *iter; - for (size_t i = 0; i < rt->NumJitFunctions(); i++) { - CompiledFunction *fun = rt->GetJitFunction(i); - uint8_t *base = reinterpret_cast(fun->GetEntryAddress()); - - for (size_t j = 0; j < fun->NumLoopEdges(); j++) { - const LoopEdge &e = fun->GetLoopEdge(j); - *reinterpret_cast(base + e.offset - 4) = e.disp32; - } - } - } -} diff --git a/sourcepawn/jit/x86/jit_x86.h b/sourcepawn/jit/x86/jit_x86.h index de1e98c7..e48d8de7 100644 --- a/sourcepawn/jit/x86/jit_x86.h +++ b/sourcepawn/jit/x86/jit_x86.h @@ -26,7 +26,6 @@ #include "sp_vm_basecontext.h" #include "compiled-function.h" #include "opcodes.h" -#include using namespace SourcePawn; @@ -163,33 +162,19 @@ class JITX86 ICompilation *ApplyOptions(ICompilation *_IN, ICompilation *_OUT); int InvokeFunction(PluginRuntime *runtime, CompiledFunction *fn, cell_t *result); - void RegisterRuntime(PluginRuntime *rt); - void DeregisterRuntime(PluginRuntime *rt); - void PatchAllJumpsForTimeout(); - void UnpatchAllJumpsFromTimeout(); - + void *TimeoutStub() const { + return m_pJitTimeout; + } + public: ExternalAddress GetUniversalReturn() { return ExternalAddress(m_pJitReturn); } - uintptr_t FrameId() const { - return frame_id_; - } - bool RunningCode() const { - return level_ != 0; - } - ke::Mutex *Mutex() { - return &mutex_; - } private: void *m_pJitEntry; /* Entry function */ void *m_pJitReturn; /* Universal return address */ void *m_pJitTimeout; /* Universal timeout address */ - ke::InlineList runtimes_; - uintptr_t frame_id_; - uintptr_t level_; - ke::Mutex mutex_; }; const Register pri = eax; From 8cf3e227ea8577fddd332ebfda19335aa762e12e Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 24 Feb 2015 00:06:49 -0800 Subject: [PATCH 3/6] Move context var initialization into BaseContext. --- sourcepawn/jit/sp_vm_basecontext.cpp | 10 ++++++++-- sourcepawn/jit/x86/jit_x86.cpp | 18 ------------------ sourcepawn/jit/x86/jit_x86.h | 2 -- 3 files changed, 8 insertions(+), 22 deletions(-) diff --git a/sourcepawn/jit/sp_vm_basecontext.cpp b/sourcepawn/jit/sp_vm_basecontext.cpp index c96e7c1a..7f460a64 100644 --- a/sourcepawn/jit/sp_vm_basecontext.cpp +++ b/sourcepawn/jit/sp_vm_basecontext.cpp @@ -58,12 +58,18 @@ BaseContext::BaseContext(PluginRuntime *pRuntime) m_ctx.n_idx = SP_ERROR_NONE; m_ctx.rp = 0; - g_Jit.SetupContextVars(m_pRuntime, this, &m_ctx); + m_ctx.tracker = new tracker_t; + m_ctx.tracker->pBase = (ucell_t *)malloc(1024); + m_ctx.tracker->pCur = m_ctx.tracker->pBase; + m_ctx.tracker->size = 1024 / sizeof(cell_t); + m_ctx.basecx = this; + m_ctx.plugin = const_cast(pRuntime->plugin()); } BaseContext::~BaseContext() { - g_Jit.FreeContextVars(&m_ctx); + free(m_ctx.tracker->pBase); + delete m_ctx.tracker; } IVirtualMachine * diff --git a/sourcepawn/jit/x86/jit_x86.cpp b/sourcepawn/jit/x86/jit_x86.cpp index 9c362e9a..0f0be507 100644 --- a/sourcepawn/jit/x86/jit_x86.cpp +++ b/sourcepawn/jit/x86/jit_x86.cpp @@ -1934,17 +1934,6 @@ JITX86::CompileFunction(PluginRuntime *prt, cell_t pcode_offs, int *err) return fun; } -void -JITX86::SetupContextVars(PluginRuntime *runtime, BaseContext *pCtx, sp_context_t *ctx) -{ - ctx->tracker = new tracker_t; - ctx->tracker->pBase = (ucell_t *)malloc(1024); - ctx->tracker->pCur = ctx->tracker->pBase; - ctx->tracker->size = 1024 / sizeof(cell_t); - ctx->basecx = pCtx; - ctx->plugin = const_cast(runtime->plugin()); -} - SPVM_NATIVE_FUNC JITX86::CreateFakeNative(SPVM_FAKENATIVE_FUNC callback, void *pData) { @@ -1996,13 +1985,6 @@ CompData::Abort() delete this; } -void -JITX86::FreeContextVars(sp_context_t *ctx) -{ - free(ctx->tracker->pBase); - delete ctx->tracker; -} - bool CompData::SetOption(const char *key, const char *val) { diff --git a/sourcepawn/jit/x86/jit_x86.h b/sourcepawn/jit/x86/jit_x86.h index e48d8de7..7bb5bb0e 100644 --- a/sourcepawn/jit/x86/jit_x86.h +++ b/sourcepawn/jit/x86/jit_x86.h @@ -154,8 +154,6 @@ class JITX86 void ShutdownJIT(); ICompilation *StartCompilation(PluginRuntime *runtime); ICompilation *StartCompilation(); - void SetupContextVars(PluginRuntime *runtime, BaseContext *pCtx, sp_context_t *ctx); - void FreeContextVars(sp_context_t *ctx); SPVM_NATIVE_FUNC CreateFakeNative(SPVM_FAKENATIVE_FUNC callback, void *pData); void DestroyFakeNative(SPVM_NATIVE_FUNC func); CompiledFunction *CompileFunction(PluginRuntime *runtime, cell_t pcode_offs, int *err); From 21f5400d9cc8cddb2258ebac4a5e6a7bc327cf0c Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 24 Feb 2015 00:21:52 -0800 Subject: [PATCH 4/6] Remove ICompilationData. --- core/logic/PluginSys.cpp | 10 +----- public/sourcepawn/sp_vm_api.h | 35 +++++---------------- sourcepawn/jit/api.cpp | 13 ++++---- sourcepawn/jit/plugin-runtime.cpp | 11 ------- sourcepawn/jit/plugin-runtime.h | 3 -- sourcepawn/jit/x86/jit_x86.cpp | 51 ------------------------------- sourcepawn/jit/x86/jit_x86.h | 22 ------------- 7 files changed, 15 insertions(+), 130 deletions(-) diff --git a/core/logic/PluginSys.cpp b/core/logic/PluginSys.cpp index 2a5e2597..db4611cf 100644 --- a/core/logic/PluginSys.cpp +++ b/core/logic/PluginSys.cpp @@ -931,20 +931,12 @@ LoadRes CPluginManager::_LoadPlugin(CPlugin **aResult, const char *path, bool de pPlugin->m_type = PluginType_MapUpdated; - ICompilation *co = NULL; - if (pPlugin->m_status == Plugin_Uncompiled) - { - co = g_pSourcePawn2->StartCompilation(); - } - - /* Do the actual compiling */ - if (co != NULL) { char fullpath[PLATFORM_MAX_PATH]; g_pSM->BuildPath(Path_SM, fullpath, sizeof(fullpath), "plugins/%s", pPlugin->m_filename); - pPlugin->m_pRuntime = g_pSourcePawn2->LoadPlugin(co, fullpath, &err); + pPlugin->m_pRuntime = g_pSourcePawn2->LoadPlugin(nullptr, fullpath, &err); if (pPlugin->m_pRuntime == NULL) { if (error) diff --git a/public/sourcepawn/sp_vm_api.h b/public/sourcepawn/sp_vm_api.h index 9c7f45b8..653b2c4f 100644 --- a/public/sourcepawn/sp_vm_api.h +++ b/public/sourcepawn/sp_vm_api.h @@ -274,26 +274,7 @@ namespace SourcePawn virtual int LookupLine(ucell_t addr, uint32_t *line) =0; }; - /** - * @brief Represents a JIT compilation or plugin loading options. - */ - class ICompilation - { - public: - /** - * @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; - }; + class ICompilation; /** * @brief Interface to managing a runtime plugin. @@ -425,11 +406,9 @@ namespace SourcePawn virtual bool IsDebugging() =0; /** - * @brief Applies new compilation/runtime settings to the runtime code. + * @brief If |co| is non-NULL, destroys |co|. No other action is taken. * - * The compilation object is destroyed once this function completes. - * - * @return Error code (SP_ERROR_NONE on success). + * @return Returns SP_ERROR_NONE. */ virtual int ApplyCompilationOptions(ICompilation *co) =0; @@ -1194,9 +1173,9 @@ namespace SourcePawn virtual const char *GetVersionString() =0; /** - * @brief Creates a new compilation options object. + * @brief Deprecated. Returns null. * - * @return Compilation options object. + * @return Null. */ virtual ICompilation *StartCompilation() =0; @@ -1206,10 +1185,10 @@ namespace SourcePawn * If a compilation object is supplied, it is destroyed upon * the function's return. * - * @param co Compilation options, or NULL for defaults. + * @param co Must be NULL. * @param file Path to the file to compile. * @param err Error code (filled on failure); required. - * @return New runtime pointer, or NULL on failure. + * @return New runtime pointer, or NULL on failure. */ virtual IPluginRuntime *LoadPlugin(ICompilation *co, const char *file, int *err) =0; diff --git a/sourcepawn/jit/api.cpp b/sourcepawn/jit/api.cpp index c205e241..4b577d4d 100644 --- a/sourcepawn/jit/api.cpp +++ b/sourcepawn/jit/api.cpp @@ -185,6 +185,12 @@ SourcePawnEngine2::LoadPlugin(ICompilation *co, const char *file, int *err) size_t ignore; PluginRuntime *pRuntime; + if (co) { + if (err) + *err = SP_ERROR_PARAM; + return nullptr; + } + FILE *fp = fopen(file, "rb"); if (!fp) { @@ -275,8 +281,6 @@ SourcePawnEngine2::LoadPlugin(ICompilation *co, const char *file, int *err) if (!pRuntime->plugin()->name) pRuntime->SetName(file); - pRuntime->ApplyCompilationOptions(co); - fclose(fp); return pRuntime; @@ -332,7 +336,7 @@ SourcePawnEngine2::GetAPIVersion() ICompilation * SourcePawnEngine2::StartCompilation() { - return g_Jit.StartCompilation(); + return nullptr; } const char * @@ -364,9 +368,6 @@ SourcePawnEngine2::CreateEmptyRuntime(const char *name, uint32_t memory) } rt->SetName(name != NULL ? name : ""); - - rt->ApplyCompilationOptions(NULL); - return rt; } diff --git a/sourcepawn/jit/plugin-runtime.cpp b/sourcepawn/jit/plugin-runtime.cpp index 7afe77b3..029d952a 100644 --- a/sourcepawn/jit/plugin-runtime.cpp +++ b/sourcepawn/jit/plugin-runtime.cpp @@ -35,7 +35,6 @@ PluginRuntime::PluginRuntime() m_pCtx(NULL), m_PubFuncs(NULL), m_PubJitFuncs(NULL), - co_(NULL), m_CompSerial(0) { memset(&m_plugin, 0, sizeof(m_plugin)); @@ -75,8 +74,6 @@ PluginRuntime::~PluginRuntime() delete m_JitFunctions[i]; delete m_pCtx; - if (co_) - co_->Abort(); free(m_plugin.base); delete [] m_plugin.memory; @@ -304,7 +301,6 @@ int PluginRuntime::CreateFromMemory(sp_file_hdr_t *hdr, uint8_t *base) md5_data.raw_digest(m_DataHash); m_pCtx = new BaseContext(this); - co_ = g_Jit.StartCompilation(this); SetupFloatNativeRemapping(); function_map_size_ = m_plugin.pcode_size / sizeof(cell_t) + 1; @@ -587,12 +583,6 @@ BaseContext *PluginRuntime::GetBaseContext() int PluginRuntime::ApplyCompilationOptions(ICompilation *co) { - if (co == NULL) - return SP_ERROR_NONE; - - co_ = g_Jit.ApplyOptions(co_, co); - m_plugin.prof_flags = ((CompData *)co_)->profile; - return SP_ERROR_NONE; } @@ -609,7 +599,6 @@ PluginRuntime::CreateBlank(uint32_t heastk) m_plugin.memory = new uint8_t[heastk]; m_pCtx = new BaseContext(this); - co_ = g_Jit.StartCompilation(this); return SP_ERROR_NONE; } diff --git a/sourcepawn/jit/plugin-runtime.h b/sourcepawn/jit/plugin-runtime.h index 01365d69..f08c5342 100644 --- a/sourcepawn/jit/plugin-runtime.h +++ b/sourcepawn/jit/plugin-runtime.h @@ -115,9 +115,6 @@ class PluginRuntime ScriptedInvoker **m_PubFuncs; CompiledFunction **m_PubJitFuncs; - private: - ICompilation *co_; - public: unsigned int m_CompSerial; diff --git a/sourcepawn/jit/x86/jit_x86.cpp b/sourcepawn/jit/x86/jit_x86.cpp index 0f0be507..36f51247 100644 --- a/sourcepawn/jit/x86/jit_x86.cpp +++ b/sourcepawn/jit/x86/jit_x86.cpp @@ -1876,21 +1876,6 @@ GenerateEntry(void **retp, void **timeoutp) return code; } -ICompilation *JITX86::ApplyOptions(ICompilation *_IN, ICompilation *_OUT) -{ - if (_IN == NULL) - return _OUT; - - CompData *_in = (CompData * )_IN; - CompData *_out = (CompData * )_OUT; - - _in->inline_level = _out->inline_level; - _in->profile = _out->profile; - - _out->Abort(); - return _in; -} - JITX86::JITX86() { m_pJitEntry = NULL; @@ -1967,42 +1952,6 @@ JITX86::DestroyFakeNative(SPVM_NATIVE_FUNC func) Environment::get()->FreeCode((void *)func); } -ICompilation * -JITX86::StartCompilation() -{ - return new CompData; -} - -ICompilation * -JITX86::StartCompilation(PluginRuntime *runtime) -{ - return new CompData; -} - -void -CompData::Abort() -{ - delete this; -} - -bool -CompData::SetOption(const char *key, const char *val) -{ - if (strcmp(key, SP_JITCONF_DEBUG) == 0) - return true; - if (strcmp(key, SP_JITCONF_PROFILE) == 0) { - profile = atoi(val); - - /** Callbacks must be profiled to profile functions! */ - if ((profile & SP_PROF_FUNCTIONS) == SP_PROF_FUNCTIONS) - profile |= SP_PROF_CALLBACKS; - - return true; - } - - return false; -} - int JITX86::InvokeFunction(PluginRuntime *runtime, CompiledFunction *fn, cell_t *result) { diff --git a/sourcepawn/jit/x86/jit_x86.h b/sourcepawn/jit/x86/jit_x86.h index 7bb5bb0e..cba9051e 100644 --- a/sourcepawn/jit/x86/jit_x86.h +++ b/sourcepawn/jit/x86/jit_x86.h @@ -61,25 +61,6 @@ struct CallThunk } }; -class CompData : public ICompilation -{ -public: - CompData() - : profile(0), - inline_level(0) - { - }; - bool SetOption(const char *key, const char *val); - void Abort(); -public: - cell_t cur_func; /* current func pcode offset */ - /* Options */ - int profile; /* profiling flags */ - int inline_level; /* inline optimization level */ - /* Per-compilation properties */ - unsigned int func_idx; /* current function index */ -}; - class Compiler { public: @@ -152,12 +133,9 @@ class JITX86 public: bool InitializeJIT(); void ShutdownJIT(); - ICompilation *StartCompilation(PluginRuntime *runtime); - ICompilation *StartCompilation(); SPVM_NATIVE_FUNC CreateFakeNative(SPVM_FAKENATIVE_FUNC callback, void *pData); void DestroyFakeNative(SPVM_NATIVE_FUNC func); CompiledFunction *CompileFunction(PluginRuntime *runtime, cell_t pcode_offs, int *err); - ICompilation *ApplyOptions(ICompilation *_IN, ICompilation *_OUT); int InvokeFunction(PluginRuntime *runtime, CompiledFunction *fn, cell_t *result); void *TimeoutStub() const { From 111dd7eb68039235de7d086deca8caa6288c272d Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 24 Feb 2015 01:12:23 -0800 Subject: [PATCH 5/6] Factor code stubs out of JITX86. --- sourcepawn/jit/AMBuilder | 3 + sourcepawn/jit/api.cpp | 5 +- sourcepawn/jit/code-stubs.cpp | 41 ++++++ sourcepawn/jit/code-stubs.h | 61 +++++++++ sourcepawn/jit/environment.cpp | 28 +++- sourcepawn/jit/environment.h | 7 + sourcepawn/jit/sp_vm_basecontext.cpp | 8 +- sourcepawn/jit/x86/code-stubs-x86.cpp | 135 ++++++++++++++++++++ sourcepawn/jit/x86/jit_x86.cpp | 177 ++------------------------ sourcepawn/jit/x86/jit_x86.h | 24 +--- sourcepawn/jit/x86/x86-utils.cpp | 30 +++++ sourcepawn/jit/x86/x86-utils.h | 27 ++++ 12 files changed, 348 insertions(+), 198 deletions(-) create mode 100644 sourcepawn/jit/code-stubs.cpp create mode 100644 sourcepawn/jit/code-stubs.h create mode 100644 sourcepawn/jit/x86/code-stubs-x86.cpp create mode 100644 sourcepawn/jit/x86/x86-utils.cpp create mode 100644 sourcepawn/jit/x86/x86-utils.h diff --git a/sourcepawn/jit/AMBuilder b/sourcepawn/jit/AMBuilder index b7db32ff..b96a3211 100644 --- a/sourcepawn/jit/AMBuilder +++ b/sourcepawn/jit/AMBuilder @@ -31,6 +31,7 @@ library = setup(builder.compiler.StaticLibrary('sourcepawn')) library.sources += [ 'api.cpp', 'code-allocator.cpp', + 'code-stubs.cpp', 'plugin-runtime.cpp', 'compiled-function.cpp', 'debug-trace.cpp', @@ -40,7 +41,9 @@ library.sources += [ 'opcodes.cpp', 'interpreter.cpp', 'watchdog_timer.cpp', + 'x86/code-stubs-x86.cpp', 'x86/jit_x86.cpp', + 'x86/x86-utils.cpp', 'zlib/adler32.c', 'zlib/compress.c', 'zlib/crc32.c', diff --git a/sourcepawn/jit/api.cpp b/sourcepawn/jit/api.cpp index 4b577d4d..6c9956d7 100644 --- a/sourcepawn/jit/api.cpp +++ b/sourcepawn/jit/api.cpp @@ -33,6 +33,7 @@ #endif #include +#include "code-stubs.h" using namespace sp; using namespace SourcePawn; @@ -298,13 +299,13 @@ return_error: SPVM_NATIVE_FUNC SourcePawnEngine2::CreateFakeNative(SPVM_FAKENATIVE_FUNC callback, void *pData) { - return g_Jit.CreateFakeNative(callback, pData); + return Environment::get()->stubs()->CreateFakeNativeStub(callback, pData); } void SourcePawnEngine2::DestroyFakeNative(SPVM_NATIVE_FUNC func) { - g_Jit.DestroyFakeNative(func); + return Environment::get()->FreeCode((void *)func); } const char * diff --git a/sourcepawn/jit/code-stubs.cpp b/sourcepawn/jit/code-stubs.cpp new file mode 100644 index 00000000..252685c7 --- /dev/null +++ b/sourcepawn/jit/code-stubs.cpp @@ -0,0 +1,41 @@ +// vim: set sts=2 ts=8 sw=2 tw=99 et: +// +// Copyright (C) 2006-2015 AlliedModders LLC +// +// This file is part of SourcePawn. SourcePawn is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// You should have received a copy of the GNU General Public License along with +// SourcePawn. If not, see http://www.gnu.org/licenses/. +// +#include "code-stubs.h" +#include "environment.h" + +using namespace sp; + +CodeStubs::CodeStubs(Environment *env) + : env_(env), + invoke_stub_(nullptr), + return_stub_(nullptr), + timeout_stub_(nullptr) +{ +} + +bool +CodeStubs::Initialize() +{ + if (!InitializeFeatureDetection()) + return false; + if (!CompileInvokeStub()) + return false; + return true; +} + +void +CodeStubs::Shutdown() +{ + if (invoke_stub_) + env_->FreeCode(invoke_stub_); +} diff --git a/sourcepawn/jit/code-stubs.h b/sourcepawn/jit/code-stubs.h new file mode 100644 index 00000000..093ec7aa --- /dev/null +++ b/sourcepawn/jit/code-stubs.h @@ -0,0 +1,61 @@ +// vim: set sts=2 ts=8 sw=2 tw=99 et: +// +// Copyright (C) 2006-2015 AlliedModders LLC +// +// This file is part of SourcePawn. SourcePawn is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// You should have received a copy of the GNU General Public License along with +// SourcePawn. If not, see http://www.gnu.org/licenses/. +// +#ifndef _include_sourcepawn_vm_code_stubs_h_ +#define _include_sourcepawn_vm_code_stubs_h_ + +#include +#include + +typedef struct sp_context_s sp_context_t; + +namespace sp { + +class Environment; + +typedef int (*InvokeStubFn)(sp_context_t *ctx, uint8_t *memory, void *code); + +class CodeStubs +{ + public: + CodeStubs(Environment *env); + + public: + bool Initialize(); + void Shutdown(); + + SPVM_NATIVE_FUNC CreateFakeNativeStub(SPVM_FAKENATIVE_FUNC callback, void *userData); + + InvokeStubFn InvokeStub() const { + return (InvokeStubFn)invoke_stub_; + } + void *ReturnStub() const { + return return_stub_; + } + void *TimeoutStub() const { + return return_stub_; + } + + private: + bool InitializeFeatureDetection(); + bool CompileInvokeStub(); + + private: + Environment *env_; + void *invoke_stub_; + void *return_stub_; // Owned by invoke_stub_. + void *timeout_stub_; // Owned by invoke_stub_. +}; + +} + +#endif // _include_sourcepawn_vm_code_stubs_h_ diff --git a/sourcepawn/jit/environment.cpp b/sourcepawn/jit/environment.cpp index ea779f96..7d6a50ea 100644 --- a/sourcepawn/jit/environment.cpp +++ b/sourcepawn/jit/environment.cpp @@ -15,6 +15,7 @@ #include "watchdog_timer.h" #include "debug-trace.h" #include "api.h" +#include "code-stubs.h" #include "watchdog_timer.h" using namespace sp; @@ -63,13 +64,14 @@ Environment::Initialize() { api_v1_ = new SourcePawnEngine(); api_v2_ = new SourcePawnEngine2(); + code_stubs_ = new CodeStubs(this); watchdog_timer_ = new WatchdogTimer(this); if ((code_pool_ = Knight::KE_CreateCodeCache()) == nullptr) return false; - // Safe to initialize JIT now that we have the code cache. - if (!g_Jit.InitializeJIT()) + // Safe to initialize code now that we have the code cache. + if (!code_stubs_->Initialize()) return false; return true; @@ -79,7 +81,7 @@ void Environment::Shutdown() { watchdog_timer_->Shutdown(); - g_Jit.ShutdownJIT(); + code_stubs_->Shutdown(); Knight::KE_DestroyCodeCache(code_pool_); assert(sEnvironment == this); @@ -208,7 +210,7 @@ Environment::PatchAllJumpsForTimeout() for (size_t j = 0; j < fun->NumLoopEdges(); j++) { const LoopEdge &e = fun->GetLoopEdge(j); - int32_t diff = intptr_t(g_Jit.TimeoutStub()) - intptr_t(base + e.offset); + int32_t diff = intptr_t(code_stubs_->TimeoutStub()) - intptr_t(base + e.offset); *reinterpret_cast(base + e.offset - 4) = diff; } } @@ -232,3 +234,21 @@ Environment::UnpatchAllJumpsFromTimeout() } } } + +int +Environment::Invoke(PluginRuntime *runtime, CompiledFunction *fn, cell_t *result) +{ + sp_context_t *ctx = runtime->GetBaseContext()->GetCtx(); + + // Note that cip, hp, sp are saved and restored by Execute2(). + ctx->cip = fn->GetCodeOffset(); + + InvokeStubFn invoke = code_stubs_->InvokeStub(); + + EnterInvoke(); + int err = invoke(ctx, runtime->plugin()->memory, fn->GetEntryAddress()); + LeaveInvoke(); + + *result = ctx->rval; + return err; +} diff --git a/sourcepawn/jit/environment.h b/sourcepawn/jit/environment.h index 40ddd46d..638a4b97 100644 --- a/sourcepawn/jit/environment.h +++ b/sourcepawn/jit/environment.h @@ -26,6 +26,7 @@ namespace sp { using namespace SourcePawn; +class CodeStubs; class WatchdogTimer; // An Environment encapsulates everything that's needed to load and run @@ -61,6 +62,9 @@ class Environment : public ISourcePawnEnvironment // Allocate and free executable memory. void *AllocateCode(size_t size); void FreeCode(void *code); + CodeStubs *stubs() { + return code_stubs_; + } // Runtime management. void RegisterRuntime(PluginRuntime *rt); @@ -70,6 +74,7 @@ class Environment : public ISourcePawnEnvironment ke::Mutex *lock() { return &mutex_; } + int Invoke(PluginRuntime *runtime, CompiledFunction *fn, cell_t *result); // Helpers. void SetProfiler(IProfilingTool *profiler) { @@ -135,6 +140,8 @@ class Environment : public ISourcePawnEnvironment uintptr_t frame_id_; uintptr_t invoke_depth_; + + ke::AutoPtr code_stubs_; }; class EnterProfileScope diff --git a/sourcepawn/jit/sp_vm_basecontext.cpp b/sourcepawn/jit/sp_vm_basecontext.cpp index 7f460a64..8d14d54b 100644 --- a/sourcepawn/jit/sp_vm_basecontext.cpp +++ b/sourcepawn/jit/sp_vm_basecontext.cpp @@ -603,10 +603,10 @@ BaseContext::Execute2(IPluginFunction *function, const cell_t *params, unsigned m_CustomMsg = false; m_InExec = true; - /* Start the frame tracer */ - - if (Environment::get()->IsJitEnabled()) - ir = g_Jit.InvokeFunction(m_pRuntime, fn, result); + // Enter the execution engine. + Environment *env = Environment::get(); + if (env->IsJitEnabled()) + ir = env->Invoke(m_pRuntime, fn, result); else ir = Interpret(m_pRuntime, cfun->Public()->code_offs, result); diff --git a/sourcepawn/jit/x86/code-stubs-x86.cpp b/sourcepawn/jit/x86/code-stubs-x86.cpp new file mode 100644 index 00000000..2b7a4b94 --- /dev/null +++ b/sourcepawn/jit/x86/code-stubs-x86.cpp @@ -0,0 +1,135 @@ +// vim: set sts=2 ts=8 sw=2 tw=99 et: +// +// Copyright (C) 2006-2015 AlliedModders LLC +// +// This file is part of SourcePawn. SourcePawn is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// You should have received a copy of the GNU General Public License along with +// SourcePawn. If not, see http://www.gnu.org/licenses/. +// +#include +#include "code-stubs.h" +#include "x86-utils.h" +#include "jit_shared.h" +#include "jit_x86.h" + +using namespace sp; +using namespace SourcePawn; + +#define __ masm. + +bool +CodeStubs::InitializeFeatureDetection() +{ + MacroAssemblerX86 masm; + MacroAssemblerX86::GenerateFeatureDetection(masm); + void *code = LinkCode(env_, masm); + if (!code) + return false; + MacroAssemblerX86::RunFeatureDetection(code); + return true; +} + + +bool +CodeStubs::CompileInvokeStub() +{ + AssemblerX86 masm; + + __ push(ebp); + __ movl(ebp, esp); + + __ push(esi); // ebp - 4 + __ push(edi); // ebp - 8 + __ push(ebx); // ebp - 12 + __ push(esp); // ebp - 16 + + __ movl(ebx, Operand(ebp, 8 + 4 * 0)); + __ movl(eax, Operand(ebp, 8 + 4 * 1)); + __ movl(ecx, Operand(ebp, 8 + 4 * 2)); + + // Set up run-time registers. + __ movl(edi, Operand(ebx, offsetof(sp_context_t, sp))); + __ addl(edi, eax); + __ movl(esi, eax); + __ movl(ebx, edi); + + // Align the stack. + __ andl(esp, 0xfffffff0); + + // Call into plugin (align the stack first). + __ call(ecx); + + // Get input context, store rval. + __ movl(ecx, Operand(ebp, 8 + 4 * 0)); + __ movl(Operand(ecx, offsetof(sp_context_t, rval)), pri); + + // Set no error. + __ movl(eax, SP_ERROR_NONE); + + // Store latest stk. If we have an error code, we'll jump directly to here, + // so eax will already be set. + Label ret; + __ bind(&ret); + __ subl(stk, dat); + __ movl(Operand(ecx, offsetof(sp_context_t, sp)), stk); + + // Restore stack. + __ movl(esp, Operand(ebp, -16)); + + // Restore registers and gtfo. + __ pop(ebx); + __ pop(edi); + __ pop(esi); + __ pop(ebp); + __ ret(); + + // The universal emergency return will jump to here. + Label error; + __ bind(&error); + __ movl(ecx, Operand(ebp, 8 + 4 * 0)); // ret-path expects ecx = ctx + __ jmp(&ret); + + Label timeout; + __ bind(&timeout); + __ movl(eax, SP_ERROR_TIMEOUT); + __ jmp(&error); + + invoke_stub_ = LinkCode(env_, masm); + if (!invoke_stub_) + return false; + + return_stub_ = reinterpret_cast(invoke_stub_) + error.offset(); + timeout_stub_ = reinterpret_cast(invoke_stub_) + timeout.offset(); + return true; +} + +SPVM_NATIVE_FUNC +CodeStubs::CreateFakeNativeStub(SPVM_FAKENATIVE_FUNC callback, void *pData) +{ + AssemblerX86 masm; + + __ push(ebx); + __ push(edi); + __ push(esi); + __ movl(edi, Operand(esp, 16)); // store ctx + __ movl(esi, Operand(esp, 20)); // store params + __ movl(ebx, esp); + __ andl(esp, 0xfffffff0); + __ subl(esp, 4); + + __ push(intptr_t(pData)); + __ push(esi); + __ push(edi); + __ call(ExternalAddress((void *)callback)); + __ movl(esp, ebx); + __ pop(esi); + __ pop(edi); + __ pop(ebx); + __ ret(); + + return (SPVM_NATIVE_FUNC)LinkCode(env_, masm); +} diff --git a/sourcepawn/jit/x86/jit_x86.cpp b/sourcepawn/jit/x86/jit_x86.cpp index 36f51247..5de146a3 100644 --- a/sourcepawn/jit/x86/jit_x86.cpp +++ b/sourcepawn/jit/x86/jit_x86.cpp @@ -38,6 +38,8 @@ #include "watchdog_timer.h" #include "interpreter.h" #include "environment.h" +#include "code-stubs.h" +#include "x86-utils.h" using namespace sp; @@ -49,20 +51,6 @@ using namespace sp; JITX86 g_Jit; -static inline uint8_t * -LinkCode(AssemblerX86 &masm) -{ - if (masm.outOfMemory()) - return NULL; - - void *code = Environment::get()->AllocateCode(masm.length()); - if (!code) - return NULL; - - masm.emitToExecutableMemory(code); - return reinterpret_cast(code); -} - static inline ConditionCode OpToCondition(OPCODE op) { @@ -299,7 +287,8 @@ CompileFromThunk(PluginRuntime *runtime, cell_t pcode_offs, void **addrp, char * } Compiler::Compiler(PluginRuntime *rt, cell_t pcode_offs) - : rt_(rt), + : env_(Environment::get()), + rt_(rt), plugin_(rt->plugin()), error_(SP_ERROR_NONE), pcode_start_(pcode_offs), @@ -365,7 +354,7 @@ Compiler::emit(int *errp) emitCallThunks(); emitErrorPaths(); - uint8_t *code = LinkCode(masm); + uint8_t *code = LinkCode(env_, masm); if (!code) { *errp = SP_ERROR_OUT_OF_MEMORY; return NULL; @@ -1532,7 +1521,7 @@ Compiler::emitCallThunks() __ bind(&error); __ movl(Operand(cipAddr()), thunk->pcode_offset); - __ jmp(g_Jit.GetUniversalReturn()); + __ jmp(ExternalAddress(env_->stubs()->ReturnStub())); } } @@ -1727,7 +1716,7 @@ Compiler::emitErrorPath(Label *dest, int code) if (dest->used()) { __ bind(dest); __ movl(eax, code); - __ jmp(g_Jit.GetUniversalReturn()); + __ jmp(ExternalAddress(env_->stubs()->ReturnStub())); } } @@ -1797,109 +1786,11 @@ Compiler::emitErrorPaths() __ bind(&extern_error_); __ movl(eax, intptr_t(rt_->GetBaseContext()->GetCtx())); __ movl(eax, Operand(eax, offsetof(sp_context_t, n_err))); - __ jmp(g_Jit.GetUniversalReturn()); + __ jmp(ExternalAddress(env_->stubs()->ReturnStub())); } } -typedef int (*JIT_EXECUTE)(sp_context_t *ctx, uint8_t *memory, void *code); - -static void * -GenerateEntry(void **retp, void **timeoutp) -{ - AssemblerX86 masm; - - __ push(ebp); - __ movl(ebp, esp); - - __ push(esi); // ebp - 4 - __ push(edi); // ebp - 8 - __ push(ebx); // ebp - 12 - __ push(esp); // ebp - 16 - - __ movl(ebx, Operand(ebp, 8 + 4 * 0)); - __ movl(eax, Operand(ebp, 8 + 4 * 1)); - __ movl(ecx, Operand(ebp, 8 + 4 * 2)); - - // Set up run-time registers. - __ movl(edi, Operand(ebx, offsetof(sp_context_t, sp))); - __ addl(edi, eax); - __ movl(esi, eax); - __ movl(ebx, edi); - - // Align the stack. - __ andl(esp, 0xfffffff0); - - // Call into plugin (align the stack first). - __ call(ecx); - - // Get input context, store rval. - __ movl(ecx, Operand(ebp, 8 + 4 * 0)); - __ movl(Operand(ecx, offsetof(sp_context_t, rval)), pri); - - // Set no error. - __ movl(eax, SP_ERROR_NONE); - - // Store latest stk. If we have an error code, we'll jump directly to here, - // so eax will already be set. - Label ret; - __ bind(&ret); - __ subl(stk, dat); - __ movl(Operand(ecx, offsetof(sp_context_t, sp)), stk); - - // Restore stack. - __ movl(esp, Operand(ebp, -16)); - - // Restore registers and gtfo. - __ pop(ebx); - __ pop(edi); - __ pop(esi); - __ pop(ebp); - __ ret(); - - // The universal emergency return will jump to here. - Label error; - __ bind(&error); - __ movl(ecx, Operand(ebp, 8 + 4 * 0)); // ret-path expects ecx = ctx - __ jmp(&ret); - - Label timeout; - __ bind(&timeout); - __ movl(eax, SP_ERROR_TIMEOUT); - __ jmp(&error); - - void *code = LinkCode(masm); - if (!code) - return NULL; - - *retp = reinterpret_cast(code) + error.offset(); - *timeoutp = reinterpret_cast(code) + timeout.offset(); - return code; -} - JITX86::JITX86() -{ - m_pJitEntry = NULL; -} - -bool -JITX86::InitializeJIT() -{ - m_pJitEntry = GenerateEntry(&m_pJitReturn, &m_pJitTimeout); - if (!m_pJitEntry) - return false; - - MacroAssemblerX86 masm; - MacroAssemblerX86::GenerateFeatureDetection(masm); - void *code = LinkCode(masm); - if (!code) - return false; - MacroAssemblerX86::RunFeatureDetection(code); - - return true; -} - -void -JITX86::ShutdownJIT() { } @@ -1918,55 +1809,3 @@ JITX86::CompileFunction(PluginRuntime *prt, cell_t pcode_offs, int *err) prt->AddJittedFunction(fun); return fun; } - -SPVM_NATIVE_FUNC -JITX86::CreateFakeNative(SPVM_FAKENATIVE_FUNC callback, void *pData) -{ - AssemblerX86 masm; - - __ push(ebx); - __ push(edi); - __ push(esi); - __ movl(edi, Operand(esp, 16)); // store ctx - __ movl(esi, Operand(esp, 20)); // store params - __ movl(ebx, esp); - __ andl(esp, 0xfffffff0); - __ subl(esp, 4); - - __ push(intptr_t(pData)); - __ push(esi); - __ push(edi); - __ call(ExternalAddress((void *)callback)); - __ movl(esp, ebx); - __ pop(esi); - __ pop(edi); - __ pop(ebx); - __ ret(); - - return (SPVM_NATIVE_FUNC)LinkCode(masm); -} - -void -JITX86::DestroyFakeNative(SPVM_NATIVE_FUNC func) -{ - Environment::get()->FreeCode((void *)func); -} - -int -JITX86::InvokeFunction(PluginRuntime *runtime, CompiledFunction *fn, cell_t *result) -{ - sp_context_t *ctx = runtime->GetBaseContext()->GetCtx(); - - // Note that cip, hp, sp are saved and restored by Execute2(). - ctx->cip = fn->GetCodeOffset(); - - JIT_EXECUTE pfn = (JIT_EXECUTE)m_pJitEntry; - - Environment::get()->EnterInvoke(); - int err = pfn(ctx, runtime->plugin()->memory, fn->GetEntryAddress()); - Environment::get()->LeaveInvoke(); - - *result = ctx->rval; - return err; -} - diff --git a/sourcepawn/jit/x86/jit_x86.h b/sourcepawn/jit/x86/jit_x86.h index cba9051e..ca5abb64 100644 --- a/sourcepawn/jit/x86/jit_x86.h +++ b/sourcepawn/jit/x86/jit_x86.h @@ -29,6 +29,10 @@ using namespace SourcePawn; +namespace sp { +class Environment; +} + #define JIT_INLINE_ERRORCHECKS (1<<0) #define JIT_INLINE_NATIVES (1<<1) #define STACK_MARGIN 64 //8 parameters of safety, I guess @@ -101,6 +105,7 @@ class Compiler private: AssemblerX86 masm; + sp::Environment *env_; PluginRuntime *rt_; const sp_plugin_t *plugin_; int error_; @@ -131,26 +136,7 @@ class JITX86 JITX86(); public: - bool InitializeJIT(); - void ShutdownJIT(); - SPVM_NATIVE_FUNC CreateFakeNative(SPVM_FAKENATIVE_FUNC callback, void *pData); - void DestroyFakeNative(SPVM_NATIVE_FUNC func); CompiledFunction *CompileFunction(PluginRuntime *runtime, cell_t pcode_offs, int *err); - int InvokeFunction(PluginRuntime *runtime, CompiledFunction *fn, cell_t *result); - - void *TimeoutStub() const { - return m_pJitTimeout; - } - - public: - ExternalAddress GetUniversalReturn() { - return ExternalAddress(m_pJitReturn); - } - - private: - void *m_pJitEntry; /* Entry function */ - void *m_pJitReturn; /* Universal return address */ - void *m_pJitTimeout; /* Universal timeout address */ }; const Register pri = eax; diff --git a/sourcepawn/jit/x86/x86-utils.cpp b/sourcepawn/jit/x86/x86-utils.cpp new file mode 100644 index 00000000..4d73903c --- /dev/null +++ b/sourcepawn/jit/x86/x86-utils.cpp @@ -0,0 +1,30 @@ +// vim: set sts=2 ts=8 sw=2 tw=99 et: +// +// Copyright (C) 2006-2015 AlliedModders LLC +// +// This file is part of SourcePawn. SourcePawn is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// You should have received a copy of the GNU General Public License along with +// SourcePawn. If not, see http://www.gnu.org/licenses/. +// +#include "environment.h" +#include "x86-utils.h" + +using namespace sp; + +uint8_t * +sp::LinkCode(Environment *env, AssemblerX86 &masm) +{ + if (masm.outOfMemory()) + return nullptr; + + void *code = env->AllocateCode(masm.length()); + if (!code) + return nullptr; + + masm.emitToExecutableMemory(code); + return reinterpret_cast(code); +} diff --git a/sourcepawn/jit/x86/x86-utils.h b/sourcepawn/jit/x86/x86-utils.h new file mode 100644 index 00000000..02dc679c --- /dev/null +++ b/sourcepawn/jit/x86/x86-utils.h @@ -0,0 +1,27 @@ +// vim: set sts=2 ts=8 sw=2 tw=99 et: +// +// Copyright (C) 2006-2015 AlliedModders LLC +// +// This file is part of SourcePawn. SourcePawn is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// You should have received a copy of the GNU General Public License along with +// SourcePawn. If not, see http://www.gnu.org/licenses/. +// +#ifndef _include_sourcepawn_vm_x86_utils_h_ +#define _include_sourcepawn_vm_x86_utils_h_ + +#include +#include + +namespace sp { + +class Environment; + +uint8_t *LinkCode(Environment *env, AssemblerX86 &masm); + +} + +#endif // _include_sourcepawn_vm_x86_utils_h_ From 781c5129a9522b2d59214dbba35bd018415bc021 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 24 Feb 2015 01:19:16 -0800 Subject: [PATCH 6/6] Remove the JITX86 class. --- sourcepawn/jit/sp_vm_basecontext.cpp | 2 +- sourcepawn/jit/x86/jit_x86.cpp | 40 ++++++++++++---------------- sourcepawn/jit/x86/jit_x86.h | 12 ++------- 3 files changed, 20 insertions(+), 34 deletions(-) diff --git a/sourcepawn/jit/sp_vm_basecontext.cpp b/sourcepawn/jit/sp_vm_basecontext.cpp index 8d14d54b..7861738f 100644 --- a/sourcepawn/jit/sp_vm_basecontext.cpp +++ b/sourcepawn/jit/sp_vm_basecontext.cpp @@ -568,7 +568,7 @@ BaseContext::Execute2(IPluginFunction *function, const cell_t *params, unsigned if (fn) { m_pRuntime->m_PubJitFuncs[public_id] = fn; } else { - if ((fn = g_Jit.CompileFunction(m_pRuntime, cfun->Public()->code_offs, &ir)) == NULL) + if ((fn = CompileFunction(m_pRuntime, cfun->Public()->code_offs, &ir)) == NULL) return ir; m_pRuntime->m_PubJitFuncs[public_id] = fn; } diff --git a/sourcepawn/jit/x86/jit_x86.cpp b/sourcepawn/jit/x86/jit_x86.cpp index 5de146a3..8a413f14 100644 --- a/sourcepawn/jit/x86/jit_x86.cpp +++ b/sourcepawn/jit/x86/jit_x86.cpp @@ -49,8 +49,6 @@ using namespace sp; #define __ masm. -JITX86 g_Jit; - static inline ConditionCode OpToCondition(OPCODE op) { @@ -255,6 +253,22 @@ GetFunctionName(const sp_plugin_t *plugin, uint32_t offs) } #endif +CompiledFunction * +CompileFunction(PluginRuntime *prt, cell_t pcode_offs, int *err) +{ + Compiler cc(prt, pcode_offs); + CompiledFunction *fun = cc.emit(err); + if (!fun) + return NULL; + + // Grab the lock before linking code in, since the watchdog timer will look + // at this list on another thread. + ke::AutoLock lock(Environment::get()->lock()); + + prt->AddJittedFunction(fun); + return fun; +} + static int CompileFromThunk(PluginRuntime *runtime, cell_t pcode_offs, void **addrp, char *pc) { @@ -267,7 +281,7 @@ CompileFromThunk(PluginRuntime *runtime, cell_t pcode_offs, void **addrp, char * CompiledFunction *fn = runtime->GetJittedFunctionByOffset(pcode_offs); if (!fn) { int err; - fn = g_Jit.CompileFunction(runtime, pcode_offs, &err); + fn = CompileFunction(runtime, pcode_offs, &err); if (!fn) return err; } @@ -1789,23 +1803,3 @@ Compiler::emitErrorPaths() __ jmp(ExternalAddress(env_->stubs()->ReturnStub())); } } - -JITX86::JITX86() -{ -} - -CompiledFunction * -JITX86::CompileFunction(PluginRuntime *prt, cell_t pcode_offs, int *err) -{ - Compiler cc(prt, pcode_offs); - CompiledFunction *fun = cc.emit(err); - if (!fun) - return NULL; - - // Grab the lock before linking code in, since the watchdog timer will look - // at this list on another thread. - ke::AutoLock lock(Environment::get()->lock()); - - prt->AddJittedFunction(fun); - return fun; -} diff --git a/sourcepawn/jit/x86/jit_x86.h b/sourcepawn/jit/x86/jit_x86.h index ca5abb64..45e4aa0e 100644 --- a/sourcepawn/jit/x86/jit_x86.h +++ b/sourcepawn/jit/x86/jit_x86.h @@ -130,15 +130,6 @@ class Compiler ke::Vector thunks_; //:TODO: free }; -class JITX86 -{ - public: - JITX86(); - - public: - CompiledFunction *CompileFunction(PluginRuntime *runtime, cell_t pcode_offs, int *err); -}; - const Register pri = eax; const Register alt = edx; const Register stk = edi; @@ -146,7 +137,8 @@ const Register dat = esi; const Register tmp = ecx; const Register frm = ebx; -extern JITX86 g_Jit; +CompiledFunction * +CompileFunction(PluginRuntime *prt, cell_t pcode_offs, int *err); #endif //_INCLUDE_SOURCEPAWN_JIT_X86_H_