diff --git a/configs/core.cfg b/configs/core.cfg
index 54c01e2f..94285095 100644
--- a/configs/core.cfg
+++ b/configs/core.cfg
@@ -132,5 +132,13 @@
 	 * passed. You can disable this feature by setting the value to "0".
 	 */
 	"SlowScriptTimeout"	"8"
+
+	/**
+	 * Disable the SourcePawn just-in-time compiler. This is intended for C++ developers using
+	 * debugging tools and finding it difficult to inspect JIT stack frames. The interpreter
+	 * is not as well-tested as the JIT and will make script execution roughly 10X slower, so
+	 * it is not intended for general purpose use.
+	 */
+	"DisableJIT"	"no"
 }
 
diff --git a/core/sm_srvcmds.cpp b/core/sm_srvcmds.cpp
index a5a46a94..d3fa7281 100644
--- a/core/sm_srvcmds.cpp
+++ b/core/sm_srvcmds.cpp
@@ -334,7 +334,10 @@ void RootConsoleMenu::OnRootConsoleCommand(const char *cmdname, const CCommand &
 	{
 		ConsolePrint(" SourceMod Version Information:");
 		ConsolePrint("    SourceMod Version: %s", SM_VERSION_STRING);
-		ConsolePrint("    SourcePawn Engine: %s (build %s)", g_pSourcePawn2->GetEngineName(), g_pSourcePawn2->GetVersionString());
+		if (g_pSourcePawn2->IsJitEnabled())
+			ConsolePrint("    SourcePawn Engine: %s (build %s)", g_pSourcePawn2->GetEngineName(), g_pSourcePawn2->GetVersionString());
+		else
+			ConsolePrint("    SourcePawn Engine: %s (build %s NO JIT)", 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("    Build ID: %s", SM_BUILD_UNIQUEID);
diff --git a/core/sourcemod.cpp b/core/sourcemod.cpp
index db525627..caa5d2aa 100644
--- a/core/sourcemod.cpp
+++ b/core/sourcemod.cpp
@@ -61,6 +61,7 @@ IForward *g_pOnMapEnd = NULL;
 IGameConfig *g_pGameConf = NULL;
 bool g_Loaded = false;
 bool sm_show_debug_spew = false;
+bool sm_disable_jit = false;
 
 typedef ISourcePawnEngine *(*GET_SP_V1)();
 typedef ISourcePawnEngine2 *(*GET_SP_V2)();
@@ -125,6 +126,14 @@ ConfigResult SourceModBase::OnSourceModConfigChanged(const char *key,
 
 		return ConfigResult_Accept;
 	}
+	else if (strcasecmp(key, "DisableJIT") == 0)
+	{
+		sm_disable_jit = (strcasecmp(value, "yes") == 0) ? true : false;
+		if (g_pSourcePawn2)
+			g_pSourcePawn2->SetJitEnabled(!sm_disable_jit);
+
+		return ConfigResult_Accept;
+	}
 
 	return ConfigResult_Ignore;
 }
@@ -242,6 +251,9 @@ bool SourceModBase::InitializeSourceMod(char *error, size_t maxlength, bool late
 
 	g_pSourcePawn2->SetDebugListener(logicore.debugger);
 
+	if (sm_disable_jit)
+		g_pSourcePawn2->SetJitEnabled(!sm_disable_jit);
+
 	sSourceModInitialized = true;
 
 	/* Hook this now so we can detect startup without calling StartSourceMod() */
diff --git a/public/sourcepawn/sp_vm_api.h b/public/sourcepawn/sp_vm_api.h
index f152b071..623b2103 100644
--- a/public/sourcepawn/sp_vm_api.h
+++ b/public/sourcepawn/sp_vm_api.h
@@ -40,7 +40,7 @@
 
 /** SourcePawn Engine API Version */
 #define SOURCEPAWN_ENGINE_API_VERSION	4
-#define SOURCEPAWN_ENGINE2_API_VERSION	5
+#define SOURCEPAWN_ENGINE2_API_VERSION	6
 
 #if !defined SOURCEMOD_BUILD
 #define SOURCEMOD_BUILD
@@ -1295,6 +1295,21 @@ namespace SourcePawn
 		 * @return			True on success, false on failure.
 		 */
 		virtual bool InstallWatchdogTimer(size_t timeout_ms) =0;
+
+		/**
+		 * @brief Sets whether the JIT is enabled or disabled.
+		 *
+		 * @param enabled	True or false to enable or disable.
+		 * @return			True if successful, false otherwise.
+		 */
+		virtual bool SetJitEnabled(bool enabled) =0;
+
+		/**
+		 * @brief Returns whether the JIT is enabled.
+		 *
+		 * @return			True if the JIT is enabled, false otherwise.
+		 */
+		virtual bool IsJitEnabled() =0;
 	};
 };
 
diff --git a/sourcepawn/jit/AMBuilder b/sourcepawn/jit/AMBuilder
index 10fd1692..311ed4bb 100644
--- a/sourcepawn/jit/AMBuilder
+++ b/sourcepawn/jit/AMBuilder
@@ -31,6 +31,7 @@ binary.AddSourceFiles('sourcepawn/jit', [
 	'sp_vm_engine.cpp',
 	'sp_vm_function.cpp',
 	'opcodes.cpp',
+	'interpreter.cpp',
 	'watchdog_timer.cpp',
 	'x86/jit_x86.cpp',
 	'zlib/adler32.c',
diff --git a/sourcepawn/jit/Makefile.shell b/sourcepawn/jit/Makefile.shell
index 41a4aee7..ad2fd0ae 100644
--- a/sourcepawn/jit/Makefile.shell
+++ b/sourcepawn/jit/Makefile.shell
@@ -20,6 +20,7 @@ OBJECTS = dll_exports.cpp 	\
 	jit_function.cpp	\
 	opcodes.cpp		\
 	watchdog_timer.cpp \
+	interpreter.cpp \
 	md5/md5.cpp			\
 	zlib/adler32.c		\
 	zlib/compress.c		\
@@ -51,7 +52,8 @@ CC = cc
 LINK = -m32 -lm -lpthread -lrt
 
 INCLUDE = -I. -I.. -I$(SMSDK)/public -I$(SMSDK)/public/jit -I$(SMSDK)/public/jit/x86 \
-	-I$(SMSDK)/public/sourcepawn -I$(MMSOURCE17)/core/sourcehook -I$(SMSDK)/knight/shared -Ix86
+	-I$(SMSDK)/public/sourcepawn -I$(MMSOURCE17)/core/sourcehook -I$(SMSDK)/knight/shared -Ix86 \
+	-I$(SMSDK)/public/amtl
 
 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 \
diff --git a/sourcepawn/jit/dll_exports.cpp b/sourcepawn/jit/dll_exports.cpp
index 6e0e23f0..9a7bc354 100644
--- a/sourcepawn/jit/dll_exports.cpp
+++ b/sourcepawn/jit/dll_exports.cpp
@@ -219,6 +219,9 @@ int main(int argc, char **argv)
 		return 1;
 	}
 
+	if (getenv("DISABLE_JIT"))
+		g_engine2.SetJitEnabled(false);
+
 	ShellDebugListener debug;
 	g_engine1.SetDebugListener(&debug);
 	g_engine2.InstallWatchdogTimer(5000);
diff --git a/sourcepawn/jit/engine2.cpp b/sourcepawn/jit/engine2.cpp
index 284256e9..840367a0 100644
--- a/sourcepawn/jit/engine2.cpp
+++ b/sourcepawn/jit/engine2.cpp
@@ -15,6 +15,7 @@ using namespace SourcePawn;
 SourcePawnEngine2::SourcePawnEngine2()
 {
 	m_Profiler = NULL;
+	jit_enabled_ = true;
 }
 
 IPluginRuntime *SourcePawnEngine2::LoadPlugin(ICompilation *co, const char *file, int *err)
@@ -146,7 +147,7 @@ void SourcePawnEngine2::DestroyFakeNative(SPVM_NATIVE_FUNC func)
 
 const char *SourcePawnEngine2::GetEngineName()
 {
-	return "SourcePawn 1.1, jit-x86";
+	return "SourcePawn 1.2, jit-x86";
 }
 
 const char *SourcePawnEngine2::GetVersionString()
diff --git a/sourcepawn/jit/engine2.h b/sourcepawn/jit/engine2.h
index 0d20975c..e9cb980e 100644
--- a/sourcepawn/jit/engine2.h
+++ b/sourcepawn/jit/engine2.h
@@ -1,3 +1,4 @@
+// vim: set ts=4 sw=4 tw=99 noet:
 #ifndef _INCLUDE_SOURCEPAWN_ENGINE_2_H_
 #define _INCLUDE_SOURCEPAWN_ENGINE_2_H_
 
@@ -27,10 +28,20 @@ namespace SourcePawn
 		void Shutdown();
 		IPluginRuntime *CreateEmptyRuntime(const char *name, uint32_t memory);
 		bool InstallWatchdogTimer(size_t timeout_ms);
+
+		bool SetJitEnabled(bool enabled) {
+			jit_enabled_ = enabled;
+			return true;
+	    }
+
+		bool IsJitEnabled() {
+			return jit_enabled_;
+		}
 	public:
 		IProfiler *GetProfiler();
 	private:
 		IProfiler *m_Profiler;
+		bool jit_enabled_;
 	};
 }
 
diff --git a/sourcepawn/jit/interpreter.cpp b/sourcepawn/jit/interpreter.cpp
new file mode 100644
index 00000000..75b4e238
--- /dev/null
+++ b/sourcepawn/jit/interpreter.cpp
@@ -0,0 +1,965 @@
+// vim: set ts=8 sts=2 sw=2 tw=99 et:
+//
+// 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.
+// 
+// SourcePawn 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 SourcePawn.  If not, see .
+#include 
+#include 
+#include "interpreter.h"
+#include "opcodes.h"
+#include "watchdog_timer.h"
+
+#define STACK_MARGIN 64
+
+using namespace SourcePawn;
+
+static inline bool
+IsValidOffset(uint32_t cip)
+{
+  return cip % 4 == 0;
+}
+
+static inline cell_t
+Read(const sp_plugin_t *plugin, cell_t offset)
+{
+  return *reinterpret_cast(plugin->memory + offset);
+}
+
+static inline void
+Write(const sp_plugin_t *plugin, cell_t offset, cell_t value)
+{
+  *reinterpret_cast(plugin->memory + offset) = value;
+}
+
+static inline cell_t *
+Jump(const sp_plugin_t *plugin, sp_context_t *ctx, cell_t target)
+{
+  if (!IsValidOffset(target) || uint32_t(target) >= plugin->pcode_size) {
+    ctx->err = SP_ERROR_INVALID_INSTRUCTION;
+    return NULL;
+  }
+
+  return reinterpret_cast(plugin->pcode + target);
+}
+
+static inline cell_t *
+JumpTarget(const sp_plugin_t *plugin, sp_context_t *ctx, cell_t *cip, bool cond)
+{
+  if (!cond)
+    return cip + 1;
+
+  cell_t target = *cip;
+  if (!IsValidOffset(target) || uint32_t(target) >= plugin->pcode_size) {
+    ctx->err = SP_ERROR_INVALID_INSTRUCTION;
+    return NULL;
+  }
+
+  cell_t *next = reinterpret_cast(plugin->pcode + target);
+  if (next < cip && !g_WatchdogTimer.HandleInterrupt()) {
+    ctx->err = SP_ERROR_TIMEOUT;
+    return NULL;
+  }
+
+  return next;
+}
+
+static inline bool
+CheckAddress(const sp_plugin_t *plugin, sp_context_t *ctx, cell_t *stk, cell_t addr)
+{
+  if (uint32_t(addr) >= plugin->mem_size) {
+    ctx->err = SP_ERROR_MEMACCESS;
+    return false;
+  }
+
+  if (addr < ctx->hp)
+    return true;
+
+  if (reinterpret_cast(plugin->memory + addr) < stk) {
+    ctx->err = SP_ERROR_MEMACCESS;
+    return false;
+  }
+
+  return true;
+}
+
+int
+PopTrackerAndSetHeap(BaseRuntime *rt)
+{
+  sp_context_t *ctx = rt->GetBaseContext()->GetCtx();
+  tracker_t *trk = ctx->tracker;
+  assert(trk->pCur > trk->pBase);
+
+  trk->pCur--;
+  if (trk->pCur < trk->pBase)
+    return SP_ERROR_TRACKER_BOUNDS;
+
+  ucell_t amt = *trk->pCur;
+  if (amt > (ctx->hp - rt->plugin()->data_size))
+    return SP_ERROR_HEAPMIN;
+
+  ctx->hp -= amt;
+  return SP_ERROR_NONE;
+}
+
+int
+PushTracker(sp_context_t *ctx, size_t amount)
+{
+  tracker_t *trk = ctx->tracker;
+
+  if ((size_t)(trk->pCur - trk->pBase) >= trk->size)
+    return SP_ERROR_TRACKER_BOUNDS;
+
+  if (trk->pCur + 1 - (trk->pBase + trk->size) == 0) {
+    size_t disp = trk->size - 1;
+    trk->size *= 2;
+    trk->pBase = (ucell_t *)realloc(trk->pBase, trk->size * sizeof(cell_t));
+
+    if (!trk->pBase)
+      return SP_ERROR_TRACKER_BOUNDS;
+
+    trk->pCur = trk->pBase + disp;
+  }
+
+  *trk->pCur++ = amount;
+  return SP_ERROR_NONE;
+}
+
+cell_t
+NativeCallback(sp_context_t *ctx, ucell_t native_idx, cell_t *params)
+{
+  cell_t save_sp = ctx->sp;
+  cell_t save_hp = ctx->hp;
+
+  ctx->n_idx = native_idx;
+
+  sp_native_t *native = &ctx->plugin->natives[native_idx];
+
+  if (native->status == SP_NATIVE_UNBOUND) {
+    ctx->n_err = SP_ERROR_INVALID_NATIVE;
+    return 0;
+  }
+
+  cell_t result = native->pfn(ctx->basecx, params);
+
+  if (ctx->n_err != SP_ERROR_NONE)
+    return result;
+
+  if (save_sp != ctx->sp) {
+    ctx->n_err = SP_ERROR_STACKLEAK;
+    return result;
+  }
+  if (save_hp != ctx->hp) {
+    ctx->n_err = SP_ERROR_HEAPLEAK;
+    return result;
+  }
+
+  return result;
+}
+
+static inline bool
+GenerateArray(BaseRuntime *rt, sp_context_t *ctx, cell_t dims, cell_t *stk, bool autozero)
+{
+  if (dims == 1) {
+    uint32_t size = *stk;
+    if (size == 0 || !ke::IsUint32MultiplySafe(size, 4)) {
+      ctx->err = SP_ERROR_ARRAY_TOO_BIG;
+      return false;
+    }
+    *stk = ctx->hp;
+
+    uint32_t bytes = size * 4;
+
+    ctx->hp += bytes;
+    if (uintptr_t(ctx->plugin->memory + ctx->hp) >= uintptr_t(stk)) {
+      ctx->err = SP_ERROR_HEAPLOW;
+      return false;
+    }
+
+    if ((ctx->err = PushTracker(ctx, bytes)) != SP_ERROR_NONE)
+      return false;
+
+    if (autozero)
+      memset(ctx->plugin->memory + ctx->hp, 0, bytes);
+
+    return true;
+  }
+
+  if ((ctx->err = GenerateFullArray(rt, dims, stk, autozero)) != SP_ERROR_NONE)
+    return false;
+
+  return true;
+}
+
+int
+Interpret(BaseRuntime *rt, uint32_t aCodeStart, cell_t *rval)
+{
+  const sp_plugin_t *plugin = rt->plugin();
+  cell_t *code = reinterpret_cast(plugin->pcode);
+  cell_t *codeend = reinterpret_cast(plugin->pcode + plugin->pcode_size);
+
+  if (!IsValidOffset(aCodeStart) || aCodeStart > plugin->pcode_size)
+    return SP_ERROR_INVALID_INSTRUCTION;
+
+  sp_context_t *ctx = rt->GetBaseContext()->GetCtx();
+  ctx->err = SP_ERROR_NONE;
+
+  // Save the original frm. BaseContext won't, and if we error, we won't hit
+  // the stack unwinding code.
+  cell_t orig_frm = ctx->frm;
+
+  cell_t pri = 0;
+  cell_t alt = 0;
+  cell_t *cip = code + (aCodeStart / 4);
+  cell_t *stk = reinterpret_cast(plugin->memory + ctx->sp);
+
+  for (;;) {
+    if (cip >= codeend) {
+      ctx->err = SP_ERROR_INVALID_INSTRUCTION;
+      goto error;
+    }
+
+#if 0
+    SpewOpcode(plugin, reinterpret_cast(plugin->pcode + aCodeStart), cip);
+#endif
+
+    OPCODE op = (OPCODE)*cip++;
+
+    switch (op) {
+      case OP_MOVE_PRI:
+        pri = alt;
+        break;
+      case OP_MOVE_ALT:
+        alt = pri;
+        break;
+
+      case OP_XCHG:
+      {
+        cell_t tmp = pri;
+        pri = alt;
+        alt = tmp;
+        break;
+      }
+
+      case OP_ZERO:
+        Write(plugin, *cip++, 0);
+        break;
+
+      case OP_ZERO_S:
+        Write(plugin, *cip++, 0);
+        break;
+
+      case OP_PUSH_PRI:
+        *--stk = pri;
+        break;
+      case OP_PUSH_ALT:
+        *--stk = alt;
+        break;
+
+      case OP_PUSH_C:
+      case OP_PUSH2_C:
+      case OP_PUSH3_C:
+      case OP_PUSH4_C:
+      case OP_PUSH5_C:
+      {
+        int n = 1;
+        if (op >= OP_PUSH2_C)
+          n = ((op - OP_PUSH2_C) / 4) + 2;
+
+        int i = 1;
+        do {
+          *--stk = *cip++;
+        } while (i++ < n);
+        break;
+      }
+
+      case OP_PUSH_ADR:
+      case OP_PUSH2_ADR:
+      case OP_PUSH3_ADR:
+      case OP_PUSH4_ADR:
+      case OP_PUSH5_ADR:
+      {
+        int n = 1;
+        if (op >= OP_PUSH2_ADR)
+          n = ((op - OP_PUSH2_ADR) / 4) + 2;
+
+        int i = 1;
+
+        do {
+          cell_t addr = ctx->frm + *cip++;
+          *--stk = addr;
+        } while (i++ < n);
+        break;
+      }
+
+      case OP_PUSH_S:
+      case OP_PUSH2_S:
+      case OP_PUSH3_S:
+      case OP_PUSH4_S:
+      case OP_PUSH5_S:
+      {
+        int n = 1;
+        if (op >= OP_PUSH2_S)
+          n = ((op - OP_PUSH2_S) / 4) + 2;
+
+        int i = 1;
+        do {
+          cell_t value = Read(plugin, ctx->frm + *cip++);
+          *--stk = value;
+        } while (i++ < n);
+        break;
+      }
+
+      case OP_PUSH:
+      case OP_PUSH2:
+      case OP_PUSH3:
+      case OP_PUSH4:
+      case OP_PUSH5:
+      {
+        int n = 1;
+        if (op >= OP_PUSH2)
+          n = ((op - OP_PUSH2) / 4) + 2;
+
+        int i = 1;
+        do {
+          cell_t value = Read(plugin, *cip++);
+          *--stk = value;
+        } while (i++ < n);
+        break;
+      }
+
+      case OP_ZERO_PRI:
+        pri = 0;
+        break;
+      case OP_ZERO_ALT:
+        alt = 0;
+        break;
+
+      case OP_ADD:
+        pri += alt;
+        break;
+
+      case OP_SUB:
+        pri -= alt;
+        break;
+
+      case OP_SUB_ALT:
+        pri = alt - pri;
+        break;
+
+      case OP_PROC:
+      {
+        *--stk = ctx->frm;
+        *--stk = 0;
+        ctx->frm = uintptr_t(stk) - uintptr_t(plugin->memory);
+        break;
+      }
+
+      case OP_IDXADDR_B:
+        pri <<= *cip++;
+        pri += alt;
+        break;
+
+      case OP_SHL:
+        pri <<= alt;
+        break;
+
+      case OP_SHR:
+        pri = unsigned(pri) >> unsigned(alt);
+        break;
+
+      case OP_SSHR:
+        pri >>= alt;
+        break;
+
+      case OP_SHL_C_PRI:
+        pri <<= *cip++;
+        break;
+      case OP_SHL_C_ALT:
+        alt <<= *cip++;
+        break;
+
+      case OP_SHR_C_PRI:
+        pri >>= *cip++;
+        break;
+      case OP_SHR_C_ALT:
+        alt >>= *cip++;
+        break;
+
+      case OP_SMUL:
+        pri *= alt;
+        break;
+
+      case OP_NOT:
+        pri = pri ? 0 : 1;
+        break;
+
+      case OP_NEG:
+        pri = -pri;
+        break;
+
+      case OP_XOR:
+        pri ^= alt;
+        break;
+
+      case OP_OR:
+        pri |= alt;
+        break;
+
+      case OP_AND:
+        pri &= alt;
+        break;
+
+      case OP_INVERT:
+        pri = ~pri;
+        break;
+
+      case OP_ADD_C:
+        pri += *cip++;
+        break;
+
+      case OP_SMUL_C:
+        pri *= *cip++;
+        break;
+
+      case OP_EQ:
+        pri = pri == alt;
+        break;
+
+      case OP_NEQ:
+        pri = pri != alt;
+        break;
+
+      case OP_SLESS:
+        pri = pri < alt;
+        break;
+
+      case OP_SLEQ:
+        pri = pri <= alt;
+        break;
+
+      case OP_SGRTR:
+        pri = pri > alt;
+        break;
+        
+      case OP_SGEQ:
+        pri = pri >= alt;
+        break;
+
+      case OP_EQ_C_PRI:
+        pri = pri == *cip++;
+        break;
+      case OP_EQ_C_ALT:
+        pri = alt == *cip++;
+        break;
+
+      case OP_INC_PRI:
+        pri++;
+        break;
+      case OP_INC_ALT:
+        alt++;
+        break;
+
+      case OP_INC:
+      {
+        cell_t offset = *cip++;
+        Write(plugin, offset, Read(plugin, offset) + 1);
+        break;
+      }
+
+      case OP_INC_S:
+      {
+        cell_t offset = *cip++;
+        cell_t value = Read(plugin, ctx->frm + offset);
+        Write(plugin, ctx->frm + offset, value + 1);
+        break;
+      }
+
+      case OP_INC_I:
+        if (!CheckAddress(plugin, ctx, stk, pri))
+          goto error;
+        Write(plugin, pri, Read(plugin, pri) + 1);
+        break;
+
+      case OP_DEC_PRI:
+        pri--;
+        break;
+      case OP_DEC_ALT:
+        alt--;
+        break;
+
+      case OP_DEC:
+      {
+        cell_t offset = *cip++;
+        Write(plugin, offset, Read(plugin, offset) - 1);
+        break;
+      }
+
+      case OP_DEC_S:
+      {
+        cell_t offset = *cip++;
+        cell_t value = Read(plugin, ctx->frm + offset);
+        Write(plugin, ctx->frm + offset, value - 1);
+        break;
+      }
+
+      case OP_DEC_I:
+        if (!CheckAddress(plugin, ctx, stk, pri))
+          goto error;
+        Write(plugin, pri, Read(plugin, pri) - 1);
+        break;
+
+      case OP_LOAD_PRI:
+        pri = Read(plugin, *cip++);
+        break;
+      case OP_LOAD_ALT:
+        alt = Read(plugin, *cip++);
+        break;
+
+      case OP_LOAD_S_PRI:
+        pri = Read(plugin, ctx->frm + *cip++);
+        break;
+      case OP_LOAD_S_ALT:
+        alt = Read(plugin, ctx->frm + *cip++);
+        break;
+
+      case OP_LOAD_S_BOTH:
+        pri = Read(plugin, ctx->frm + *cip++);
+        alt = Read(plugin, ctx->frm + *cip++);
+        break;
+
+      case OP_LREF_S_PRI:
+      {
+        pri = Read(plugin, ctx->frm + *cip++);
+        pri = Read(plugin, pri);
+        break;
+      }
+
+      case OP_LREF_S_ALT:
+      {
+        alt = Read(plugin, ctx->frm + *cip++);
+        alt = Read(plugin, alt);
+        break;
+      }
+
+      case OP_CONST_PRI:
+        pri = *cip++;
+        break;
+      case OP_CONST_ALT:
+        alt = *cip++;
+        break;
+
+      case OP_ADDR_PRI:
+        pri = ctx->frm + *cip++;
+        break;
+      case OP_ADDR_ALT:
+        alt = ctx->frm + *cip++;
+        break;
+
+      case OP_STOR_PRI:
+        Write(plugin, *cip++, pri);
+        break;
+      case OP_STOR_ALT:
+        Write(plugin, *cip++, alt);
+        break;
+
+      case OP_STOR_S_PRI:
+        Write(plugin, ctx->frm + *cip++, pri);
+        break;
+      case OP_STOR_S_ALT:
+        Write(plugin, ctx->frm +*cip++, alt);
+        break;
+
+      case OP_IDXADDR:
+        pri = alt + pri * 4;
+        break;
+
+      case OP_SREF_S_PRI:
+      {
+        cell_t offset = *cip++;
+        cell_t addr = Read(plugin, ctx->frm + offset);
+        Write(plugin, addr, pri);
+        break;
+      }
+
+      case OP_SREF_S_ALT:
+      {
+        cell_t offset = *cip++;
+        cell_t addr = Read(plugin, ctx->frm + offset);
+        Write(plugin, addr, alt);
+        break;
+      }
+
+      case OP_POP_PRI:
+        pri = *stk++;
+        break;
+      case OP_POP_ALT:
+        alt = *stk++;
+        break;
+
+      case OP_SWAP_PRI:
+      case OP_SWAP_ALT:
+      {
+        cell_t reg = (op == OP_SREF_S_PRI) ? pri : alt;
+        cell_t temp = *stk;
+        *stk = reg;
+        reg = temp;
+        break;
+      }
+
+      case OP_LIDX:
+        pri = alt + pri * 4;
+        if (!CheckAddress(plugin, ctx, stk, pri))
+          goto error;
+        pri = Read(plugin, pri);
+        break;
+
+      case OP_LIDX_B:
+      {
+        cell_t val = *cip++;
+        pri = alt + (pri << val);
+        if (!CheckAddress(plugin, ctx, stk, pri))
+          goto error;
+        pri = Read(plugin, pri);
+        break;
+      }
+
+      case OP_CONST:
+      {
+        cell_t offset = *cip++;
+        cell_t value = *cip++;
+        Write(plugin, offset, value);
+        break;
+      }
+
+      case OP_CONST_S:
+      {
+        cell_t offset = *cip++;
+        cell_t value = *cip++;
+        Write(plugin, ctx->frm + offset, value);
+        break;
+      }
+
+      case OP_LOAD_I:
+        if (!CheckAddress(plugin, ctx, stk, pri))
+          goto error;
+        pri = Read(plugin, pri);
+        break;
+
+      case OP_STOR_I:
+        if (!CheckAddress(plugin, ctx, stk, alt))
+          goto error;
+        Write(plugin, alt, pri);
+        break;
+
+      case OP_SDIV:
+      case OP_SDIV_ALT:
+      {
+        cell_t dividend = (op == OP_SDIV) ? pri : alt;
+        cell_t divisor = (op == OP_SDIV) ? alt : pri;
+        if (divisor == 0) {
+          ctx->err = SP_ERROR_DIVIDE_BY_ZERO;
+          goto error;
+        }
+        if (dividend == INT_MIN && divisor == -1) {
+          ctx->err = SP_ERROR_INTEGER_OVERFLOW;
+          goto error;
+        }
+        pri = dividend / divisor;
+        alt = dividend % divisor;
+        break;
+      }
+      
+      case OP_LODB_I:
+      {
+        cell_t val = *cip++;
+        if (!CheckAddress(plugin, ctx, stk, pri))
+          goto error;
+        pri = Read(plugin, pri);
+        if (val == 1)
+          pri &= 0xff;
+        else if (val == 2)
+          pri &= 0xffff;
+        break;
+      }
+
+      case OP_STRB_I:
+      {
+        cell_t val = *cip++;
+        if (!CheckAddress(plugin, ctx, stk, alt))
+          goto error;
+        if (val == 1)
+          *reinterpret_cast(plugin->memory + alt) = pri;
+        else if (val == 2)
+          *reinterpret_cast(plugin->memory + alt) = pri;
+        else if (val == 4)
+          *reinterpret_cast(plugin->memory + alt) = pri;
+        break;
+      }
+
+      case OP_RETN:
+      {
+        stk++;
+        ctx->frm = *stk++;
+        stk += *stk + 1;
+        *rval = pri;
+        ctx->err = SP_ERROR_NONE;
+        goto done;
+      }
+
+      case OP_MOVS:
+      {
+        uint8_t *src = plugin->memory + pri;
+        uint8_t *dest = plugin->memory + alt;
+        memcpy(dest, src, *cip++);
+        break;
+      }
+
+      case OP_FILL:
+      {
+        uint8_t *dest = plugin->memory + alt;
+        memset(dest, pri, *cip++);
+        break;
+      }
+
+      case OP_STRADJUST_PRI:
+        pri += 4;
+        pri >>= 2;
+        break;
+
+      case OP_STACK:
+      {
+        cell_t amount = *cip++;
+        if (!IsValidOffset(amount)) {
+          ctx->err = SP_ERROR_INVALID_INSTRUCTION;
+          goto error;
+        }
+
+        stk += amount / 4;
+        if (amount > 0) {
+          if (uintptr_t(stk) >= uintptr_t(plugin->memory + plugin->mem_size)) {
+            ctx->err = SP_ERROR_STACKMIN;
+            goto error;
+          }
+        } else {
+          if (uintptr_t(stk) < uintptr_t(plugin->memory + ctx->hp + STACK_MARGIN)) {
+            ctx->err = SP_ERROR_STACKLOW;
+            goto error;
+          }
+        }
+        break;
+      }
+
+      case OP_HEAP:
+      {
+        cell_t amount = *cip++;
+
+        alt = ctx->hp;
+        ctx->hp += amount;
+
+        if (amount > 0) {
+          if (uintptr_t(plugin->memory + ctx->hp) > uintptr_t(stk)) {
+            ctx->err = SP_ERROR_HEAPLOW;
+            goto error;
+          }
+        } else {
+          if (uint32_t(ctx->hp) < plugin->data_size) {
+            ctx->err = SP_ERROR_HEAPMIN;
+            goto error;
+          }
+        }
+        break;
+      }
+
+      case OP_JUMP:
+        if ((cip = JumpTarget(plugin, ctx, cip, true)) == NULL)
+          goto error;
+        break;
+
+      case OP_JZER:
+        if ((cip = JumpTarget(plugin, ctx, cip, pri == 0)) == NULL)
+          goto error;
+        break;
+      case OP_JNZ:
+        if ((cip = JumpTarget(plugin, ctx, cip, pri != 0)) == NULL)
+          goto error;
+        break;
+
+      case OP_JEQ:
+        if ((cip = JumpTarget(plugin, ctx, cip, pri == alt)) == NULL)
+          goto error;
+        break;
+      case OP_JNEQ:
+        if ((cip = JumpTarget(plugin, ctx, cip, pri != alt)) == NULL)
+          goto error;
+        break;
+      case OP_JSLESS:
+        if ((cip = JumpTarget(plugin, ctx, cip, pri < alt)) == NULL)
+          goto error;
+        break;
+      case OP_JSLEQ:
+        if ((cip = JumpTarget(plugin, ctx, cip, pri <= alt)) == NULL)
+          goto error;
+        break;
+      case OP_JSGRTR:
+        if ((cip = JumpTarget(plugin, ctx, cip, pri > alt)) == NULL)
+          goto error;
+        break;
+      case OP_JSGEQ:
+        if ((cip = JumpTarget(plugin, ctx, cip, pri >= alt)) == NULL)
+          goto error;
+        break;
+
+      case OP_TRACKER_PUSH_C:
+      {
+        cell_t amount = *cip++;
+        int error = PushTracker(ctx, amount * 4);
+        if (error != SP_ERROR_NONE) {
+          ctx->err = error;
+          goto error;
+        }
+        break;
+      }
+
+      case OP_TRACKER_POP_SETHEAP:
+      {
+        int error = PopTrackerAndSetHeap(rt);
+        if (error != SP_ERROR_NONE) {
+          ctx->err = error;
+          goto error;
+        }
+        break;
+      }
+
+      case OP_BREAK:
+        ctx->cip = uintptr_t(cip - 1) - uintptr_t(plugin->pcode);
+        break;
+
+      case OP_BOUNDS:
+      {
+        cell_t value = *cip++;
+        if (uint32_t(pri) > uint32_t(value)) {
+          ctx->err = SP_ERROR_ARRAY_BOUNDS;
+          goto error;
+        }
+        break;
+      }
+
+      case OP_CALL:
+      {
+        cell_t offset = *cip++;
+
+        if (!IsValidOffset(offset) || uint32_t(offset) >= plugin->pcode_size) {
+          ctx->err = SP_ERROR_INSTRUCTION_PARAM;
+          goto error;
+        }
+
+        if (ctx->rp >= SP_MAX_RETURN_STACK) {
+          ctx->err = SP_ERROR_STACKLOW;
+          goto error;
+        }
+
+        // For debugging.
+        uintptr_t rcip = uintptr_t(cip - 2) - uintptr_t(plugin->pcode);
+        ctx->rstk_cips[ctx->rp++] = rcip;
+        ctx->cip = offset;
+        ctx->sp = uintptr_t(stk) - uintptr_t(plugin->memory);
+
+        int err = Interpret(rt, offset, &pri);
+
+        stk = reinterpret_cast(plugin->memory + ctx->sp);
+        ctx->cip = rcip;
+        ctx->rp--;
+
+        if (err != SP_ERROR_NONE)
+          goto error;
+        break;
+      }
+
+      case OP_GENARRAY:
+      case OP_GENARRAY_Z:
+      {
+        cell_t val = *cip++;
+        if (!GenerateArray(rt, ctx, val, stk, op == OP_GENARRAY_Z))
+          goto error;
+
+        stk += (val - 1) * 4;
+        break;
+      }
+
+      case OP_SYSREQ_C:
+      case OP_SYSREQ_N:
+      {
+        uint32_t native_index = *cip++;
+
+        if (native_index >= plugin->num_natives) {
+          ctx->err = SP_ERROR_INSTRUCTION_PARAM;
+          goto error;
+        }
+
+        uint32_t num_params;
+        if (op == OP_SYSREQ_N) {
+          num_params = *cip++;
+          *--stk = num_params;
+        }
+
+        ctx->sp = uintptr_t(stk) - uintptr_t(plugin->memory);
+        pri = NativeCallback(ctx, native_index, stk);
+        if (ctx->n_err != SP_ERROR_NONE) {
+          ctx->err = ctx->n_err;
+          goto error;
+        }
+
+        if (op == OP_SYSREQ_N)
+          stk += num_params + 1;
+        break;
+      }
+
+      case OP_SWITCH:
+      {
+        cell_t offset = *cip++;
+        cell_t *table = reinterpret_cast(plugin->pcode + offset + sizeof(cell_t));
+
+        size_t ncases = *table++;
+        cell_t target = *table++;   // default case
+
+        for (size_t i = 0; i < ncases; i++) {
+          if (table[i * 2] == pri) {
+            target = table[i * 2 + 1];
+            break;
+          }
+        }
+
+        if ((cip = Jump(plugin, ctx, target)) == NULL)
+          goto error;
+        break;
+      }
+
+      default:
+      {
+        ctx->err = SP_ERROR_INVALID_INSTRUCTION;
+        goto error;
+      }
+    } // switch
+  }
+
+ done:
+  assert(orig_frm == ctx->frm);
+  ctx->sp = uintptr_t(stk) - uintptr_t(plugin->memory);
+  return ctx->err;
+
+ error:
+  ctx->frm = orig_frm;
+  goto done;
+}
+
diff --git a/sourcepawn/jit/interpreter.h b/sourcepawn/jit/interpreter.h
new file mode 100644
index 00000000..60e3f2f5
--- /dev/null
+++ b/sourcepawn/jit/interpreter.h
@@ -0,0 +1,39 @@
+// vim: set ts=8 sts=2 sw=2 tw=99 et:
+//
+// 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.
+// 
+// SourcePawn 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 SourcePawn.  If not, see .
+#ifndef _include_sourcepawn_interpreter_h_
+#define _include_sourcepawn_interpreter_h_
+
+#include 
+#include 
+#include "BaseRuntime.h"
+#include "sp_vm_basecontext.h"
+
+struct tracker_t
+{
+  size_t size; 
+  ucell_t *pBase; 
+  ucell_t *pCur;
+};
+
+int Interpret(BaseRuntime *rt, uint32_t aCodeStart, cell_t *rval);
+
+int GenerateFullArray(BaseRuntime *rt, uint32_t argc, cell_t *argv, int autozero);
+cell_t NativeCallback(sp_context_t *ctx, ucell_t native_idx, cell_t *params);
+int PopTrackerAndSetHeap(BaseRuntime *rt);
+int PushTracker(sp_context_t *ctx, size_t amount);
+
+#endif // _include_sourcepawn_interpreter_h_
diff --git a/sourcepawn/jit/jit_shared.h b/sourcepawn/jit/jit_shared.h
index 778ccb86..883f3bd4 100644
--- a/sourcepawn/jit/jit_shared.h
+++ b/sourcepawn/jit/jit_shared.h
@@ -67,6 +67,9 @@ namespace SourcePawn
 	} sp_plugin_t;
 }
 
+struct tracker_t;
+class BaseContext;
+
 typedef struct sp_context_s
 {
 	cell_t			hp;				/**< Heap pointer */
@@ -74,8 +77,12 @@ typedef struct sp_context_s
 	cell_t			frm;			/**< Frame pointer */
 	cell_t			rval;			/**< Return value from InvokeFunction() */
 	int32_t			cip;			/**< Code pointer last error occurred in */
+	int32_t			err;			/**< Error last set by interpreter */
 	int32_t			n_err;			/**< Error code set by a native */
 	uint32_t		n_idx;			/**< Current native index being executed */
+	tracker_t 		*tracker;
+	sp_plugin_t 	*plugin;
+	BaseContext		*basecx;
 	void *			vm[8];			/**< VM-specific pointers */
 	cell_t			rp;				/**< Return stack pointer */
 	cell_t			rstk_cips[SP_MAX_RETURN_STACK];
diff --git a/sourcepawn/jit/sp_vm_basecontext.cpp b/sourcepawn/jit/sp_vm_basecontext.cpp
index 82ee6bb7..666c6cfb 100644
--- a/sourcepawn/jit/sp_vm_basecontext.cpp
+++ b/sourcepawn/jit/sp_vm_basecontext.cpp
@@ -38,6 +38,8 @@
 #include "sp_vm_engine.h"
 #include "watchdog_timer.h"
 #include "x86/jit_x86.h"
+#include "engine2.h"
+#include "interpreter.h"
 
 using namespace SourcePawn;
 
@@ -595,7 +597,7 @@ int BaseContext::Execute2(IPluginFunction *function, const cell_t *params, unsig
 	}
 
 	/* See if we have to compile the callee. */
-	if ((fn = m_pRuntime->m_PubJitFuncs[public_id]) == NULL)
+	if (g_engine2.IsJitEnabled() && (fn = m_pRuntime->m_PubJitFuncs[public_id]) == NULL)
 	{
 		/* We might not have to - check pcode offset. */
 		fn = m_pRuntime->GetJittedFunctionByOffset(pubfunc->code_offs);
@@ -646,7 +648,10 @@ int BaseContext::Execute2(IPluginFunction *function, const cell_t *params, unsig
 
 	/* Start the frame tracer */
 
-	ir = g_Jit.InvokeFunction(m_pRuntime, fn, result);
+	if (g_engine2.IsJitEnabled())
+		ir = g_Jit.InvokeFunction(m_pRuntime, fn, result);
+	else
+		ir = Interpret(m_pRuntime, pubfunc->code_offs, result);
 
 	/* Restore some states, stop the frame tracer */
 
diff --git a/sourcepawn/jit/x86/jit_x86.cpp b/sourcepawn/jit/x86/jit_x86.cpp
index 8e50501d..74cb7ed7 100644
--- a/sourcepawn/jit/x86/jit_x86.cpp
+++ b/sourcepawn/jit/x86/jit_x86.cpp
@@ -38,6 +38,7 @@
 #include "../BaseRuntime.h"
 #include "../sp_vm_basecontext.h"
 #include "watchdog_timer.h"
+#include "interpreter.h"
 
 using namespace Knight;
 
@@ -166,50 +167,8 @@ GenerateArrayIndirectionVectors(cell_t *arraybase, cell_t dims[], cell_t _dimcou
   return data_offs;
 }
 
-static int
-PopTrackerAndSetHeap(BaseRuntime *rt)
-{
-  sp_context_t *ctx = rt->GetBaseContext()->GetCtx();
-  tracker_t *trk = (tracker_t *)(ctx->vm[JITVARS_TRACKER]);
-  assert(trk->pCur > trk->pBase);
-
-  trk->pCur--;
-  if (trk->pCur < trk->pBase)
-    return SP_ERROR_TRACKER_BOUNDS;
-
-  ucell_t amt = *trk->pCur;
-  if (amt > (ctx->hp - rt->plugin()->data_size))
-    return SP_ERROR_HEAPMIN;
-
-  ctx->hp -= amt;
-  return SP_ERROR_NONE;
-}
-
-static int
-PushTracker(sp_context_t *ctx, size_t amount)
-{
-  tracker_t *trk = (tracker_t *)(ctx->vm[JITVARS_TRACKER]);
-
-  if ((size_t)(trk->pCur - trk->pBase) >= trk->size)
-    return SP_ERROR_TRACKER_BOUNDS;
-
-  if (trk->pCur + 1 - (trk->pBase + trk->size) == 0) {
-    size_t disp = trk->size - 1;
-    trk->size *= 2;
-    trk->pBase = (ucell_t *)realloc(trk->pBase, trk->size * sizeof(cell_t));
-
-    if (!trk->pBase)
-      return SP_ERROR_TRACKER_BOUNDS;
-
-    trk->pCur = trk->pBase + disp;
-  }
-
-  *trk->pCur++ = amount;
-  return SP_ERROR_NONE;
-}
-
-static int
-GenerateArray(BaseRuntime *rt, uint32_t argc, cell_t *argv, int autozero)
+int
+GenerateFullArray(BaseRuntime *rt, uint32_t argc, cell_t *argv, int autozero)
 {
   sp_context_t *ctx = rt->GetBaseContext()->GetCtx();
 
@@ -342,55 +301,6 @@ CompileFromThunk(BaseRuntime *runtime, cell_t pcode_offs, void **addrp, char *pc
   return SP_ERROR_NONE;
 }
 
-static cell_t
-NativeCallback(sp_context_t *ctx, ucell_t native_idx, cell_t *params)
-{
-  sp_native_t *native;
-  cell_t save_sp = ctx->sp;
-  cell_t save_hp = ctx->hp;
-  sp_plugin_t *pl = (sp_plugin_t *)(ctx->vm[JITVARS_PLUGIN]);
-
-  ctx->n_idx = native_idx;
-
-  if (ctx->hp < (cell_t)pl->data_size) {
-    ctx->n_err = SP_ERROR_HEAPMIN;
-    return 0;
-  }
-
-  if (ctx->hp + STACK_MARGIN > ctx->sp) {
-    ctx->n_err = SP_ERROR_STACKLOW;
-    return 0;
-  }
-
-  if ((uint32_t)ctx->sp >= pl->mem_size) {
-    ctx->n_err = SP_ERROR_STACKMIN;
-    return 0;
-  }
-
-  native = &pl->natives[native_idx];
-
-  if (native->status == SP_NATIVE_UNBOUND) {
-    ctx->n_err = SP_ERROR_INVALID_NATIVE;
-    return 0;
-  }
-
-  cell_t result = native->pfn(GET_CONTEXT(ctx), params);
-
-  if (ctx->n_err != SP_ERROR_NONE)
-    return result;
-
-  if (save_sp != ctx->sp) {
-    ctx->n_err = SP_ERROR_STACKLEAK;
-    return result;
-  }
-  if (save_hp != ctx->hp) {
-    ctx->n_err = SP_ERROR_HEAPLEAK;
-    return result;
-  }
-
-  return result;
-}
-
 Compiler::Compiler(BaseRuntime *rt, cell_t pcode_offs)
   : rt_(rt),
     plugin_(rt->plugin()),
@@ -1226,7 +1136,7 @@ Compiler::emitOp(OPCODE op)
       __ movl(alt, Operand(hpAddr()));
       __ addl(Operand(hpAddr()), amount);
 
-      if (amount > 0) {
+      if (amount < 0) {
         __ cmpl(Operand(hpAddr()), plugin_->data_size);
         __ j(below, &error_heap_min_);
       } else {
@@ -1473,7 +1383,7 @@ Compiler::emitGenArray(bool autozero)
     __ push(stk);
     __ push(val);
     __ push(intptr_t(rt_));
-    __ call(ExternalAddress((void *)GenerateArray));
+    __ call(ExternalAddress((void *)GenerateFullArray));
     __ addl(esp, 4 * sizeof(void *));
 
     // restore pri to tmp
@@ -1921,16 +1831,13 @@ JITX86::CompileFunction(BaseRuntime *prt, cell_t pcode_offs, int *err)
 void
 JITX86::SetupContextVars(BaseRuntime *runtime, BaseContext *pCtx, sp_context_t *ctx)
 {
-  tracker_t *trk = new tracker_t;
-
-  ctx->vm[JITVARS_TRACKER] = trk;
-  ctx->vm[JITVARS_BASECTX] = pCtx; /* GetDefaultContext() is not constructed yet */
+  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->vm[JITVARS_PROFILER] = g_engine2.GetProfiler();
-  ctx->vm[JITVARS_PLUGIN] = const_cast(runtime->plugin());
-
-  trk->pBase = (ucell_t *)malloc(1024);
-  trk->pCur = trk->pBase;
-  trk->size = 1024 / sizeof(cell_t);
+  ctx->plugin = const_cast(runtime->plugin());
 }
 
 SPVM_NATIVE_FUNC
@@ -1987,8 +1894,8 @@ CompData::Abort()
 void
 JITX86::FreeContextVars(sp_context_t *ctx)
 {
-  free(((tracker_t *)(ctx->vm[JITVARS_TRACKER]))->pBase);
-  delete (tracker_t *)ctx->vm[JITVARS_TRACKER];
+  free(ctx->tracker->pBase);
+  delete ctx->tracker;
 }
 
 bool
diff --git a/sourcepawn/jit/x86/jit_x86.h b/sourcepawn/jit/x86/jit_x86.h
index eae3bff8..5fa7dc7e 100644
--- a/sourcepawn/jit/x86/jit_x86.h
+++ b/sourcepawn/jit/x86/jit_x86.h
@@ -36,22 +36,10 @@ using namespace SourcePawn;
 #define STACK_MARGIN            64      //8 parameters of safety, I guess
 #define JIT_FUNCMAGIC           0x214D4148  //magic function offset
 
-#define JITVARS_TRACKER         0    //important: don't change this to avoid trouble
-#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; 
-  ucell_t *pBase; 
-  ucell_t *pCur;
-} tracker_t;
-
 typedef struct funcinfo_s
 {
   unsigned int magic;