From b9b0ec865c74bfc9ef4321f0c7527b67ef49dc8a Mon Sep 17 00:00:00 2001
From: David Anderson <dvander@alliedmods.net>
Date: Tue, 24 Feb 2015 23:37:23 -0800
Subject: [PATCH] Simplify the JIT function cache.

---
 sourcepawn/jit/plugin-context.cpp   | 18 ++++++++--------
 sourcepawn/jit/plugin-runtime.cpp   | 32 ++++++++++-------------------
 sourcepawn/jit/plugin-runtime.h     | 16 ++++++++++++---
 sourcepawn/jit/scripted-invoker.cpp |  3 ++-
 sourcepawn/jit/scripted-invoker.h   | 12 +++++++++++
 sourcepawn/jit/x86/jit_x86.cpp      |  2 +-
 6 files changed, 47 insertions(+), 36 deletions(-)

diff --git a/sourcepawn/jit/plugin-context.cpp b/sourcepawn/jit/plugin-context.cpp
index 22dd7ef1..664eed1b 100644
--- a/sourcepawn/jit/plugin-context.cpp
+++ b/sourcepawn/jit/plugin-context.cpp
@@ -550,17 +550,15 @@ PluginContext::Execute2(IPluginFunction *function, const cell_t *params, unsigne
   EnterProfileScope scriptScope("SourcePawn", cfun->FullName());
 
   /* See if we have to compile the callee. */
-  if (Environment::get()->IsJitEnabled() &&
-      (fn = m_pRuntime->m_PubJitFuncs[public_id]) == NULL)
-  {
+  if (Environment::get()->IsJitEnabled()) {
     /* We might not have to - check pcode offset. */
-    fn = m_pRuntime->GetJittedFunctionByOffset(cfun->Public()->code_offs);
-    if (fn) {
-      m_pRuntime->m_PubJitFuncs[public_id] = fn;
-    } else {
-      if ((fn = CompileFunction(m_pRuntime, cfun->Public()->code_offs, &ir)) == NULL)
-        return ir;
-      m_pRuntime->m_PubJitFuncs[public_id] = fn;
+    if ((fn = cfun->cachedCompiledFunction()) == nullptr) {
+      fn = m_pRuntime->GetJittedFunctionByOffset(cfun->Public()->code_offs);
+      if (!fn) {
+        if ((fn = CompileFunction(m_pRuntime, cfun->Public()->code_offs, &ir)) == NULL)
+          return ir;
+      }
+      cfun->setCachedCompiledFunction(fn);
     }
   }
 
diff --git a/sourcepawn/jit/plugin-runtime.cpp b/sourcepawn/jit/plugin-runtime.cpp
index cbaed60b..751b0f2b 100644
--- a/sourcepawn/jit/plugin-runtime.cpp
+++ b/sourcepawn/jit/plugin-runtime.cpp
@@ -34,7 +34,6 @@ PluginRuntime::PluginRuntime()
   : m_Debug(&m_plugin),
     m_pCtx(NULL), 
     m_PubFuncs(NULL),
-    m_PubJitFuncs(NULL),
     m_CompSerial(0)
 {
   memset(&m_plugin, 0, sizeof(m_plugin));
@@ -42,7 +41,6 @@ PluginRuntime::PluginRuntime()
   m_MaxFuncs = 0;
   m_NumFuncs = 0;
   float_table_ = NULL;
-  function_map_ = NULL;
   alt_pcode_ = NULL;
   
   memset(m_CodeHash, 0, sizeof(m_CodeHash));
@@ -65,9 +63,7 @@ PluginRuntime::~PluginRuntime()
   for (uint32_t i = 0; i < m_plugin.num_publics; i++)
     delete m_PubFuncs[i];
   delete [] m_PubFuncs;
-  delete [] m_PubJitFuncs;
   delete [] float_table_;
-  delete [] function_map_;
   delete [] alt_pcode_;
 
   for (size_t i = 0; i < m_JitFunctions.length(); i++)
@@ -286,8 +282,6 @@ int PluginRuntime::CreateFromMemory(sp_file_hdr_t *hdr, uint8_t *base)
   if (m_plugin.num_publics > 0) {
     m_PubFuncs = new ScriptedInvoker *[m_plugin.num_publics];
     memset(m_PubFuncs, 0, sizeof(ScriptedInvoker *) * m_plugin.num_publics);
-    m_PubJitFuncs = new CompiledFunction *[m_plugin.num_publics];
-    memset(m_PubJitFuncs, 0, sizeof(CompiledFunction *) * m_plugin.num_publics);
   }
 
   MD5 md5_pcode;
@@ -303,9 +297,9 @@ int PluginRuntime::CreateFromMemory(sp_file_hdr_t *hdr, uint8_t *base)
   m_pCtx = new PluginContext(this);
 
   SetupFloatNativeRemapping();
-  function_map_size_ = m_plugin.pcode_size / sizeof(cell_t) + 1;
-  function_map_ = new CompiledFunction *[function_map_size_];
-  memset(function_map_, 0, function_map_size_ * sizeof(CompiledFunction *));
+
+  if (!function_map_.init(32))
+    return SP_ERROR_OUT_OF_MEMORY;
 
   return SP_ERROR_NONE;
 }
@@ -315,24 +309,20 @@ PluginRuntime::AddJittedFunction(CompiledFunction *fn)
 {
   m_JitFunctions.append(fn);
 
-  cell_t pcode_offset = fn->GetCodeOffset();
-  assert(pcode_offset % 4 == 0);
+  ucell_t pcode_offset = fn->GetCodeOffset();
+  FunctionMap::Insert p = function_map_.findForAdd(pcode_offset);
+  assert(!p.found());
 
-  uint32_t pcode_index = pcode_offset / 4;
-  assert(pcode_index < function_map_size_);
-
-  function_map_[pcode_index] = fn;
+  function_map_.add(p, pcode_offset, fn);
 }
 
 CompiledFunction *
 PluginRuntime::GetJittedFunctionByOffset(cell_t pcode_offset)
 {
-  assert(pcode_offset % 4 == 0);
-
-  uint32_t pcode_index = pcode_offset / 4;
-  assert(pcode_index < function_map_size_);
-
-  return function_map_[pcode_index];
+  FunctionMap::Result r = function_map_.find(pcode_offset);
+  if (r.found())
+    return r->value;
+  return nullptr;
 }
 
 int
diff --git a/sourcepawn/jit/plugin-runtime.h b/sourcepawn/jit/plugin-runtime.h
index 27166ae8..a3e34690 100644
--- a/sourcepawn/jit/plugin-runtime.h
+++ b/sourcepawn/jit/plugin-runtime.h
@@ -16,6 +16,7 @@
 #include <sp_vm_api.h>
 #include <am-vector.h>
 #include <am-inlinelist.h>
+#include <am-hashmap.h>
 #include "jit_shared.h"
 #include "compiled-function.h"
 #include "scripted-invoker.h"
@@ -110,15 +111,24 @@ class PluginRuntime
   unsigned int m_NumFuncs;
   unsigned int m_MaxFuncs;
   floattbl_t *float_table_;
-  CompiledFunction **function_map_;
-  size_t function_map_size_;
+
+  struct FunctionMapPolicy {
+    static inline uint32_t hash(ucell_t value) {
+      return ke::HashInteger<4>(value);
+    }
+    static inline bool matches(ucell_t a, ucell_t b) {
+      return a == b;
+    }
+  };
+  typedef ke::HashMap<ucell_t, CompiledFunction *, FunctionMapPolicy> FunctionMap;
+
+  FunctionMap function_map_;
   ke::Vector<CompiledFunction *> m_JitFunctions;
 
  public:
   DebugInfo m_Debug;
   PluginContext *m_pCtx;
   ScriptedInvoker **m_PubFuncs;
-  CompiledFunction **m_PubJitFuncs;
 
  public:
   unsigned int m_CompSerial;
diff --git a/sourcepawn/jit/scripted-invoker.cpp b/sourcepawn/jit/scripted-invoker.cpp
index bf02595c..b422bac4 100644
--- a/sourcepawn/jit/scripted-invoker.cpp
+++ b/sourcepawn/jit/scripted-invoker.cpp
@@ -52,7 +52,8 @@ ScriptedInvoker::GetParentContext()
 ScriptedInvoker::ScriptedInvoker(PluginRuntime *runtime, funcid_t id, uint32_t pub_id)
  : m_curparam(0),
    m_errorstate(SP_ERROR_NONE),
-   m_FnId(id)
+   m_FnId(id),
+   cc_function_(nullptr)
 {
   m_pRuntime = runtime;
 
diff --git a/sourcepawn/jit/scripted-invoker.h b/sourcepawn/jit/scripted-invoker.h
index 653a5c10..077ed0b0 100644
--- a/sourcepawn/jit/scripted-invoker.h
+++ b/sourcepawn/jit/scripted-invoker.h
@@ -19,6 +19,10 @@ class PluginRuntime;
 
 using namespace SourcePawn;
 
+namespace sp {
+class CompiledFunction;
+}
+
 struct ParamInfo
 {
   int flags;      /* Copy-back flags */
@@ -70,6 +74,13 @@ class ScriptedInvoker : public IPluginFunction
     return public_;
   }
 
+  sp::CompiledFunction *cachedCompiledFunction() const {
+    return cc_function_;
+  }
+  void setCachedCompiledFunction(sp::CompiledFunction *fn) {
+    cc_function_ = fn;
+  }
+
  private:
   int _PushString(const char *string, int sz_flags, int cp_flags, size_t len);
   int SetError(int err);
@@ -83,6 +94,7 @@ class ScriptedInvoker : public IPluginFunction
   funcid_t m_FnId;
   char *full_name_;
   sp_public_t *public_;
+  sp::CompiledFunction *cc_function_;
 };
 
 #endif //_INCLUDE_SOURCEMOD_BASEFUNCTION_H_
diff --git a/sourcepawn/jit/x86/jit_x86.cpp b/sourcepawn/jit/x86/jit_x86.cpp
index c064c8a7..a7b0a819 100644
--- a/sourcepawn/jit/x86/jit_x86.cpp
+++ b/sourcepawn/jit/x86/jit_x86.cpp
@@ -165,7 +165,7 @@ CompileFromThunk(PluginRuntime *runtime, cell_t pcode_offs, void **addrp, char *
   }
 
 #if defined JIT_SPEW
-  g_engine1.GetDebugHook()->OnDebugSpew(
+  Environment::get()->debugger()->OnDebugSpew(
       "Patching thunk to %s::%s\n",
       runtime->plugin()->name,
       GetFunctionName(runtime->plugin(), pcode_offs));