sourcepawn/jit/sp_vm_engine.cpp
author David Anderson <danderson@mozilla.com>
Thu Aug 08 09:41:24 2013 -0700 (2013-08-08)
changeset 3977 fca2b54741ca
parent 2473 2df0a0591913
child 3990 c7fb79059d7a
permissions -rw-r--r--
Refactor the JIT to use a newer, simpler macro assembler. (bug 5827, r=ann)
     1 /**
     2  * vim: set ts=4 :
     3  * =============================================================================
     4  * SourcePawn
     5  * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
     6  * =============================================================================
     7  *
     8  * This program is free software; you can redistribute it and/or modify it under
     9  * the terms of the GNU General Public License, version 3.0, as published by the
    10  * Free Software Foundation.
    11  * 
    12  * This program is distributed in the hope that it will be useful, but WITHOUT
    13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    14  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
    15  * details.
    16  *
    17  * You should have received a copy of the GNU General Public License along with
    18  * this program.  If not, see <http://www.gnu.org/licenses/>.
    19  *
    20  * As a special exception, AlliedModders LLC gives you permission to link the
    21  * code of this program (as well as its derivative works) to "Half-Life 2," the
    22  * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
    23  * by the Valve Corporation.  You must obey the GNU General Public License in
    24  * all respects for all other code used.  Additionally, AlliedModders LLC grants
    25  * this exception to all derivative works.  AlliedModders LLC defines further
    26  * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
    27  * or <http://www.sourcemod.net/license.php>.
    28  *
    29  * Version: $Id$
    30  */
    31 
    32 #include <stdlib.h>
    33 #include <string.h>
    34 #include <assert.h>
    35 #include "sp_vm_types.h"
    36 #include <KeCodeAllocator.h>
    37 #include "sp_file_headers.h"
    38 #include "sp_vm_engine.h"
    39 #include "zlib/zlib.h"
    40 #include "sp_vm_basecontext.h"
    41 #include "jit_x86.h"
    42 #if defined __GNUC__
    43 #include <unistd.h>
    44 #endif
    45 
    46 SourcePawnEngine g_engine1;
    47 
    48 #if defined WIN32
    49  #define WIN32_LEAN_AND_MEAN
    50  #include <windows.h>
    51 #elif defined __GNUC__
    52  #include <sys/mman.h>
    53 #endif
    54 
    55 #if defined __linux__
    56 #include <malloc.h>
    57 #endif
    58 
    59 using namespace SourcePawn;
    60 
    61 #define ERROR_MESSAGE_MAX		29
    62 static const char *g_ErrorMsgTable[] = 
    63 {
    64 	NULL,
    65 	"Unrecognizable file format",
    66 	"Decompressor was not found",
    67 	"Not enough space on the heap",
    68 	"Invalid parameter or parameter type",
    69 	"Invalid plugin address",
    70 	"Object or index not found",
    71 	"Invalid index or index not found",
    72 	"Not enough space on the stack",
    73 	"Debug section not found or debug not enabled",
    74 	"Invalid instruction",
    75 	"Invalid memory access",
    76 	"Stack went below stack boundary",
    77 	"Heap went below heap boundary",
    78 	"Divide by zero",
    79 	"Array index is out of bounds",
    80 	"Instruction contained invalid parameter",
    81 	"Stack memory leaked by native",
    82 	"Heap memory leaked by native",
    83 	"Dynamic array is too big",
    84 	"Tracker stack is out of bounds",
    85 	"Native is not bound",
    86 	"Maximum number of parameters reached",
    87 	"Native detected error",
    88 	"Plugin not runnable",
    89 	"Call was aborted",
    90 	"Plugin format is too old",
    91 	"Plugin format is too new",
    92     "Out of memory",
    93     "Integer overflow"
    94 };
    95 
    96 const char *SourcePawnEngine::GetErrorString(int error)
    97 {
    98 	if (error < 1 || error > ERROR_MESSAGE_MAX)
    99 	{
   100 		return NULL;
   101 	}
   102 
   103 	return g_ErrorMsgTable[error];
   104 }
   105 
   106 SourcePawnEngine::SourcePawnEngine()
   107 {
   108 	m_pDebugHook = NULL;
   109 }
   110 
   111 SourcePawnEngine::~SourcePawnEngine()
   112 {
   113 }
   114 
   115 void *SourcePawnEngine::ExecAlloc(size_t size)
   116 {
   117 #if defined WIN32
   118 	return VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
   119 #elif defined __GNUC__
   120 # if defined __APPLE__
   121 	void *base = valloc(size);
   122 # else
   123 	void *base = memalign(sysconf(_SC_PAGESIZE), size);
   124 # endif
   125 	if (mprotect(base, size, PROT_READ|PROT_WRITE|PROT_EXEC) != 0)
   126 	{
   127 		free(base);
   128 		return NULL;
   129 	}
   130 	return base;
   131 #endif
   132 }
   133 
   134 void *SourcePawnEngine::AllocatePageMemory(size_t size)
   135 {
   136 	return g_Jit.AllocCode(size);
   137 }
   138 
   139 void SourcePawnEngine::SetReadExecute(void *ptr)
   140 {
   141 	/* already re */
   142 }
   143 
   144 void SourcePawnEngine::SetReadWrite(void *ptr)
   145 {
   146 	/* already rw */
   147 }
   148 
   149 void SourcePawnEngine::FreePageMemory(void *ptr)
   150 {
   151 	g_Jit.FreeCode(ptr);
   152 }
   153 
   154 void SourcePawnEngine::ExecFree(void *address)
   155 {
   156 #if defined WIN32
   157 	VirtualFree(address, 0, MEM_RELEASE);
   158 #elif defined __GNUC__
   159 	free(address);
   160 #endif
   161 }
   162 
   163 void SourcePawnEngine::SetReadWriteExecute(void *ptr)
   164 {
   165 //:TODO:	g_ExeMemory.SetRWE(ptr);
   166 	SetReadExecute(ptr);
   167 }
   168 
   169 void *SourcePawnEngine::BaseAlloc(size_t size)
   170 {
   171 	return malloc(size);
   172 }
   173 
   174 void SourcePawnEngine::BaseFree(void *memory)
   175 {
   176 	free(memory);
   177 }
   178 
   179 sp_plugin_t *SourcePawnEngine::LoadFromFilePointer(FILE *fp, int *err)
   180 {
   181 	if (err != NULL)
   182 	{
   183 		*err = SP_ERROR_ABORTED;
   184 	}
   185 
   186 	return NULL;
   187 }
   188 
   189 sp_plugin_t *SourcePawnEngine::LoadFromMemory(void *base, sp_plugin_t *plugin, int *err)
   190 {
   191 	if (err != NULL)
   192 	{
   193 		*err = SP_ERROR_ABORTED;
   194 	}
   195 
   196 	return NULL;
   197 }
   198 
   199 int SourcePawnEngine::FreeFromMemory(sp_plugin_t *plugin)
   200 {
   201 	return SP_ERROR_ABORTED;
   202 }
   203 
   204 IDebugListener *SourcePawnEngine::SetDebugListener(IDebugListener *pListener)
   205 {
   206 	IDebugListener *old = m_pDebugHook;
   207 
   208 	m_pDebugHook = pListener;
   209 
   210 	return old;
   211 }
   212 
   213 unsigned int SourcePawnEngine::GetEngineAPIVersion()
   214 {
   215 	return SOURCEPAWN_ENGINE_API_VERSION;
   216 }
   217 
   218 unsigned int SourcePawnEngine::GetContextCallCount()
   219 {
   220 	return 0;
   221 }
   222 
   223 void SourcePawnEngine::ReportError(BaseRuntime *runtime, int err, const char *errstr, cell_t rp_start)
   224 {
   225 	if (m_pDebugHook == NULL)
   226 	{
   227 		return;
   228 	}
   229 
   230 	CContextTrace trace(runtime, err, errstr, rp_start);
   231 
   232 	m_pDebugHook->OnContextExecuteError(runtime->GetDefaultContext(), &trace);
   233 }
   234 
   235 CContextTrace::CContextTrace(BaseRuntime *pRuntime, int err, const char *errstr, cell_t start_rp) 
   236 : m_pRuntime(pRuntime), m_Error(err), m_pMsg(errstr), m_StartRp(start_rp), m_Level(0)
   237 {
   238 	m_ctx = pRuntime->m_pCtx->GetCtx();
   239 	m_pDebug = m_pRuntime->GetDebugInfo();
   240 }
   241 
   242 bool CContextTrace::DebugInfoAvailable()
   243 {
   244 	return (m_pDebug != NULL);
   245 }
   246 
   247 const char *CContextTrace::GetCustomErrorString()
   248 {
   249 	return m_pMsg;
   250 }
   251 
   252 int CContextTrace::GetErrorCode()
   253 {
   254 	return m_Error;
   255 }
   256 
   257 const char *CContextTrace::GetErrorString()
   258 {
   259 	if (m_Error > ERROR_MESSAGE_MAX || m_Error < 1)
   260 	{
   261 		return "Invalid error code";
   262 	}
   263 	else
   264 	{
   265 		return g_ErrorMsgTable[m_Error];
   266 	}
   267 }
   268 
   269 void CContextTrace::ResetTrace()
   270 {
   271 	m_Level = 0;
   272 }
   273 
   274 bool CContextTrace::GetTraceInfo(CallStackInfo *trace)
   275 {
   276 	cell_t cip;
   277 
   278 	if (m_Level == 0)
   279 	{
   280 		cip = m_ctx->err_cip;
   281 	}
   282 	else if (m_ctx->rp > 0)
   283 	{
   284 		/* Entries go from ctx.rp - 1 to m_StartRp */
   285 		cell_t offs, start, end;
   286 
   287 		offs = m_Level - 1;
   288 		start = m_ctx->rp - 1;
   289 		end = m_StartRp;
   290 
   291 		if (start - offs < end)
   292 		{
   293 			return false;
   294 		}
   295 
   296 		cip = m_ctx->rstk_cips[start - offs];
   297 	}
   298 	else
   299 	{
   300 		return false;
   301 	}
   302 
   303 	if (trace == NULL)
   304 	{
   305 		m_Level++;
   306 		return true;
   307 	}
   308 
   309 	if (m_pDebug->LookupFile(cip, &(trace->filename)) != SP_ERROR_NONE)
   310 	{
   311 		trace->filename = NULL;
   312 	}
   313 
   314 	if (m_pDebug->LookupFunction(cip, &(trace->function)) != SP_ERROR_NONE)
   315 	{
   316 		trace->function = NULL;
   317 	}
   318 
   319 	if (m_pDebug->LookupLine(cip, &(trace->line)) != SP_ERROR_NONE)
   320 	{
   321 		trace->line = 0;
   322 	}
   323 
   324 	m_Level++;
   325 
   326 	return true;
   327 }
   328 
   329 const char *CContextTrace::GetLastNative(uint32_t *index)
   330 {
   331 	if (m_ctx->n_err == SP_ERROR_NONE)
   332 	{
   333 		return NULL;
   334 	}
   335 
   336 	sp_native_t *native;
   337 	if (m_pRuntime->GetNativeByIndex(m_ctx->n_idx, &native) != SP_ERROR_NONE)
   338 	{
   339 		return NULL;
   340 	}
   341 
   342 	if (index)
   343 	{
   344 		*index = m_ctx->n_idx;
   345 	}
   346 
   347 	return native->name;
   348 }
   349 
   350 IDebugListener *SourcePawnEngine::GetDebugHook()
   351 {
   352 	return m_pDebugHook;
   353 }
   354