diff --git a/sourcepawn/include/sp_vm_api.h b/sourcepawn/include/sp_vm_api.h
new file mode 100644
index 00000000..c469093a
--- /dev/null
+++ b/sourcepawn/include/sp_vm_api.h
@@ -0,0 +1,133 @@
+#ifndef _INCLUDE_SOURCEPAWN_VM_API_H_
+#define _INCLUDE_SOURCEPAWN_VM_API_H_
+
+#include <stdio.h>
+#include "sp_vm_types.h"
+#include "sp_vm_context.h"
+
+namespace SourcePawn
+{
+	class IPluginContext;
+
+	/**
+	 * Contains helper functions used by VMs and the host app
+	 */
+	class ISourcePawnEngine
+	{
+	public:
+		/**
+		* Loads a named file from a file pointer.  
+		* Using this means base memory will be allocated by the VM.
+		* 
+		* @param fp		File pointer.  May be at any offset.  Not closed on return.
+		* @param err		Optional error code pointer.
+		* @return			A new plugin structure.
+		*/	
+		virtual sp_plugin_t *LoadFromFilePointer(FILE *fp, int *err) =0;
+	
+		/**
+		 * Loads a file from a base memory address.
+		 *	
+		 * @param base		Base address of the plugin's memory region.
+		 * @param plugin	If NULL, a new plugin pointer is returned.
+		 *                  Otherwise, the passed pointer is used.
+		 * @param err		Optional error code pointer.
+		 * @return			The resulting plugin pointer.
+		 */
+		virtual sp_plugin_t *LoadFromMemory(void *base, sp_plugin_t *plugin, int *err) =0;
+
+		/**
+		 * Frees all of the memory associated with a plugin file.
+		 * If allocated using SP_LoadFromMemory, the base and plugin pointer 
+		 *  itself are not freed (so this may end up doing nothing).
+		 */
+		virtual int FreeFromMemory(sp_plugin_t *plugin) =0;
+
+		/**
+		 * Creates a new IContext from a context handle.
+		 *
+		 * @param ctx		Context to use as a basis for the IPluginContext.
+		 * @return			New IPluginContext handle.
+		 */
+		virtual IPluginContext *CreateBaseContext(sp_context_t *ctx) =0;
+
+		/** 
+		 * Frees a context.
+		 *
+		 * @param ctx		Context pointer to free.
+		 */
+		virtual void FreeBaseContext(IPluginContext *ctx) =0;
+
+		/**
+		 * Allocates memory.
+		 * 
+		 * @param size		Size of memory to allocate.
+		 * @return			Pointer to memory, NULL if allocation failed.
+		 */
+		virtual void *BaseAlloc(size_t size) =0;
+
+		/**
+		 * Frees memory allocated with BaseAlloc.
+		 *
+		 * @param mem		Memory address to free.
+		 */
+		virtual void BaseFree(void *memory) =0;
+	};
+
+	class ICompilation;
+
+	class IVirtualMachine
+	{
+	public:
+		/**
+		 * Returns the string name of a VM implementation.
+		 */
+		virtual const char *GetVMName() =0;
+
+		/**
+		 * Begins a new compilation
+		 * 
+		 * @param plugin	Pointer to a plugin structure.
+		 * @return			New compilation pointer.
+		 */
+		virtual ICompilation *StartCompilation(sp_plugin_t *plugin) =0;
+
+		/**
+		 * Sets a compilation option.
+		 *
+		 * @param co		Pointer to a compilation.
+		 * @param key		Option key name.
+		 * @param val		Option value string.
+		 * @return			True if option could be set, false otherwise.
+		 */
+		virtual bool SetCompilationOption(ICompilation *co, const char *key, const char *val) =0;
+
+		/**
+		 * Finalizes a compilation into a new IContext.
+		 * Note: This will free the ICompilation pointer.
+		 *
+		 * @param co		Compilation pointer.
+		 * @return			New plugin context.
+		 */
+		virtual IPluginContext *CompileToContext(ICompilation *co) =0;
+
+		/**
+		 * Frees any internal variable usage on a context.
+		 *
+		 * @param ctx		Context structure pointer.
+		 */
+		virtual void FreeContextVars(sp_context_t *ctx) =0;
+
+		/**
+		 * Calls the "execute" function on a context.
+		 *
+		 * @param ctx		Executes a function in a context.
+		 * @param code_idx	Index into the code section.
+		 * @param result	Pointer to store result in.
+		 * @return			Error code (if any).
+		 */
+		virtual int ContextExecute(sp_context_t *ctx, uint32_t code_idx, cell_t *result) =0;
+	};
+};
+
+#endif //_INCLUDE_SOURCEPAWN_VM_API_H_
diff --git a/sourcepawn/include/sp_vm_context.h b/sourcepawn/include/sp_vm_context.h
new file mode 100644
index 00000000..e10dfca8
--- /dev/null
+++ b/sourcepawn/include/sp_vm_context.h
@@ -0,0 +1,309 @@
+#ifndef _INCLUDE_SOURCEPAWN_VM_CONTEXT_H_
+#define _INCLUDE_SOURCEPAWN_VM_CONTEXT_H_
+
+#include "sp_vm_types.h"
+
+/*****************
+ ** Note that all functions return a non-zero error code on failure
+ *   unless otherwise noted.
+ * All input pointers must be valid unless otherwise noted as optional.
+ * All output pointers on failure are undefined.
+ * All local address are guaranteed to be positive.  However, they are stored
+ *  as signed integers, because they must logically fit inside a cell.
+ */
+
+namespace SourcePawn
+{
+	class IVirtualMachine;
+
+	class IPluginDebugInfo
+	{
+	public:
+		/**
+		 * Given a code pointer, finds the file it is associated with.
+		 * 
+		 * @param addr		Code address offset.
+		 * @param filename	Pointer to store filename pointer in.
+		 */
+		virtual int LookupFile(ucell_t addr, const char **filename) =0;
+
+		/**
+		 * Given a code pointer, finds the function it is associated with.
+		 *
+		 * @param addr		Code address offset.
+		 * @param name		Pointer to store function name pointer in.
+		 */
+		virtual int LookupFunction(ucell_t addr, const char **name) =0;
+
+		/**
+		 * Given a code pointer, finds the line it is associated with.
+		 *
+		 * @param addr		Code address offset.
+		 * @param line		Pointer to store line number in.
+		 */
+		virtual int LookupLine(ucell_t addr, uint32_t *line) =0;
+	};
+
+	class IPluginContext
+	{
+	public:
+		virtual ~IPluginContext() { };
+	public:
+		/** 
+		 * Returns the parent IVirtualMachine.
+		 *
+		 * @return				Parent virtual machine pointer.
+		 */
+		virtual IVirtualMachine *GetVirtualMachine() =0;
+
+		/**
+		 * Returns the child sp_context_t structure.
+		 *
+		 * @return				Child sp_context_t structure.
+		 */
+		virtual sp_context_t *GetContext() =0;
+
+		/**
+		 * Returns true if the plugin is in debug mode.
+		 *
+		 * @return				True if in debug mode, false otherwise.
+		 */
+		virtual bool IsDebugging() =0;
+
+		/**
+		 * Installs a debug break and returns the old one, if any.
+		 * This will fail if the plugin is not debugging.
+		 *
+		 * @param newpfn		New function pointer.
+		 * @param oldpfn		Pointer to retrieve old function pointer.
+		 */
+		virtual int SetDebugBreak(SPVM_DEBUGBREAK newpfn, SPVM_DEBUGBREAK *oldpfn) =0;
+
+		/**
+		 * Returns debug info.
+		 *
+		 * @return				IPluginDebugInfo, or NULL if no debug info found.
+		 */
+		virtual IPluginDebugInfo *GetDebugInfo() =0;
+
+		/**
+		 * Allocs memory on the secondary stack of a plugin.
+		 * Note that although called a heap, it is in fact a stack.
+		 * 
+		 * @param cells			Number of cells to allocate.
+		 * @param local_adddr	Will be filled with data offset to heap.
+		 * @param phys_addr		Physical address to heap memory.
+		 */
+		virtual int HeapAlloc(unsigned int cells, cell_t *local_addr, cell_t **phys_addr) =0;
+
+		/**
+		 * Pops a heap address off the heap stack.  Use this to free memory allocated with
+		 *  SP_HeapAlloc().  
+		 * Note that in SourcePawn, the heap is in fact a bottom-up stack.  Deallocations
+		 *  with this native should be performed in precisely the REVERSE order.
+		 *
+		 * @param local_addr	Local address to free.
+ 		 */
+		virtual int HeapPop(cell_t local_addr) =0;
+
+		/**
+		 * Releases a heap address using a different method than SP_HeapPop().
+		 * This allows you to release in any order.  However, if you allocate N 
+		 *  objects, release only some of them, then begin allocating again, 
+		 *  you cannot go back and starting freeing the originals.  
+		 * In other words, for each chain of allocations, if you start deallocating,
+		 *  then allocating more in a chain, you must only deallocate from the current 
+		 *  allocation chain.  This is basically HeapPop() except on a larger scale.
+		 *
+		 * @param local_addr	Local address to free.
+ 		 */
+		virtual int HeapRelease(cell_t local_addr) =0;
+
+		/**
+		 * Finds a native by name.
+		 *
+		 * @param name			Name of native.
+		 * @param index			Optionally filled with native index number.
+		 */
+		virtual int FindNativeByName(const char *name, uint32_t *index) =0;
+
+		/**
+		 * Gets native info by index.
+		 *
+		 * @param index			Index number of native.
+		 * @param native		Optionally filled with pointer to native structure.
+		 */
+		virtual int GetNativeByIndex(uint32_t index, sp_native_t **native) =0;
+
+		/**
+		 * Gets the number of natives.
+		 * 
+		 * @return				Filled with the number of natives.
+		 */
+		virtual uint32_t GetNativesNum() =0;
+
+		/**
+		 * Finds a public function by name.
+		 *
+		 * @param name			Name of public
+		 * @param index			Optionally filled with public index number.
+		 */
+		virtual int FindPublicByName(const char *name, uint32_t *index) =0;
+
+		/**
+		 * Gets public function info by index.
+		 * 
+		 * @param index			Public function index number.
+		 * @param pblic			Optionally filled with pointer to public structure.
+		 */
+		virtual int GetPublicByIndex(uint32_t index, sp_public_t **publicptr) =0;
+
+		/**
+		 * Gets the number of public functions.
+		 *
+		 * @return				Filled with the number of public functions.
+		 */
+		virtual uint32_t GetPublicsNum() =0;
+
+		/**
+		 * Gets public variable info by index.
+		 * @param index			Public variable index number.
+		 * @param pubvar		Optionally filled with pointer to pubvar structure.
+		 */
+		virtual int GetPubvarByIndex(uint32_t index, sp_pubvar_t **pubvar) =0;
+
+		/**
+		 * Finds a public variable by name.
+		 *
+		 * @param name			Name of pubvar
+		 * @param index			Optionally filled with pubvar index number.
+		 * @param local_addr	Optionally filled with local address offset.
+		 * @param phys_addr		Optionally filled with relocated physical address.
+		 */
+		virtual int FindPubvarByName(const char *name, uint32_t *index) =0;
+
+		/**
+		* Gets the addresses of a public variable.
+		* 
+		* @param index			Index of public variable.
+		* @param local_addr		Address to store local address in.
+		* @param phys_addr		Address to store physically relocated in.
+		*/
+		virtual int GetPubvarAddrs(uint32_t index, cell_t *local_addr, cell_t **phys_addr) =0;
+
+		/**
+		 * Returns the number of public variables.
+		 *
+		 * @return				Number of public variables.
+		 */
+		virtual uint32_t GetPubVarsNum() =0;
+
+		/**
+		 * Round-about method of converting a plugin reference to a physical address
+		 *
+		 * @param local_addr	Local address in plugin.
+		 * @param phys_addr		Optionally filled with relocated physical address.
+		 */
+		virtual int LocalToPhysAddr(cell_t local_addr, cell_t **phys_addr) =0;
+
+		/**
+		 * Converts a local address to a physical string.
+		 * Note that SourcePawn does not support packed strings, as such this function is
+		 *  'cell to char' only.
+		 *
+		 * @param local_addr	Local address in plugin.
+		 * @param buffer		Destination output buffer.
+		 * @param maxlength		Maximum length of output buffer, including null terminator.
+		 * @param chars			Optionally filled with the number of characters written.
+		 */
+		virtual int LocalToString(cell_t local_addr, char *buffer, size_t maxlength, int *chars) =0;
+
+		/**
+		 * Converts a physical string to a local address.
+		 * Note that SourcePawn does not support packed strings.
+		 *
+		 * @param local_addr	Local address in plugin.
+		 * @param chars			Number of chars to write, including NULL terminator.
+		 * @param source		Source string to copy.
+		 */
+		virtual int StringToLocal(cell_t local_addr, size_t chars, const char *source) =0;
+
+		/**
+		 * Pushes a cell onto the stack.  Increases the parameter count by one.
+		 *
+		 * @param value			Cell value.
+		 */
+		virtual int PushCell(cell_t value) =0;
+
+		/** 
+		 * Pushes an array of cells onto the stack.  Increases the parameter count by one.
+		 * If the function returns an error it will fail entirely, releasing anything allocated in the process.
+		 * Note that this does not release the heap, so you should release it after
+		 *  calling Execute().
+		 *
+		 * @param local_addr	Filled with local address to release.
+		 * @param phys_addr		Optionally filled with physical address of new array.
+		 * @param array			Cell array to copy.
+		 * @param numcells		Number of cells in the array to copy.
+		 */
+		virtual int PushCellArray(cell_t *local_addr, cell_t **phys_addr, cell_t array[], unsigned int numcells) =0;
+
+		/**
+		 * Pushes a string onto the stack (by reference) and increases the parameter count by one.
+		 * Note that this does not release the heap, so you should release it after
+		 *  calling Execute().
+		 *
+		 * @param local_addr	Filled with local address to release.
+		 * @param phys_addr		Optionally filled with physical address of new array.
+		 * @param array			Cell array to copy.
+		 * @param numcells		Number of cells in the array to copy.
+		 */
+		virtual int PushString(cell_t *local_addr, cell_t **phys_addr, const char *string) =0;
+
+		/**
+		 * Individually pushes each cell of an array of cells onto the stack.  Increases the 
+		 *  parameter count by the number of cells pushed.
+		 * If the function returns an error it will fail entirely, releasing anything allocated in the process.
+		 *
+		 * @param array			Array of cells to read from.
+		 * @param numcells		Number of cells to read.
+		 */
+		virtual int PushCellsFromArray(cell_t array[], unsigned int numcells) =0;
+
+		/** 
+		 * Binds a list of native names and their function pointers to a context.
+		 * If num is 0, the list is read until an entry with a NULL name is reached.
+		 * All natives are assigned a status of SP_NATIVE_OKAY by default.
+		 * If overwrite is non-zero, already registered natives will be overwritten.
+		 * 
+		 * @param natives		Array of natives.
+		 * @param num			Number of natives in array.
+		 */
+		virtual int BindNatives(sp_nativeinfo_t *natives, unsigned int num, int overwrite) =0;
+
+		/**
+		 * Binds a single native.  Overwrites any existing bind.
+		 * If the context does not contain the native that will be binded the function will return
+		 *  with a SP_ERR_NOT_FOUND error.
+		 *
+		 * @param native		Pointer to native.
+		 * @param status		Status value to set (should be SP_NATIVE_OKAY).
+		 */
+		virtual int BindNative(sp_nativeinfo_t *native, uint32_t status) =0;
+
+		/**
+		 * Binds a single native to any non-registered or pending native.
+		 * Status is automatically set to pending.
+		 *
+		 * @param native		Native to bind.
+		 */
+		virtual int BindNativeToAny(SPVM_NATIVE_FUNC native) =0;
+
+		/**
+		 * Executes a public function.
+		 */
+		virtual int Execute(uint32_t public_func, cell_t *result) =0;
+	};
+};
+
+#endif //_INCLUDE_SOURCEPAWN_VM_CONTEXT_H_
diff --git a/sourcepawn/include/sp_vm_types.h b/sourcepawn/include/sp_vm_types.h
index f3f9c618..bb133369 100644
--- a/sourcepawn/include/sp_vm_types.h
+++ b/sourcepawn/include/sp_vm_types.h
@@ -19,6 +19,7 @@ typedef int32_t		cell_t;
 #define SP_ERR_INDEX				7	/* Invalid index parameter */
 #define SP_ERR_NATIVE_PENDING		8	/* A script tried to exec an unbound native */
 #define SP_ERR_STACKERR				9	/* Stack/Heap collision */
+#define SP_ERR_NOTDEBUGGING			10	/* Debug mode was not on or debug section not found */
 
 /**********************************************
  *** The following structures are reference structures.
@@ -125,6 +126,15 @@ typedef struct sp_native_s
 	uint32_t			status;	/* status flags */
 } sp_native_t;
 
+/** 
+ * Used for setting natives from modules/host apps.
+ */
+typedef struct sp_nativeinfo_s
+{
+	const char		*name;
+	SPVM_NATIVE_FUNC func;
+} sp_nativeinfo_t;
+
 /** 
  * Debug file table
  */
@@ -159,49 +169,39 @@ typedef struct sp_debug_symbol_s
 	sp_fdbg_symbol_t	*sym;	/* pointer to original symbol */
 } sp_debug_symbol_t;
 
-/**
- * Executes a Context.
- * @sp_context_s	- Execution Context
- * @uint32_t		- Offset from code pointer
- * @res				- return value of function
- * @return			- error code (0=none)
- */
-typedef int (*SPVM_EXEC)(struct sp_context_s *,
-							uint32_t,
-							cell_t *res);
-
 /**
  * Breaks into a debugger
  */
 typedef int (*SPVM_DEBUGBREAK)(struct sp_context_s *);
 
-#define SP_CONTEXT_DEBUG			(1<<0)		/* in debug mode */
-#define SP_CONTEXT_INHERIT_MEMORY	(1<<1)		/* inherits memory pointers */
-#define SP_CONTEXT_INHERIT_CODE		(1<<2)		/* inherits code pointers */
+#define SPFLAG_PLUGIN_DEBUG		(1<<0)		/* plugin is in debug mode */
 
 /**
  * This is the heart of the VM.  It contains all of the runtime
  *  information about a plugin context.  
- * It is split into three sections.
+ * Note that user[0..3] can be used for any user based pointers.
+ * vm[0..3] should not be touched, as it is reserved for the VM.
  */
 typedef struct sp_context_s
 {
 	/* general/parent information */
 	void			*base;		/* base of generated code and memory */
 	sp_plugin_t		*plugin;	/* pointer back to parent information */
-	struct sp_context_s *parent;	/* pointer to parent context */
-	uint32_t		flags;		/* context flags */
+	void			*context;	/* pointer to IPluginContext */
+	void			*vmbase;	/* pointer to IVirtualMachine */
+	void			*user[4];	/* user specific pointers */
+	void			*vm[4];		/* VM specific pointers */
+	uint32_t		flags;		/* compilation flags */
 	SPVM_DEBUGBREAK dbreak;		/* debug break function */
-	void			*user;		/* user specific pointer */
-	/* execution specific data */
-	SPVM_EXEC		exec;		/* execution base */
-	cell_t			pri;		/* PRI register */
-	cell_t			alt;		/* ALT register */
+	/* context runtime information */
+	ucell_t			memory;		/* total memory size; */
 	uint8_t			*data;		/* data chunk */
 	cell_t			heapbase;	/* heap base */
+	/* execution specific data */
+	cell_t			pri;		/* PRI register */
+	cell_t			alt;		/* ALT register */
 	cell_t			hp;			/* heap pointer */
 	cell_t			sp;			/* stack pointer */
-	ucell_t			memory;		/* total memory size; */
 	int32_t			err;		/* error code */
 	uint32_t		pushcount;	/* push count */
 	/* context rebased database */
diff --git a/sourcepawn/vm/msvc8/vm.vcproj b/sourcepawn/vm/msvc8/vm.vcproj
index 2516a305..9fd1a5ce 100644
--- a/sourcepawn/vm/msvc8/vm.vcproj
+++ b/sourcepawn/vm/msvc8/vm.vcproj
@@ -176,7 +176,11 @@
 			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
 			>
 			<File
-				RelativePath="..\sp_vm.c"
+				RelativePath="..\sp_vm_basecontext.cpp"
+				>
+			</File>
+			<File
+				RelativePath="..\sp_vm_engine.cpp"
 				>
 			</File>
 		</Filter>
@@ -186,19 +190,11 @@
 			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
 			>
 			<File
-				RelativePath="..\..\include\sp_file_headers.h"
+				RelativePath="..\sp_vm_basecontext.h"
 				>
 			</File>
 			<File
-				RelativePath="..\sp_vm.h"
-				>
-			</File>
-			<File
-				RelativePath="..\sp_vm_debug.h"
-				>
-			</File>
-			<File
-				RelativePath="..\..\include\sp_vm_types.h"
+				RelativePath="..\sp_vm_engine.h"
 				>
 			</File>
 		</Filter>
@@ -308,6 +304,26 @@
 				</File>
 			</Filter>
 		</Filter>
+		<Filter
+			Name="SDK"
+			>
+			<File
+				RelativePath="..\..\include\sp_file_headers.h"
+				>
+			</File>
+			<File
+				RelativePath="..\..\include\sp_vm_api.h"
+				>
+			</File>
+			<File
+				RelativePath="..\..\include\sp_vm_context.h"
+				>
+			</File>
+			<File
+				RelativePath="..\..\include\sp_vm_types.h"
+				>
+			</File>
+		</Filter>
 	</Files>
 	<Globals>
 	</Globals>
diff --git a/sourcepawn/vm/sp_vm.c b/sourcepawn/vm/sp_vm.c
deleted file mode 100644
index 303b92c3..00000000
--- a/sourcepawn/vm/sp_vm.c
+++ /dev/null
@@ -1,648 +0,0 @@
-#include <limits.h>
-#include <string.h>
-#include <assert.h>
-#include <malloc.h>
-#include "sp_vm.h"
-
-#define CELLBOUNDMAX	(INT_MAX/sizeof(cell_t))
-#define STACKMARGIN		((cell_t)(16*sizeof(cell_t)))
-
-/*int main()
-{
-	/** temporary testing area */
-	/*sp_context_t ctx;
-	cell_t l, *p;
-	cell_t arr1[] = {1,3,3,7};
-	cell_t arr2[] = {123,1234,12345,123456};
-	const char *str = "hat hat";
-	char buf[20];
-
-	ctx.data = (uint8_t *)malloc(50000);
-	ctx.memory = 50000;
-	ctx.heapbase = 200;
-	ctx.hp = ctx.heapbase;
-	ctx.sp = 45000;
-
-	assert(SP_HeapAlloc(&ctx, 500, &l, &p) == SP_ERR_NONE);
-	assert(SP_HeapPop(&ctx, l) == SP_ERR_NONE);
-	assert(SP_HeapRelease(&ctx, l) == SP_ERR_NONE);
-	assert(SP_HeapRelease(&ctx, 4) == SP_ERR_INVALID_ADDRESS);
-	assert(SP_HeapAlloc(&ctx, 500, &l, &p) == SP_ERR_NONE);
-	assert(SP_HeapRelease(&ctx, l) == SP_ERR_NONE);
-	assert(SP_PushCell(&ctx, 1337) == SP_ERR_NONE);
-	assert(SP_PushCellArray(&ctx, &l, &p, arr1, 4) == SP_ERR_NONE);
-	assert(SP_HeapRelease(&ctx, l) == SP_ERR_NONE);
-	assert(SP_PushCellsFromArray(&ctx, arr2, 4) == SP_ERR_NONE);
-	assert(SP_PushString(&ctx, &l, &p, str) == SP_ERR_NONE);
-	assert(SP_LocalToString(&ctx, l, NULL, buf, 20) == SP_ERR_NONE);
-	assert(SP_HeapRelease(&ctx, l) == SP_ERR_NONE);
-
-	return 0;
-}*/
-
-int SP_HeapAlloc(sp_context_t *ctx, unsigned int cells, cell_t *local_addr, cell_t **phys_addr)
-{
-	cell_t *addr;
-	ucell_t realmem;
-
-#if 0
-	if (cells > CELLBOUNDMAX)
-	{
-		return SP_ERR_PARAM;
-	}
-#else
-	assert(cells < CELLBOUNDMAX);
-#endif
-
-	realmem = cells * sizeof(cell_t);
-
-	/**
-	 * Check if the space between the heap and stack is sufficient.
-	 */
-	if ((cell_t)(ctx->sp - ctx->hp - realmem) < STACKMARGIN)
-	{
-		return SP_ERR_HEAPLOW;
-	}
-
-	addr = (cell_t *)(ctx->data + ctx->hp);
-	/* store size of allocation in cells */
-	*addr = (cell_t)cells;
-	addr++;
-	ctx->hp += sizeof(cell_t);
-
-	*local_addr = ctx->hp;
-
-	if (phys_addr)
-	{
-		*phys_addr = addr;
-	}
-
-	ctx->hp += realmem;
-
-	return SP_ERR_NONE;
-}
-
-int SP_HeapPop(sp_context_t *ctx, cell_t local_addr)
-{
-	cell_t cellcount;
-	cell_t *addr;
-
-	/* check the bounds of this address */
-	local_addr -= sizeof(cell_t);
-	if (local_addr < ctx->heapbase || local_addr >= ctx->sp)
-	{
-		return SP_ERR_INVALID_ADDRESS;
-	}
-
-	addr = (cell_t *)(ctx->data + local_addr);
-	cellcount = (*addr) * sizeof(cell_t);
-	/* check if this memory count looks valid */
-	if (ctx->hp - cellcount - sizeof(cell_t) != local_addr)
-	{
-		return SP_ERR_INVALID_ADDRESS;
-	}
-
-	ctx->hp = local_addr;
-
-	return SP_ERR_NONE;
-}
-
-int SP_HeapRelease(sp_context_t *ctx, cell_t local_addr)
-{
-	if (local_addr < ctx->heapbase)
-	{
-		return SP_ERR_INVALID_ADDRESS;
-	}
-
-	ctx->hp = local_addr - sizeof(cell_t);
-
-	return SP_ERR_NONE;
-}
-
-int SP_FindNativeByName(sp_context_t *ctx, const char *name, uint32_t *index)
-{
-	int diff, high, low;
-	uint32_t mid;
-
-	high = ctx->plugin->info.natives_num - 1;
-	low = 0;
-
-	while (low <= high)
-	{
-		mid = (low + high) / 2;
-		diff = strcmp(ctx->natives[mid].name, name);
-		if (diff == 0)
-		{
-			if (index)
-			{
-				*index = mid;
-			}
-			return SP_ERR_NONE;
-		} else if (diff < 0) {
-			low = mid + 1;
-		} else {
-			high = mid - 1;
-		}
-	}
-
-	return SP_ERR_NOT_FOUND;
-}
-
-int SP_GetNativeByIndex(sp_context_t *ctx, uint32_t index, sp_native_t **native)
-{
-	if (index >= ctx->plugin->info.natives_num)
-	{
-		return SP_ERR_INDEX;
-	}
-
-	if (native)
-	{
-		*native = &(ctx->natives[index]);
-	}
-
-	return SP_ERR_NONE;
-}
-
-int SP_GetNativesNum(sp_context_t *ctx, uint32_t *num)
-{
-	*num = ctx->plugin->info.natives_num;
-
-	return SP_ERR_NONE;
-}
-
-int SP_FindPublicByName(sp_context_t *ctx, const char *name, uint32_t *index)
-{
-	int diff, high, low;
-	uint32_t mid;
-
-	high = ctx->plugin->info.publics_num - 1;
-	low = 0;
-
-	while (low <= high)
-	{
-		mid = (low + high) / 2;
-		diff = strcmp(ctx->publics[mid].name, name);
-		if (diff == 0)
-		{
-			if (index)
-			{
-				*index = mid;
-			}
-			return SP_ERR_NONE;
-		} else if (diff < 0) {
-			low = mid + 1;
-		} else {
-			high = mid - 1;
-		}
-	}
-
-	return SP_ERR_NOT_FOUND;
-}
-
-int SP_GetPublicByIndex(sp_context_t *ctx, uint32_t index, sp_public_t **pblic)
-{
-	if (index >= ctx->plugin->info.publics_num)
-	{
-		return SP_ERR_INDEX;
-	}
-
-	if (pblic)
-	{
-		*pblic = &(ctx->publics[index]);
-	}
-
-	return SP_ERR_NONE;
-}
-
-int SP_GetPublicsNum(sp_context_t *ctx, uint32_t *num)
-{
-	*num = ctx->plugin->info.publics_num;
-
-	return SP_ERR_NONE;
-}
-
-int SP_GetPubvarByIndex(sp_context_t *ctx, uint32_t index, sp_pubvar_t **pubvar)
-{
-	if (index >= ctx->plugin->info.pubvars_num)
-	{
-		return SP_ERR_INDEX;
-	}
-
-	if (pubvar)
-	{
-		*pubvar = &(ctx->pubvars[index]);
-	}
-
-	return SP_ERR_NONE;
-}
-
-int SP_FindPubvarByName(sp_context_t *ctx, const char *name, uint32_t *index)
-{
-	int diff, high, low;
-	uint32_t mid;
-
-	high = ctx->plugin->info.pubvars_num - 1;
-	low = 0;
-
-	while (low <= high)
-	{
-		mid = (low + high) / 2;
-		diff = strcmp(ctx->pubvars[mid].name, name);
-		if (diff == 0)
-		{
-			if (index)
-			{
-				*index = mid;
-			}
-			return SP_ERR_NONE;
-		} else if (diff < 0) {
-			low = mid + 1;
-		} else {
-			high = mid - 1;
-		}
-	}
-
-	return SP_ERR_NOT_FOUND;
-}
-
-int SP_GetPubvarAddrs(sp_context_t *ctx, uint32_t index, cell_t *local_addr, cell_t **phys_addr)
-{
-	if (index >= ctx->plugin->info.pubvars_num)
-	{
-		return SP_ERR_INDEX;
-	}
-
-	*local_addr = ctx->plugin->info.pubvars[index].address;
-	*phys_addr = ctx->pubvars[index].offs;
-
-	return SP_ERR_NONE;
-}
-
-int SP_GetPubVarsNum(sp_context_t *ctx, uint32_t *num)
-{
-	*num = ctx->plugin->info.pubvars_num;
-
-	return SP_ERR_NONE;
-}
-
-int SP_BindNatives(sp_context_t *ctx, sp_nativeinfo_t *natives, unsigned int num, int overwrite)
-{
-	uint32_t i, j, max;
-
-	max = ctx->plugin->info.natives_num;
-
-	for (i=0; i<max; i++)
-	{
-		if ((ctx->natives[i].status == SP_NATIVE_OKAY) && !overwrite)
-		{
-			continue;
-		}
-
-		for (j=0; (natives[j].name) && (!num || j<num); j++)
-		{
-			if (!strcmp(ctx->natives[i].name, natives[j].name))
-			{
-				ctx->natives[i].pfn = natives[j].func;
-				ctx->natives[i].status = SP_NATIVE_OKAY;
-			}
-		}
-	}
-
-	return SP_ERR_NONE;
-}
-
-int SP_BindNative(sp_context_t *ctx, sp_nativeinfo_t *native, uint32_t status)
-{
-	uint32_t index;
-	int err;
-
-	if ((err = SP_FindNativeByName(ctx, native->name, &index)) != SP_ERR_NONE)
-	{
-		return err;
-	}
-
-	ctx->natives[index].pfn = native->func;
-	ctx->natives[index].status = status;
-
-	return SP_ERR_NONE;
-}
-
-int SP_BindNativeToAny(sp_context_t *ctx, SPVM_NATIVE_FUNC native)
-{
-	uint32_t nativesnum, i;
-
-	nativesnum = ctx->plugin->info.natives_num;
-
-	for (i=0; i<nativesnum; i++)
-	{
-		if (ctx->natives[i].status != SP_NATIVE_OKAY)
-		{
-			ctx->natives[i].pfn = native;
-			ctx->natives[i].status = SP_NATIVE_PENDING;
-		}
-	}
-
-	return SP_ERR_NONE;
-}
-
-int SP_LocalToPhysAddr(sp_context_t *ctx, cell_t local_addr, cell_t **phys_addr)
-{
-	if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->memory))
-	{
-		return SP_ERR_INVALID_ADDRESS;
-	}
-
-	if (phys_addr)
-	{
-		*phys_addr = (cell_t *)(ctx->data + local_addr);
-	}
-
-	return SP_ERR_NONE;
-}
-
-int SP_PushCell(sp_context_t *ctx, cell_t value)
-{
-	if ((ctx->hp + STACKMARGIN) > (cell_t)(ctx->sp - sizeof(cell_t)))
-	{
-		return SP_ERR_STACKERR;
-	}
-
-	ctx->sp -= sizeof(cell_t);
-	*(cell_t *)(ctx->data + ctx->sp) = value;
-	ctx->pushcount++;
-
-	return SP_ERR_NONE;
-}
-
-int SP_PushCellsFromArray(sp_context_t *ctx, cell_t array[], unsigned int numcells)
-{
-	unsigned int i;
-	int err;
-
-	for (i=0; i<numcells; i++)
-	{
-		if ((err = SP_PushCell(ctx, array[i])) != SP_ERR_NONE)
-		{
-			ctx->sp += (cell_t)(i * sizeof(cell_t));
-			ctx->pushcount -= i;
-			return err;
-		}
-	}
-
-	return SP_ERR_NONE;
-}
-
-int SP_PushCellArray(sp_context_t *ctx, cell_t *local_addr, cell_t **phys_addr, cell_t array[], unsigned int numcells)
-{
-	cell_t *ph_addr;
-	int err;
-
-	if ((err = SP_HeapAlloc(ctx, numcells, local_addr, &ph_addr)) != SP_ERR_NONE)
-	{
-		return err;
-	}
-
-	memcpy(ph_addr, array, numcells * sizeof(cell_t));
-
-	if ((err = SP_PushCell(ctx, *local_addr)) != SP_ERR_NONE)
-	{
-		SP_HeapRelease(ctx, *local_addr);
-		return err;
-	}
-
-	if (phys_addr)
-	{
-		*phys_addr = ph_addr;
-	}
-
-	return SP_ERR_NONE;
-}
-
-int SP_LocalToString(sp_context_t *ctx, cell_t local_addr, int *chars, char *buffer, size_t maxlength)
-{
-	int len = 0;
-	cell_t *src;
-
-	if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->memory))
-	{
-		return SP_ERR_INVALID_ADDRESS;
-	}
-
-	src = (cell_t *)(ctx->data + local_addr);
-	while ((*src != '\0') && ((size_t)len < maxlength))
-	{
-		buffer[len++] = (char)*src++;
-	}
-
-	if ((size_t)len >= maxlength)
-	{
-		len = maxlength - 1;
-	}
-	if (len >= 0)
-	{
-		buffer[len] = '\0';
-	}
-
-	if (chars)
-	{
-		*chars = len;
-	}
-
-	return SP_ERR_NONE;
-}
-
-int SP_PushString(sp_context_t *ctx, cell_t *local_addr, cell_t **phys_addr, const char *string)
-{
-	cell_t *ph_addr;
-	int err;
-	unsigned int i, numcells = strlen(string);
-
-	if ((err = SP_HeapAlloc(ctx, numcells+1, local_addr, &ph_addr)) != SP_ERR_NONE)
-	{
-		return err;
-	}
-
-	for (i=0; i<numcells; i++)
-	{
-		ph_addr[i] = (cell_t)string[i];
-	}
-	ph_addr[numcells] = '\0';
-
-	if ((err = SP_PushCell(ctx, *local_addr)) != SP_ERR_NONE)
-	{
-		SP_HeapRelease(ctx, *local_addr);
-		return err;
-	}
-
-	if (phys_addr)
-	{
-		*phys_addr = ph_addr;
-	}
-
-	return SP_ERR_NONE;
-}
-
-int SP_StringToLocal(sp_context_t *ctx, cell_t local_addr, size_t chars, const char *source)
-{
-	cell_t *dest;
-	int i, len;
-
-	if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->memory))
-	{
-		return SP_ERR_INVALID_ADDRESS;
-	}
-
-	len = strlen(source);
-	dest = (cell_t *)(ctx->data + local_addr);
-
-	if ((size_t)len >= chars)
-	{
-		len = chars - 1;
-	}
-
-	for (i=0; i<len; i++)
-	{
-		dest[i] = (cell_t)source[i];
-	}
-	dest[len] = '\0';
-
-	return SP_ERR_NONE;
-}
-
-int SP_CreateBaseContext(sp_plugin_t *plugin, sp_context_t **ctx)
-{
-	uint32_t iter, max;
-	uint8_t *dat, *cursor;
-	const char *strbase;
-	sp_fdbg_symbol_t *sym;
-	sp_fdbg_arraydim_t *arr;
-	sp_context_t *context;
-
-	context = (sp_context_t *)malloc(sizeof(sp_context_t));
-	memset(context, 0, sizeof(sp_context_t));
-
-	context->base = plugin->base;
-	context->plugin = plugin;
-	context->flags = plugin->flags;
-
-	context->data = (uint8_t *)malloc(plugin->memory);
-	memcpy(context->data, plugin->data, plugin->data_size);
-	context->memory = plugin->memory;
-	context->heapbase = (cell_t)(plugin->data_size);
-
-	strbase = plugin->info.stringbase;
-
-	if (max = plugin->info.publics_num)
-	{
-		context->publics = (sp_public_t *)malloc(sizeof(sp_public_t) * max);
-		for (iter=0; iter<max; iter++)
-		{
-			context->publics[iter].name = strbase + plugin->info.publics[iter].name;
-			context->publics[iter].offs = plugin->info.publics[iter].address;
-		}
-	}
-
-	if (max = plugin->info.pubvars_num)
-	{
-		dat = plugin->data;
-		context->pubvars = (sp_pubvar_t *)malloc(sizeof(sp_pubvar_t) * max);
-		for (iter=0; iter<max; iter++)
-		{
-			context->pubvars[iter].name = strbase + plugin->info.pubvars[iter].name;
-			context->pubvars[iter].offs = (cell_t *)(dat + plugin->info.pubvars[iter].address);
-		}
-	}
-
-	if (max = plugin->info.natives_num)
-	{
-		context->natives = (sp_native_t *)malloc(sizeof(sp_native_t) * max);
-		for (iter=0; iter<max; iter++)
-		{
-			context->natives[iter].name = strbase + plugin->info.natives[iter].name;
-			context->natives[iter].pfn = SP_NoExecNative;
-			context->natives[iter].status = SP_NATIVE_NONE;
-		}
-	}
-
-	strbase = plugin->debug.stringbase;
-
-	if (plugin->flags & SP_FLAG_DEBUG)
-	{
-		max = plugin->debug.files_num;
-		context->files = (sp_debug_file_t *)malloc(sizeof(sp_debug_file_t) * max);
-		for (iter=0; iter<max; iter++)
-		{
-			context->files[iter].addr = plugin->debug.files[iter].addr;
-			context->files[iter].name = strbase + plugin->debug.files[iter].name;
-		}
-
-		max = plugin->debug.lines_num;
-		context->lines = (sp_debug_line_t *)malloc(sizeof(sp_debug_line_t) * max);
-		for (iter=0; iter<max; iter++)
-		{
-			context->lines[iter].addr = plugin->debug.lines[iter].addr;
-			context->lines[iter].line = plugin->debug.lines[iter].line;
-		}
-
-		cursor = (uint8_t *)(plugin->debug.symbols);
-		max = plugin->debug.syms_num;
-		context->symbols = (sp_debug_symbol_t *)malloc(sizeof(sp_debug_symbol_t) * max);
-		for (iter=0; iter<max; iter++)
-		{
-			sym = (sp_fdbg_symbol_t *)cursor;
-
-			context->symbols[iter].codestart = sym->codestart;
-			context->symbols[iter].codeend = sym->codeend;
-			context->symbols[iter].name = strbase + sym->name;
-			context->symbols[iter].sym = sym;
-
-			if (sym->dimcount > 0)
-			{
-				cursor += sizeof(sp_fdbg_symbol_t);
-				arr = (sp_fdbg_arraydim_t *)cursor;
-				context->symbols[iter].dims = arr;
-				cursor += sizeof(sp_fdbg_arraydim_t) * sym->dimcount;
-				continue;
-			}
-
-			context->symbols[iter].dims = NULL;
-			cursor += sizeof(sp_fdbg_symbol_t);
-		}
-	}
-
-	*ctx = context;
-	return SP_ERR_NONE;
-}
-
-int SP_FreeBaseContext(sp_context_t *ctx)
-{
-	if (ctx->flags & SP_FLAG_DEBUG)
-	{
-		free(ctx->symbols);
-		free(ctx->lines);
-		free(ctx->files);
-	}
-	if (ctx->plugin->info.natives)
-	{
-		free(ctx->natives);
-	}
-	if (ctx->plugin->info.pubvars_num)
-	{
-		free(ctx->pubvars);
-	}
-	if (ctx->plugin->info.publics_num)
-	{
-		free(ctx->publics);
-	}
-	free(ctx->data);
-	free(ctx);
-
-	return SP_ERR_NONE;
-}
-
-cell_t SP_NoExecNative(sp_context_t *ctx, cell_t *params)
-{
-	ctx->err = SP_ERR_NATIVE_PENDING;
-
-	return 0;
-}
\ No newline at end of file
diff --git a/sourcepawn/vm/sp_vm.h b/sourcepawn/vm/sp_vm.h
deleted file mode 100644
index 8ed41cb2..00000000
--- a/sourcepawn/vm/sp_vm.h
+++ /dev/null
@@ -1,322 +0,0 @@
-#ifndef _INCLUDE_SOURCEPAWN_VM_H_
-#define _INCLUDE_SOURCEPAWN_VM_H_
-
-#include <stdio.h>
-#include "sp_vm_types.h"
-
-/*****************
- ** Note that all functions return a non-zero error code on failure
- *   unless otherwise noted.
- * All input pointers must be valid unless otherwise noted as optional.
- * All output pointers on failure are undefined.
- * All local address are guaranteed to be positive.  However, they are stored
- *  as signed integers, because they must logically fit inside a cell.
- */
-
-typedef struct sp_nativeinfo_s
-{
-	const char		*name;
-	SPVM_NATIVE_FUNC func;
-} sp_nativeinfo_t;
-
-/**
- * Loads a named file from a file pointer.  
- * Using this means base memory will be allocated by the VM.
- * 
- * @param fp		File pointer.  May be at any offset.  Not closed on return.
- * @param err		Optional error code pointer.
- * @return			A new plugin structure.
- */
-sp_plugin_t *SP_LoadFromFilePointer(FILE *fp, int *err);
-
-/**
- * Loads a file from a base memory address.
- *
- * @param base		Base address of the plugin's memory region.
- * @param plugin	If NULL, a new plugin pointer is returned.
- *                  Otherwise, the passed pointer is used.
- * @param err		Optional error code pointer.
- * @return			The resulting plugin pointer.
- */
-sp_plugin_t *SP_LoadFromMemory(void *base, sp_plugin_t *plugin, int *err);
-
-/**
- * Frees all of the memory associated with a plugin file.
- * If allocated using SP_LoadFromMemory, the base and plugin pointer 
- *  itself are not freed (so this may end up doing nothing).
- */
-int SP_FreeFromMemory(sp_plugin_t *plugin);
-
-/**
- * Allocs memory on the secondary stack of a plugin.
- * Note that although called a heap, it is in fact a stack.
- * 
- * @param ctx			Context pointer.
- * @param cells			Number of cells to allocate.
- * @param local_adddr	Will be filled with data offset to heap.
- * @param phys_addr		Physical address to heap memory.
- */
-int SP_HeapAlloc(sp_context_t *ctx, unsigned int cells, cell_t *local_addr, cell_t **phys_addr);
-
-/**
- * Pops a heap address off the heap stack.  Use this to free memory allocated with
- *  SP_HeapAlloc().  
- * Note that in SourcePawn, the heap is in fact a bottom-up stack.  Deallocations
- *  with this native should be performed in precisely the REVERSE order.
- */
-int SP_HeapPop(sp_context_t *ctx, cell_t local_addr);
-
-/**
- * Releases a heap address using a different method than SP_HeapPop().
- * This allows you to release in any order.  However, if you allocate N 
- *  objects, release only some of them, then begin allocating again, 
- *  you cannot go back and starting freeing the originals.  
- * In other words, for each chain of allocations, if you start deallocating,
- *  then allocating more in a chain, you must only deallocate from the current 
- *  allocation chain.  This is basically SP_HeapPop() except on a larger scale.
- */
-int SP_HeapRelease(sp_context_t *ctx, cell_t local_addr);
-
-/**
- * Finds a native by name.
- *
- * @param ctx			Context pointer.
- * @param name			Name of native.
- * @param index			Optionally filled with native index number.
- */
-int SP_FindNativeByName(sp_context_t *ctx, const char *name, uint32_t *index);
-
-/**
- * Gets native info by index.
- *
- * @param ctx			Context pointer.
- * @param index			Index number of native.
- * @param native		Optionally filled with pointer to native structure.
- */
-int SP_GetNativeByIndex(sp_context_t *ctx, uint32_t index, sp_native_t **native);
-
-/**
- * Gets the number of natives.
- * 
- * @param ctx			Context pointer.
- * @param num			Filled with the number of natives.
- */
-int SP_GetNativesNum(sp_context_t *ctx, uint32_t *num);
-
-/**
- * Finds a public function by name.
- *
- * @param ctx			Context pointer.
- * @param name			Name of public
- * @param index			Optionally filled with public index number.
- */
-int SP_FindPublicByName(sp_context_t *ctx, const char *name, uint32_t *index);
-
-
-/**
- * Gets public function info by index.
- * 
- * @param ctx			Context pointer.
- * @param index			Public function index number.
- * @param pblic			Optionally filled with pointer to public structure.
- */
-int SP_GetPublicByIndex(sp_context_t *ctx, uint32_t index, sp_public_t **pblic);
-
-/**
- * Gets the number of public functions.
- *
- * @param ctx			Context pointer.
- * @param num			Filled with the number of public functions.
- */
-int SP_GetPublicsNum(sp_context_t *ctx, uint32_t *num);
-
-/**
- * Gets public variable info by index.
- * @param ctx			Context pointer.
- * @param index			Public variable index number.
- * @param pubvar		Optionally filled with pointer to pubvar structure.
- */
-int SP_GetPubvarByIndex(sp_context_t *ctx, uint32_t index, sp_pubvar_t **pubvar);
-
-/**
- * Finds a public variable by name.
- *
- * @param ctx			Context pointer.
- * @param name			Name of pubvar
- * @param index			Optionally filled with pubvar index number.
- * @param local_addr	Optionally filled with local address offset.
- * @param phys_addr		Optionally filled with relocated physical address.
- */
-int SP_FindPubvarByName(sp_context_t *ctx, const char *name, uint32_t *index);
-
-//:TODO: fill in the info of this function, hi
-int SP_GetPubvarAddrs(sp_context_t *ctx, uint32_t index, cell_t *local_addr, cell_t **phys_addr);
-
-/**
-* Gets the number of public variables.
-*
-* @param ctx			Context pointer.
-* @param num			Filled with the number of public variables.
-*/
-int SP_GetPubVarsNum(sp_context_t *ctx, uint32_t *num);
-
-/**
- * Round-about method of converting a plugin reference to a physical address
- *
- * @param ctx			Context pointer.
- * @param local_addr	Local address in plugin.
- * @param phys_addr		Optionally filled with relocated physical address.
- */
-int SP_LocalToPhysAddr(sp_context_t *ctx, cell_t local_addr, cell_t **phys_addr);
-
-/**
- * Converts a local address to a physical string.
- * Note that SourcePawn does not support packed strings, as such this function is
- *  'cell to char' only.
- *
- * @param ctx			Context pointer.
- * @param local_addr	Local address in plugin.
- * @param chars			Optionally filled with the number of characters written.
- * @param buffer		Destination output buffer.
- * @param maxlength		Maximum length of output buffer, including null terminator.
- */
-int SP_LocalToString(sp_context_t *ctx, 
-					cell_t local_addr, 
-					int *chars, 
-					char *buffer, 
-					size_t maxlength);
-
-/**
- * Converts a physical string to a local address.
- * Note that SourcePawn does not support packed strings.
- * @param ctx			Context pointer
- * @param local_addr	Local address in plugin.
- * @param chars			Number of chars to write, including NULL terminator.
- * @param source		Source string to copy.
- */
-int SP_StringToLocal(sp_context_t *ctx,
-					 cell_t local_addr,
-					 size_t chars,
-					 const char *source);
-
-/**
- * Pushes a cell onto the stack.  Increases the parameter count by one.
- *
- * @param ctx			Context pointer.
- * @param value			Cell value.
- */
-int SP_PushCell(sp_context_t *ctx, cell_t value);
-
-/** 
- * Pushes an array of cells onto the stack.  Increases the parameter count by one.
- * If the function returns an error it will fail entirely, releasing anything allocated in the process.
- * Note that this does not release the heap, so you should release it after
- *  calling SP_Execute().
- *
- * @param ctx			Context pointer.
- * @param local_addr	Filled with local address to release.
- * @param phys_addr		Optionally filled with physical address of new array.
- * @param array			Cell array to copy.
- * @param numcells		Number of cells in the array to copy.
- */
-int SP_PushCellArray(sp_context_t *ctx, 
-					 cell_t *local_addr,
-					 cell_t **phys_addr,
-					 cell_t array[],
-					 unsigned int numcells);
-
-/**
- * Pushes a string onto the stack (by reference) and increases the parameter count by one.
- * Note that this does not release the heap, so you should release it after
- *  calling SP_Execute().
- *
- * @param ctx			Context pointer.
- * @param local_addr	Filled with local address to release.
- * @param phys_addr		Optionally filled with physical address of new array.
- * @param array			Cell array to copy.
- * @param numcells		Number of cells in the array to copy.
- */
-int SP_PushString(sp_context_t *ctx,
-				  cell_t *local_addr,
-				  cell_t **phys_addr,
-				  const char *string);
-
-/**
- * Individually pushes each cell of an array of cells onto the stack.  Increases the 
- *  parameter count by the number of cells pushed.
- * If the function returns an error it will fail entirely, releasing anything allocated in the process.
- *
- * @param ctx			Context pointer.
- * @param array			Array of cells to read from.
- * @param numcells		Number of cells to read.
- */
-int SP_PushCellsFromArray(sp_context_t *ctx, cell_t array[], unsigned int numcells);
-
-/** 
- * Binds a list of native names and their function pointers to a context.
- * If num is 0, the list is read until an entry with a NULL name is reached.
- * All natives are assigned a status of SP_NATIVE_OKAY by default.
- * If overwrite is non-zero, already registered natives will be overwritten.
- * 
- * @param ctx			Context pointer.
- * @param natives		Array of natives.
- * @param num			Number of natives in array.
- */
-int SP_BindNatives(sp_context_t *ctx, sp_nativeinfo_t *natives, unsigned int num, int overwrite);
-
-/**
- * Binds a single native.  Overwrites any existing bind.
- * If the context does not contain the native that will be binded the function will return
- *  with a SP_ERR_NOT_FOUND error.
- *
- * @param ctx			Context pointer.
- * @param native		Pointer to native.
- * @param status		Status value to set (should be SP_NATIVE_OKAY).
- */
-int SP_BindNative(sp_context_t *ctx, sp_nativeinfo_t *native, uint32_t status);
-
-/**
- * Binds a single native to any non-registered or pending native.
- * Status is automatically set to pending.
- *
- * @param ctx			Context pointer.
- */
-int SP_BindNativeToAny(sp_context_t *ctx, SPVM_NATIVE_FUNC native);
-
-/**
- * Executes a public function in a context.
- * The parameter count is set to zero during execution.
- * All context-specific variables that are modified are saved before execution,
- *  thus allowing nested calls to SP_Execute().  
- *
- * @param ctx			Context pointer.
- * @param idx			Public function index number.
- * @param result		Optional pointer to store return value.
- */
-int SP_Execute(sp_context_t *ctx, uint32_t idx, cell_t *result);
-
-/**
- * Creates a base context.  The context is not bound to any JIT, and thus
- *  inherits the parent code pointer of the file structure.  It does, 
- *  however, have relocated info+debug tables (even though the code address
- *  do not need to be relocated).  
- * It is guaranteed to have a newly allocated and copied memory layout
- *  of the data, heap and stack, and thus relevant address in the info/debug
- *  tables must be relocated.
- *
- * @param plugin		Plugin file structure to build a context form.
- * @param ctx			Pointer to store newly created context pointer.
- */
-int SP_CreateBaseContext(sp_plugin_t *plugin, sp_context_t **ctx);
-
-/**
- * Frees a base context.
- *
- * @param ctx			Context pointer.
- */
-int SP_FreeBaseContext(sp_context_t *ctx);
-
-//:TODO: fill in this
-cell_t SP_NoExecNative(sp_context_t *ctx, cell_t *params);
-
-#endif //_INCLUDE_SOURCEPAWN_VM_H_
diff --git a/sourcepawn/vm/sp_vm_basecontext.cpp b/sourcepawn/vm/sp_vm_basecontext.cpp
new file mode 100644
index 00000000..bc38cc82
--- /dev/null
+++ b/sourcepawn/vm/sp_vm_basecontext.cpp
@@ -0,0 +1,611 @@
+#include <string.h>
+#include <assert.h>
+#include <limits.h>
+#include "sp_vm_api.h"
+#include "sp_vm_basecontext.h"
+
+using namespace SourcePawn;
+
+#define CELLBOUNDMAX	(INT_MAX/sizeof(cell_t))
+#define STACKMARGIN		((cell_t)(16*sizeof(cell_t)))
+
+BaseContext::BaseContext(sp_context_t *_ctx)
+{
+	ctx = _ctx;
+}
+
+IVirtualMachine *BaseContext::GetVirtualMachine()
+{
+	return (IVirtualMachine *)ctx->vmbase;
+}
+
+sp_context_t *BaseContext::GetContext()
+{
+	return ctx;
+}
+
+bool BaseContext::IsDebugging()
+{
+	return (ctx->flags & SPFLAG_PLUGIN_DEBUG);
+}
+
+int BaseContext::SetDebugBreak(SPVM_DEBUGBREAK newpfn, SPVM_DEBUGBREAK *oldpfn)
+{
+	if (!IsDebugging())
+	{
+		return SP_ERR_NOTDEBUGGING;
+	}
+
+	*oldpfn = ctx->dbreak;
+	ctx->dbreak = newpfn;
+
+	return SP_ERR_NONE;
+}
+
+IPluginDebugInfo *BaseContext::GetDebugInfo()
+{
+	return this;
+}
+
+int BaseContext::Execute(uint32_t public_func, cell_t *result)
+{
+	IVirtualMachine *vm = (IVirtualMachine *)ctx->vmbase;
+
+	int err;
+	sp_public_t *pubfunc;
+	if ((err=GetPublicByIndex(public_func, &pubfunc)) != SP_ERR_NONE)
+	{
+		return err;
+	}
+
+	return vm->ContextExecute(ctx, pubfunc->offs, result);
+}
+
+int BaseContext::HeapAlloc(unsigned int cells, cell_t *local_addr, cell_t **phys_addr)
+{
+	cell_t *addr;
+	ucell_t realmem;
+
+#if 0
+	if (cells > CELLBOUNDMAX)
+	{
+		return SP_ERR_PARAM;
+	}
+#else
+	assert(cells < CELLBOUNDMAX);
+#endif
+
+	realmem = cells * sizeof(cell_t);
+
+	/**
+	* Check if the space between the heap and stack is sufficient.
+	*/
+	if ((cell_t)(ctx->sp - ctx->hp - realmem) < STACKMARGIN)
+	{
+		return SP_ERR_HEAPLOW;
+	}
+
+	addr = (cell_t *)(ctx->data + ctx->hp);
+	/* store size of allocation in cells */
+	*addr = (cell_t)cells;
+	addr++;
+	ctx->hp += sizeof(cell_t);
+
+	*local_addr = ctx->hp;
+
+	if (phys_addr)
+	{
+		*phys_addr = addr;
+	}
+
+	ctx->hp += realmem;
+
+	return SP_ERR_NONE;
+}
+
+int BaseContext::HeapPop(cell_t local_addr)
+{
+	cell_t cellcount;
+	cell_t *addr;
+
+	/* check the bounds of this address */
+	local_addr -= sizeof(cell_t);
+	if (local_addr < ctx->heapbase || local_addr >= ctx->sp)
+	{
+		return SP_ERR_INVALID_ADDRESS;
+	}
+
+	addr = (cell_t *)(ctx->data + local_addr);
+	cellcount = (*addr) * sizeof(cell_t);
+	/* check if this memory count looks valid */
+	if (ctx->hp - cellcount - sizeof(cell_t) != local_addr)
+	{
+		return SP_ERR_INVALID_ADDRESS;
+	}
+
+	ctx->hp = local_addr;
+
+	return SP_ERR_NONE;
+}
+
+
+int BaseContext::HeapRelease(cell_t local_addr)
+{
+	if (local_addr < ctx->heapbase)
+	{
+		return SP_ERR_INVALID_ADDRESS;
+	}
+
+	ctx->hp = local_addr - sizeof(cell_t);
+
+	return SP_ERR_NONE;
+}
+
+int BaseContext::FindNativeByName(const char *name, uint32_t *index)
+{
+	int diff, high, low;
+	uint32_t mid;
+
+	high = ctx->plugin->info.natives_num - 1;
+	low = 0;
+
+	while (low <= high)
+	{
+		mid = (low + high) / 2;
+		diff = strcmp(ctx->natives[mid].name, name);
+		if (diff == 0)
+		{
+			if (index)
+			{
+				*index = mid;
+			}
+			return SP_ERR_NONE;
+		} else if (diff < 0) {
+			low = mid + 1;
+		} else {
+			high = mid - 1;
+		}
+	}
+
+	return SP_ERR_NOT_FOUND;
+}
+
+int BaseContext::GetNativeByIndex(uint32_t index, sp_native_t **native)
+{
+	if (index >= ctx->plugin->info.natives_num)
+	{
+		return SP_ERR_INDEX;
+	}
+
+	if (native)
+	{
+		*native = &(ctx->natives[index]);
+	}
+
+	return SP_ERR_NONE;
+}
+
+
+uint32_t BaseContext::GetNativesNum()
+{
+	return ctx->plugin->info.natives_num;
+}
+
+int BaseContext::FindPublicByName(const char *name, uint32_t *index)
+{
+	int diff, high, low;
+	uint32_t mid;
+
+	high = ctx->plugin->info.publics_num - 1;
+	low = 0;
+
+	while (low <= high)
+	{
+		mid = (low + high) / 2;
+		diff = strcmp(ctx->publics[mid].name, name);
+		if (diff == 0)
+		{
+			if (index)
+			{
+				*index = mid;
+			}
+			return SP_ERR_NONE;
+		} else if (diff < 0) {
+			low = mid + 1;
+		} else {
+			high = mid - 1;
+		}
+	}
+
+	return SP_ERR_NOT_FOUND;
+}
+
+int BaseContext::GetPublicByIndex(uint32_t index, sp_public_t **pblic)
+{
+	if (index >= ctx->plugin->info.publics_num)
+	{
+		return SP_ERR_INDEX;
+	}
+
+	if (pblic)
+	{
+		*pblic = &(ctx->publics[index]);
+	}
+
+	return SP_ERR_NONE;
+}
+
+uint32_t BaseContext::GetPublicsNum()
+{
+	return ctx->plugin->info.publics_num;
+}
+
+int BaseContext::GetPubvarByIndex(uint32_t index, sp_pubvar_t **pubvar)
+{
+	if (index >= ctx->plugin->info.pubvars_num)
+	{
+		return SP_ERR_INDEX;
+	}
+
+	if (pubvar)
+	{
+		*pubvar = &(ctx->pubvars[index]);
+	}
+
+	return SP_ERR_NONE;
+}
+
+int BaseContext::FindPubvarByName(const char *name, uint32_t *index)
+{
+	int diff, high, low;
+	uint32_t mid;
+
+	high = ctx->plugin->info.pubvars_num - 1;
+	low = 0;
+
+	while (low <= high)
+	{
+		mid = (low + high) / 2;
+		diff = strcmp(ctx->pubvars[mid].name, name);
+		if (diff == 0)
+		{
+			if (index)
+			{
+				*index = mid;
+			}
+			return SP_ERR_NONE;
+		} else if (diff < 0) {
+			low = mid + 1;
+		} else {
+			high = mid - 1;
+		}
+	}
+
+	return SP_ERR_NOT_FOUND;
+}
+
+int BaseContext::GetPubvarAddrs(uint32_t index, cell_t *local_addr, cell_t **phys_addr)
+{
+	if (index >= ctx->plugin->info.pubvars_num)
+	{
+		return SP_ERR_INDEX;
+	}
+
+	*local_addr = ctx->plugin->info.pubvars[index].address;
+	*phys_addr = ctx->pubvars[index].offs;
+
+	return SP_ERR_NONE;
+}
+
+uint32_t BaseContext::GetPubVarsNum()
+{
+	return ctx->plugin->info.pubvars_num;
+}
+
+int BaseContext::BindNatives(sp_nativeinfo_t *natives, unsigned int num, int overwrite)
+{
+	uint32_t i, j, max;
+
+	max = ctx->plugin->info.natives_num;
+
+	for (i=0; i<max; i++)
+	{
+		if ((ctx->natives[i].status == SP_NATIVE_OKAY) && !overwrite)
+		{
+			continue;
+		}
+
+		for (j=0; (natives[j].name) && (!num || j<num); j++)
+		{
+			if (!strcmp(ctx->natives[i].name, natives[j].name))
+			{
+				ctx->natives[i].pfn = natives[j].func;
+				ctx->natives[i].status = SP_NATIVE_OKAY;
+			}
+		}
+	}
+
+	return SP_ERR_NONE;
+}
+
+
+
+int BaseContext::BindNative(sp_nativeinfo_t *native, uint32_t status)
+{
+	uint32_t index;
+	int err;
+
+	if ((err = FindNativeByName(native->name, &index)) != SP_ERR_NONE)
+	{
+		return err;
+	}
+
+	ctx->natives[index].pfn = native->func;
+	ctx->natives[index].status = status;
+
+	return SP_ERR_NONE;
+}
+
+int BaseContext::BindNativeToAny(SPVM_NATIVE_FUNC native)
+{
+	uint32_t nativesnum, i;
+
+	nativesnum = ctx->plugin->info.natives_num;
+
+	for (i=0; i<nativesnum; i++)
+	{
+		if (ctx->natives[i].status != SP_NATIVE_OKAY)
+		{
+			ctx->natives[i].pfn = native;
+			ctx->natives[i].status = SP_NATIVE_PENDING;
+		}
+	}
+
+	return SP_ERR_NONE;
+}
+
+int BaseContext::LocalToPhysAddr(cell_t local_addr, cell_t **phys_addr)
+{
+	if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->memory))
+	{
+		return SP_ERR_INVALID_ADDRESS;
+	}
+
+	if (phys_addr)
+	{
+		*phys_addr = (cell_t *)(ctx->data + local_addr);
+	}
+
+	return SP_ERR_NONE;
+}
+
+int BaseContext::PushCell(cell_t value)
+{
+	if ((ctx->hp + STACKMARGIN) > (cell_t)(ctx->sp - sizeof(cell_t)))
+	{
+		return SP_ERR_STACKERR;
+	}
+
+	ctx->sp -= sizeof(cell_t);
+	*(cell_t *)(ctx->data + ctx->sp) = value;
+	ctx->pushcount++;
+
+	return SP_ERR_NONE;
+}
+
+int BaseContext::PushCellsFromArray(cell_t array[], unsigned int numcells)
+{
+	unsigned int i;
+	int err;
+
+	for (i=0; i<numcells; i++)
+	{
+		if ((err = PushCell(array[i])) != SP_ERR_NONE)
+		{
+			ctx->sp += (cell_t)(i * sizeof(cell_t));
+			ctx->pushcount -= i;
+			return err;
+		}
+	}
+
+	return SP_ERR_NONE;
+}
+
+int BaseContext::PushCellArray(cell_t *local_addr, cell_t **phys_addr, cell_t array[], unsigned int numcells)
+{
+	cell_t *ph_addr;
+	int err;
+
+	if ((err = HeapAlloc(numcells, local_addr, &ph_addr)) != SP_ERR_NONE)
+	{
+		return err;
+	}
+
+	memcpy(ph_addr, array, numcells * sizeof(cell_t));
+
+	if ((err = PushCell(*local_addr)) != SP_ERR_NONE)
+	{
+		HeapRelease(*local_addr);
+		return err;
+	}
+
+	if (phys_addr)
+	{
+		*phys_addr = ph_addr;
+	}
+
+	return SP_ERR_NONE;
+}
+
+int BaseContext::LocalToString(cell_t local_addr, char *buffer, size_t maxlength, int *chars)
+{
+	int len = 0;
+	cell_t *src;
+
+	if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->memory))
+	{
+		return SP_ERR_INVALID_ADDRESS;
+	}
+
+	src = (cell_t *)(ctx->data + local_addr);
+	while ((*src != '\0') && ((size_t)len < maxlength))
+	{
+		buffer[len++] = (char)*src++;
+	}
+
+	if ((size_t)len >= maxlength)
+	{
+		len = maxlength - 1;
+	}
+	if (len >= 0)
+	{
+		buffer[len] = '\0';
+	}
+
+	if (chars)
+	{
+		*chars = len;
+	}
+
+	return SP_ERR_NONE;
+}
+
+int BaseContext::PushString(cell_t *local_addr, cell_t **phys_addr, const char *string)
+{
+	cell_t *ph_addr;
+	int err;
+	unsigned int i, numcells = strlen(string);
+
+	if ((err = HeapAlloc(numcells+1, local_addr, &ph_addr)) != SP_ERR_NONE)
+	{
+		return err;
+	}
+
+	for (i=0; i<numcells; i++)
+	{
+		ph_addr[i] = (cell_t)string[i];
+	}
+	ph_addr[numcells] = '\0';
+
+	if ((err = PushCell(*local_addr)) != SP_ERR_NONE)
+	{
+		HeapRelease(*local_addr);
+		return err;
+	}
+
+	if (phys_addr)
+	{
+		*phys_addr = ph_addr;
+	}
+
+	return SP_ERR_NONE;
+}
+
+int BaseContext::StringToLocal(cell_t local_addr, size_t chars, const char *source)
+{
+	cell_t *dest;
+	int i, len;
+
+	if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->memory))
+	{
+		return SP_ERR_INVALID_ADDRESS;
+	}
+
+	len = strlen(source);
+	dest = (cell_t *)(ctx->data + local_addr);
+
+	if ((size_t)len >= chars)
+	{
+		len = chars - 1;
+	}
+
+	for (i=0; i<len; i++)
+	{
+		dest[i] = (cell_t)source[i];
+	}
+	dest[len] = '\0';
+
+	return SP_ERR_NONE;
+}
+
+#define USHR(x) ((unsigned int)(x)>>1)
+
+int BaseContext::LookupFile(ucell_t addr, const char **filename)
+{
+	int high, low, mid;
+
+	high = ctx->plugin->debug.files_num;
+	low = -1;
+
+	while (high - low > 1)
+	{
+		mid = USHR(low + high);
+		if (ctx->files[mid].addr <= addr)
+		{
+			low = mid;
+		} else {
+			high = mid;
+		}
+	}
+
+	if (low == -1)
+	{
+		return SP_ERR_NOT_FOUND;
+	}
+
+	*filename = ctx->files[low].name;
+
+	return SP_ERR_NONE;
+}
+
+int BaseContext::LookupFunction(ucell_t addr, const char **name)
+{
+	uint32_t iter, max = ctx->plugin->debug.syms_num;
+
+	for (iter=0; iter<max; iter++)
+	{
+		if ((ctx->symbols[iter].sym->ident == SP_SYM_FUNCTION) 
+			&& (ctx->symbols[iter].codestart <= addr) 
+			&& (ctx->symbols[iter].codeend > addr))
+		{
+			break;
+		}
+	}
+
+	if (iter >= max)
+	{
+		return SP_ERR_NOT_FOUND;
+	}
+
+	*name = ctx->symbols[iter].name;
+
+	return SP_ERR_NONE;
+}
+
+int BaseContext::LookupLine(ucell_t addr, uint32_t *line)
+{
+	int high, low, mid;
+
+	high = ctx->plugin->debug.lines_num;
+	low = -1;
+
+	while (high - low > 1)
+	{
+		mid = USHR(low + high);
+		if (ctx->lines[mid].addr <= addr)
+		{
+			low = mid;
+		} else {
+			high = mid;
+		}
+	}
+
+	if (low == -1)
+	{
+		return SP_ERR_NOT_FOUND;
+	}
+
+	*line = ctx->lines[low].line;
+
+	return SP_ERR_NONE;
+}
diff --git a/sourcepawn/vm/sp_vm_basecontext.h b/sourcepawn/vm/sp_vm_basecontext.h
new file mode 100644
index 00000000..e49972e4
--- /dev/null
+++ b/sourcepawn/vm/sp_vm_basecontext.h
@@ -0,0 +1,53 @@
+#ifndef _INCLUDE_SOURCEPAWN_BASECONTEXT_H_
+#define _INCLUDE_SOURCEPAWN_BASECONTEXT_H_
+
+#include "sp_vm_context.h"
+
+namespace SourcePawn
+{
+	class BaseContext : 
+		public IPluginContext,
+		public IPluginDebugInfo
+	{
+	public:
+		BaseContext(sp_context_t *ctx);
+	public: //IPluginContext
+		IVirtualMachine *GetVirtualMachine();
+		sp_context_t *GetContext();
+		bool IsDebugging();
+		int SetDebugBreak(SPVM_DEBUGBREAK newpfn, SPVM_DEBUGBREAK *oldpfn);
+		IPluginDebugInfo *GetDebugInfo();
+		virtual int HeapAlloc(unsigned int cells, cell_t *local_addr, cell_t **phys_addr);
+		virtual int HeapPop(cell_t local_addr);
+		virtual int HeapRelease(cell_t local_addr);
+		virtual int FindNativeByName(const char *name, uint32_t *index);
+		virtual int GetNativeByIndex(uint32_t index, sp_native_t **native);
+		virtual uint32_t GetNativesNum();
+		virtual int FindPublicByName(const char *name, uint32_t *index);
+		virtual int GetPublicByIndex(uint32_t index, sp_public_t **publicptr);
+		virtual uint32_t GetPublicsNum();
+		virtual int GetPubvarByIndex(uint32_t index, sp_pubvar_t **pubvar);
+		virtual int FindPubvarByName(const char *name, uint32_t *index);
+		virtual int GetPubvarAddrs(uint32_t index, cell_t *local_addr, cell_t **phys_addr);
+		virtual uint32_t GetPubVarsNum();
+		virtual int LocalToPhysAddr(cell_t local_addr, cell_t **phys_addr);
+		virtual int LocalToString(cell_t local_addr, char *buffer, size_t maxlength, int *chars);
+		virtual int StringToLocal(cell_t local_addr, size_t chars, const char *source);
+		virtual int PushCell(cell_t value);
+		virtual int PushCellArray(cell_t *local_addr, cell_t **phys_addr, cell_t array[], unsigned int numcells);
+		virtual int PushString(cell_t *local_addr, cell_t **phys_addr, const char *string);
+		virtual int PushCellsFromArray(cell_t array[], unsigned int numcells);
+		virtual int BindNatives(sp_nativeinfo_t *natives, unsigned int num, int overwrite);
+		virtual int BindNative(sp_nativeinfo_t *native, uint32_t status);
+		virtual int BindNativeToAny(SPVM_NATIVE_FUNC native);
+		virtual int Execute(uint32_t public_func, cell_t *result);
+	public: //IPluginDebugInfo
+		virtual int LookupFile(ucell_t addr, const char **filename);
+		virtual int LookupFunction(ucell_t addr, const char **name);
+		virtual int LookupLine(ucell_t addr, uint32_t *line);
+	private:
+		sp_context_t *ctx;
+	};
+};
+
+#endif //_INCLUDE_SOURCEPAWN_BASECONTEXT_H_
diff --git a/sourcepawn/vm/sp_vm_debug.c b/sourcepawn/vm/sp_vm_debug.c
deleted file mode 100644
index 862af16d..00000000
--- a/sourcepawn/vm/sp_vm_debug.c
+++ /dev/null
@@ -1,94 +0,0 @@
-#include "sp_vm.h"
-#include "sp_vm_debug.h"
-
-#define USHR(x) ((unsigned int)(x)>>1)
-
-int SP_DbgLookupFile(sp_context_t *ctx, ucell_t addr, const char **filename)
-{
-	int high, low, mid;
-
-	high = ctx->plugin->debug.files_num;
-	low = -1;
-
-	while (high - low > 1)
-	{
-		mid = USHR(low + high);
-		if (ctx->files[mid].addr <= addr)
-		{
-			low = mid;
-		} else {
-			high = mid;
-		}
-	}
-
-	if (low == -1)
-	{
-		return SP_ERR_NOT_FOUND;
-	}
-
-	*filename = ctx->files[low].name;
-
-	return SP_ERR_NONE;
-}
-
-int SP_DbgLookupFunction(sp_context_t *ctx, ucell_t addr, const char **name)
-{
-	uint32_t iter, max = ctx->plugin->debug.syms_num;
-
-	for (iter=0; iter<max; iter++)
-	{
-		if ((ctx->symbols[iter].sym->ident == SP_SYM_FUNCTION) 
-			&& (ctx->symbols[iter].codestart <= addr) 
-			&& (ctx->symbols[iter].codeend > addr))
-		{
-			break;
-		}
-	}
-
-	if (iter >= max)
-	{
-		return SP_ERR_NOT_FOUND;
-	}
-
-	*name = ctx->symbols[iter].name;
-
-	return SP_ERR_NONE;
-}
-
-int SP_DbgLookupLine(sp_context_t *ctx, ucell_t addr, uint32_t *line)
-{
-	int high, low, mid;
-
-	high = ctx->plugin->debug.lines_num;
-	low = -1;
-
-	while (high - low > 1)
-	{
-		mid = USHR(low + high);
-		if (ctx->lines[mid].addr <= addr)
-		{
-			low = mid;
-		} else {
-			high = mid;
-		}
-	}
-
-	if (low == -1)
-	{
-		return SP_ERR_NOT_FOUND;
-	}
-
-	*line = ctx->lines[low].line;
-
-	return SP_ERR_NONE;
-}
-
-int SP_DbgInstallBreak(sp_context_t *ctx, SPVM_DEBUGBREAK newpfn, SPVM_DEBUGBREAK *oldpfn)
-{
-	if (ctx->dbreak)
-		*oldpfn = ctx->dbreak;
-
-	ctx->dbreak = newpfn;
-
-	return SP_ERR_NONE;
-}
diff --git a/sourcepawn/vm/sp_vm_debug.h b/sourcepawn/vm/sp_vm_debug.h
deleted file mode 100644
index 901f955c..00000000
--- a/sourcepawn/vm/sp_vm_debug.h
+++ /dev/null
@@ -1,52 +0,0 @@
-#ifndef _INCLUDE_SOURCEPAWN_VM_DEBUG_H
-#define _INCLUDE_SOURCEPAWN_VM_DEBUG_H
-
-/*****************
- ** Note that all functions return a non-zero error code on failure
- *   unless otherwise noted.
- * All input pointers must be valid unless otherwise noted as optional.
- * All output pointers on failure are undefined.
- * All local address are guaranteed to be positive.  However, they are stored
- *  as signed integers, because they must logically fit inside a cell.
- */
-
-/**
- * Given a code pointer, finds the file it is associated with.
- * 
- * @param ctx		Context pointer.
- * @param addr		Code address offset.
- * @param filename	Pointer to store filename pointer in.
- */
-int SP_DbgLookupFile(sp_context_t *ctx, ucell_t addr, const char **filename);
-
-/**
- * Given a code pointer, finds the function it is associated with.
- *
- * @param ctx		Context pointer.
- * @param addr		Code address offset.
- * @param name		Pointer to store function name pointer in.
- */
-int SP_DbgLookupFunction(sp_context_t *ctx, ucell_t addr, const char **name);
-
-/**
- * Given a code pointer, finds the line it is associated with.
- *
- * @param ctx		Context pointer.
- * @param addr		Code address offset.
- * @param line		Pointer to store line number in.
- */
-int SP_DbgLookupLine(sp_context_t *ctx, ucell_t addr, uint32_t *line);
-
-/**
- * Installs a debug break and returns the old one, if any.
- *
- * @param ctx		Context pointer.
- * @param newpfn	New function pointer.
- * @param oldpfn	Pointer to retrieve old function pointer.
- */
-int SP_DbgInstallBreak(sp_context_t *ctx, 
-					   SPVM_DEBUGBREAK newpfn, 
-					   SPVM_DEBUGBREAK *oldpfn);
-
-
-#endif //_INCLUDE_SOURCEPAWN_VM_DEBUG_H
diff --git a/sourcepawn/vm/sp_reader.c b/sourcepawn/vm/sp_vm_engine.cpp
similarity index 74%
rename from sourcepawn/vm/sp_reader.c
rename to sourcepawn/vm/sp_vm_engine.cpp
index 7f6b17c6..5bae6220 100644
--- a/sourcepawn/vm/sp_reader.c
+++ b/sourcepawn/vm/sp_vm_engine.cpp
@@ -1,7 +1,37 @@
 #include <malloc.h>
 #include <string.h>
-#include "sp_vm.h"
+#include "sp_file_headers.h"
+#include "sp_vm_types.h"
+#include "sp_vm_engine.h"
 #include "zlib/zlib.h"
+#include "sp_vm_basecontext.h"
+
+using namespace SourcePawn;
+
+void *SourcePawnEngine::BaseAlloc(size_t size)
+{
+	return malloc(size);
+}
+
+void SourcePawnEngine::BaseFree(void *memory)
+{
+	free(memory);
+}
+
+IPluginContext *SourcePawnEngine::CreateBaseContext(sp_context_t *ctx)
+{
+	return new BaseContext(ctx);
+}
+
+void SourcePawnEngine::FreeBaseContext(IPluginContext *ctx)
+{
+	sp_context_t *_ctx = ctx->GetContext();
+	IVirtualMachine *vm = ctx->GetVirtualMachine();
+	
+	vm->FreeContextVars(_ctx);
+
+	delete ctx;
+}
 
 sp_plugin_t *_ReadPlugin(sp_file_hdr_t *hdr, uint8_t *base, sp_plugin_t *plugin, int *err)
 {
@@ -15,7 +45,7 @@ sp_plugin_t *_ReadPlugin(sp_file_hdr_t *hdr, uint8_t *base, sp_plugin_t *plugin,
 
 	while (sectnum < hdr->sections)
 	{
-		nameptr = base + hdr->stringtab + secptr->nameoffs;
+		nameptr = (char *)(base + hdr->stringtab + secptr->nameoffs);
 
 		if (!(plugin->pcode) && !strcmp(nameptr, ".code"))
 		{
@@ -48,7 +78,7 @@ sp_plugin_t *_ReadPlugin(sp_file_hdr_t *hdr, uint8_t *base, sp_plugin_t *plugin,
 		}
 		else if (!(plugin->info.stringbase) && !strcmp(nameptr, ".names"))
 		{
-			plugin->info.stringbase = base + secptr->dataoffs;
+			plugin->info.stringbase = (const char *)(base + secptr->dataoffs);
 		}
 		else if (!(plugin->debug.files) && !strcmp(nameptr, ".dbg.files"))
 		{
@@ -71,7 +101,7 @@ sp_plugin_t *_ReadPlugin(sp_file_hdr_t *hdr, uint8_t *base, sp_plugin_t *plugin,
 		}
 		else if (!(plugin->debug.stringbase) && !strcmp(nameptr, ".dbg.strings"))
 		{
-			plugin->debug.stringbase = base + secptr->dataoffs;
+			plugin->debug.stringbase = (const char *)(base + secptr->dataoffs);
 		}
 
 		secptr++;
@@ -104,7 +134,7 @@ return_error:
 	return NULL;
 }
 
-sp_plugin_t *SP_LoadFromFilePointer(FILE *fp, int *err)
+sp_plugin_t *SourcePawnEngine::LoadFromFilePointer(FILE *fp, int *err)
 {
 	sp_file_hdr_t hdr;
 	sp_plugin_t *plugin;
@@ -184,6 +214,8 @@ sp_plugin_t *SP_LoadFromFilePointer(FILE *fp, int *err)
 		return NULL;
 	}
 
+	plugin->allocflags = 0;
+
 	return plugin;
 
 return_error:
@@ -194,7 +226,7 @@ return_error:
 	return NULL;
 }
 
-sp_plugin_t *SP_LoadFromMemory(void *base, sp_plugin_t *plugin, int *err)
+sp_plugin_t *SourcePawnEngine::LoadFromMemory(void *base, sp_plugin_t *plugin, int *err)
 {
 	sp_file_hdr_t hdr;
 	uint8_t noptr = 0;
@@ -207,7 +239,7 @@ sp_plugin_t *SP_LoadFromMemory(void *base, sp_plugin_t *plugin, int *err)
 		noptr = 1;
 	}
 
-	if (!_ReadPlugin(&hdr, base, plugin, err))
+	if (!_ReadPlugin(&hdr, (uint8_t *)base, plugin, err))
 	{
 		if (noptr)
 		{
@@ -216,5 +248,26 @@ sp_plugin_t *SP_LoadFromMemory(void *base, sp_plugin_t *plugin, int *err)
 		return NULL;
 	}
 
+	if (!noptr)
+	{
+		plugin->allocflags |= SP_FA_SELF_EXTERNAL;
+	}
+	plugin->allocflags |= SP_FA_BASE_EXTERNAL;
+
 	return plugin;
 }
+
+int SourcePawnEngine::FreeFromMemory(sp_plugin_t *plugin)
+{
+	if (!(plugin->allocflags & SP_FA_BASE_EXTERNAL))
+	{
+		free(plugin->base);
+		plugin->base = NULL;
+	}
+	if (!(plugin->allocflags & SP_FA_SELF_EXTERNAL))
+	{
+		free(plugin);
+	}
+
+	return SP_ERR_NONE;
+}
diff --git a/sourcepawn/vm/sp_vm_engine.h b/sourcepawn/vm/sp_vm_engine.h
new file mode 100644
index 00000000..13b18557
--- /dev/null
+++ b/sourcepawn/vm/sp_vm_engine.h
@@ -0,0 +1,73 @@
+#ifndef _INCLUDE_SOURCEPAWN_VM_ENGINE_H_
+#define _INCLUDE_SOURCEPAWN_VM_ENGINE_H_
+
+#include "sp_vm_api.h"
+
+namespace SourcePawn
+{
+	class SourcePawnEngine : public ISourcePawnEngine
+	{
+	public:
+		/**
+		 * Loads a named file from a file pointer.  
+		 * Using this means base memory will be allocated by the VM.
+		 * Note: The file handle position may be undefined on entry, and is
+		 *  always undefined on conclusion.
+		 * 
+		 * @param fp			File pointer.  May be at any offset.  Not closed on return.
+		 * @param err		Optional error code pointer.
+		 * @return			A new plugin structure.
+		 */	
+		sp_plugin_t *LoadFromFilePointer(FILE *fp, int *err);
+
+		/**
+		 * Loads a file from a base memory address.
+		 *	
+		 * @param base		Base address of the plugin's memory region.
+		 * @param plugin	If NULL, a new plugin pointer is returned.
+		 *                  Otherwise, the passed pointer is used.
+		 * @param err		Optional error code pointer.
+		 * @return			The resulting plugin pointer.
+		 */
+		sp_plugin_t *LoadFromMemory(void *base, sp_plugin_t *plugin, int *err);
+
+		/**
+		 * Frees all of the memory associated with a plugin file.
+		 * If allocated using SP_LoadFromMemory, the base and plugin pointer 
+		 *  itself are not freed (so this may end up doing nothing).
+		 */
+		int FreeFromMemory(sp_plugin_t *plugin);
+
+		/**
+		 * Creates a new IContext from a context handle.
+		 *
+		 * @param ctx		Context to use as a basis for the IPluginContext.
+		 * @return			New IPluginContext handle.
+		 */
+		IPluginContext *CreateBaseContext(sp_context_t *ctx);
+
+		/** 
+		 * Frees a context.
+		 *
+		 * @param ctx		Context pointer to free.
+		 */
+		void FreeBaseContext(IPluginContext *ctx);
+
+		/**
+		 * Allocates memory.
+		 * 
+		 * @param size		Size of memory to allocate.
+		 * @return			Pointer to memory, NULL if allocation failed.
+		 */
+		void *BaseAlloc(size_t size);
+
+		/**
+		 * Frees memory allocated with BaseAlloc.
+		 *
+		 * @param mem		Memory address to free.
+		 */
+		void BaseFree(void *memory);
+	};
+};
+
+#endif //_INCLUDE_SOURCEPAWN_VM_ENGINE_H_