sourcepawn/jit/sp_vm_basecontext.cpp
changeset 2193 db7c6362f3f2
child 2214 2b31563dec08
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/sourcepawn/jit/sp_vm_basecontext.cpp	Fri Jul 11 08:18:43 2008 +0000
     1.3 @@ -0,0 +1,810 @@
     1.4 +/**
     1.5 + * vim: set ts=4 :
     1.6 + * =============================================================================
     1.7 + * SourcePawn
     1.8 + * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
     1.9 + * =============================================================================
    1.10 + *
    1.11 + * This program is free software; you can redistribute it and/or modify it under
    1.12 + * the terms of the GNU General Public License, version 3.0, as published by the
    1.13 + * Free Software Foundation.
    1.14 + * 
    1.15 + * This program is distributed in the hope that it will be useful, but WITHOUT
    1.16 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    1.17 + * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
    1.18 + * details.
    1.19 + *
    1.20 + * You should have received a copy of the GNU General Public License along with
    1.21 + * this program.  If not, see <http://www.gnu.org/licenses/>.
    1.22 + *
    1.23 + * As a special exception, AlliedModders LLC gives you permission to link the
    1.24 + * code of this program (as well as its derivative works) to "Half-Life 2," the
    1.25 + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
    1.26 + * by the Valve Corporation.  You must obey the GNU General Public License in
    1.27 + * all respects for all other code used.  Additionally, AlliedModders LLC grants
    1.28 + * this exception to all derivative works.  AlliedModders LLC defines further
    1.29 + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
    1.30 + * or <http://www.sourcemod.net/license.php>.
    1.31 + *
    1.32 + * Version: $Id$
    1.33 + */
    1.34 +
    1.35 +#include <string.h>
    1.36 +#include <stdarg.h>
    1.37 +#include <assert.h>
    1.38 +#include <limits.h>
    1.39 +#include "sp_vm_api.h"
    1.40 +#include "sp_vm_basecontext.h"
    1.41 +#include "sp_vm_engine.h"
    1.42 +#include "x86/jit_x86.h"
    1.43 +
    1.44 +using namespace SourcePawn;
    1.45 +
    1.46 +#define CELLBOUNDMAX	(INT_MAX/sizeof(cell_t))
    1.47 +#define STACKMARGIN		((cell_t)(16*sizeof(cell_t)))
    1.48 +
    1.49 +BaseContext::BaseContext(BaseRuntime *pRuntime)
    1.50 +{
    1.51 +	m_pRuntime = pRuntime;
    1.52 +	m_pPlugin = m_pRuntime->m_pPlugin;
    1.53 +
    1.54 +	m_InExec = false;
    1.55 +	m_CustomMsg = false;
    1.56 +
    1.57 +	m_pNullVec = NULL;
    1.58 +	m_pNullString = NULL;
    1.59 +}
    1.60 +
    1.61 +BaseContext::~BaseContext()
    1.62 +{
    1.63 +}
    1.64 +
    1.65 +IVirtualMachine *BaseContext::GetVirtualMachine()
    1.66 +{
    1.67 +	return NULL;
    1.68 +}
    1.69 +
    1.70 +sp_context_t *BaseContext::GetContext()
    1.71 +{
    1.72 +	return reinterpret_cast<sp_context_t *>((IPluginContext * )this);
    1.73 +}
    1.74 +
    1.75 +sp_context_t *BaseContext::GetCtx()
    1.76 +{
    1.77 +	return &m_ctx;
    1.78 +}
    1.79 +
    1.80 +bool BaseContext::IsDebugging()
    1.81 +{
    1.82 +	return m_pRuntime->IsDebugging();
    1.83 +}
    1.84 +
    1.85 +int BaseContext::SetDebugBreak(void *newpfn, void *oldpfn)
    1.86 +{
    1.87 +	return SP_ERROR_ABORTED;
    1.88 +}
    1.89 +
    1.90 +IPluginDebugInfo *BaseContext::GetDebugInfo()
    1.91 +{
    1.92 +	return NULL;
    1.93 +}
    1.94 +
    1.95 +int BaseContext::Execute(uint32_t code_addr, cell_t *result)
    1.96 +{
    1.97 +	return SP_ERROR_ABORTED;
    1.98 +}
    1.99 +
   1.100 +void BaseContext::SetErrorMessage(const char *msg, va_list ap)
   1.101 +{
   1.102 +	m_CustomMsg = true;
   1.103 +
   1.104 +	vsnprintf(m_MsgCache, sizeof(m_MsgCache), msg, ap);
   1.105 +}
   1.106 +
   1.107 +void BaseContext::_SetErrorMessage(const char *msg, ...)
   1.108 +{
   1.109 +	va_list ap;
   1.110 +	va_start(ap, msg);
   1.111 +	SetErrorMessage(msg, ap);
   1.112 +	va_end(ap);
   1.113 +}
   1.114 +
   1.115 +cell_t BaseContext::ThrowNativeErrorEx(int error, const char *msg, ...)
   1.116 +{
   1.117 +	if (!m_InExec)
   1.118 +	{
   1.119 +		return 0;
   1.120 +	}
   1.121 +
   1.122 +	m_ctx.n_err = error;
   1.123 +	
   1.124 +	if (msg)
   1.125 +	{
   1.126 +		va_list ap;
   1.127 +		va_start(ap, msg);
   1.128 +		SetErrorMessage(msg, ap);
   1.129 +		va_end(ap);
   1.130 +	}
   1.131 +
   1.132 +	return 0;
   1.133 +}
   1.134 +
   1.135 +cell_t BaseContext::ThrowNativeError(const char *msg, ...)
   1.136 +{
   1.137 +	if (!m_InExec)
   1.138 +	{
   1.139 +		return 0;
   1.140 +	}
   1.141 +
   1.142 +	m_ctx.n_err = SP_ERROR_NATIVE;
   1.143 +
   1.144 +	if (msg)
   1.145 +	{
   1.146 +		va_list ap;
   1.147 +		va_start(ap, msg);
   1.148 +		SetErrorMessage(msg, ap);
   1.149 +		va_end(ap);
   1.150 +	}
   1.151 +
   1.152 +	return 0;
   1.153 +}
   1.154 +
   1.155 +int BaseContext::HeapAlloc(unsigned int cells, cell_t *local_addr, cell_t **phys_addr)
   1.156 +{
   1.157 +	cell_t *addr;
   1.158 +	ucell_t realmem;
   1.159 +
   1.160 +#if 0
   1.161 +	if (cells > CELLBOUNDMAX)
   1.162 +	{
   1.163 +		return SP_ERROR_ARAM;
   1.164 +	}
   1.165 +#else
   1.166 +	assert(cells < CELLBOUNDMAX);
   1.167 +#endif
   1.168 +
   1.169 +	realmem = cells * sizeof(cell_t);
   1.170 +
   1.171 +	/**
   1.172 +	 * Check if the space between the heap and stack is sufficient.
   1.173 +	 */
   1.174 +	if ((cell_t)(m_ctx.sp - m_ctx.hp - realmem) < STACKMARGIN)
   1.175 +	{
   1.176 +		return SP_ERROR_HEAPLOW;
   1.177 +	}
   1.178 +
   1.179 +	addr = (cell_t *)(m_pPlugin->memory + m_ctx.hp);
   1.180 +	/* store size of allocation in cells */
   1.181 +	*addr = (cell_t)cells;
   1.182 +	addr++;
   1.183 +	m_ctx.hp += sizeof(cell_t);
   1.184 +
   1.185 +	*local_addr = m_ctx.hp;
   1.186 +
   1.187 +	if (phys_addr)
   1.188 +	{
   1.189 +		*phys_addr = addr;
   1.190 +	}
   1.191 +
   1.192 +	m_ctx.hp += realmem;
   1.193 +
   1.194 +	return SP_ERROR_NONE;
   1.195 +}
   1.196 +
   1.197 +int BaseContext::HeapPop(cell_t local_addr)
   1.198 +{
   1.199 +	cell_t cellcount;
   1.200 +	cell_t *addr;
   1.201 +
   1.202 +	/* check the bounds of this address */
   1.203 +	local_addr -= sizeof(cell_t);
   1.204 +	if (local_addr < (cell_t)m_pPlugin->data_size || local_addr >= m_ctx.sp)
   1.205 +	{
   1.206 +		return SP_ERROR_INVALID_ADDRESS;
   1.207 +	}
   1.208 +
   1.209 +	addr = (cell_t *)(m_pPlugin->memory + local_addr);
   1.210 +	cellcount = (*addr) * sizeof(cell_t);
   1.211 +	/* check if this memory count looks valid */
   1.212 +	if ((signed)(m_ctx.hp - cellcount - sizeof(cell_t)) != local_addr)
   1.213 +	{
   1.214 +		return SP_ERROR_INVALID_ADDRESS;
   1.215 +	}
   1.216 +
   1.217 +	m_ctx.hp = local_addr;
   1.218 +
   1.219 +	return SP_ERROR_NONE;
   1.220 +}
   1.221 +
   1.222 +
   1.223 +int BaseContext::HeapRelease(cell_t local_addr)
   1.224 +{
   1.225 +	if (local_addr < (cell_t)m_pPlugin->data_size)
   1.226 +	{
   1.227 +		return SP_ERROR_INVALID_ADDRESS;
   1.228 +	}
   1.229 +
   1.230 +	m_ctx.hp = local_addr - sizeof(cell_t);
   1.231 +
   1.232 +	return SP_ERROR_NONE;
   1.233 +}
   1.234 +
   1.235 +int BaseContext::FindNativeByName(const char *name, uint32_t *index)
   1.236 +{
   1.237 +	return m_pRuntime->FindNativeByName(name, index);
   1.238 +}
   1.239 +
   1.240 +int BaseContext::GetNativeByIndex(uint32_t index, sp_native_t **native)
   1.241 +{
   1.242 +	return m_pRuntime->GetNativeByIndex(index, native);
   1.243 +}
   1.244 +
   1.245 +
   1.246 +uint32_t BaseContext::GetNativesNum()
   1.247 +{
   1.248 +	return m_pRuntime->GetNativesNum();
   1.249 +}
   1.250 +
   1.251 +int BaseContext::FindPublicByName(const char *name, uint32_t *index)
   1.252 +{
   1.253 +	return m_pRuntime->FindPublicByName(name, index);
   1.254 +}
   1.255 +
   1.256 +int BaseContext::GetPublicByIndex(uint32_t index, sp_public_t **pblic)
   1.257 +{
   1.258 +	return m_pRuntime->GetPublicByIndex(index, pblic);
   1.259 +}
   1.260 +
   1.261 +uint32_t BaseContext::GetPublicsNum()
   1.262 +{
   1.263 +	return m_pRuntime->GetPublicsNum();
   1.264 +}
   1.265 +
   1.266 +int BaseContext::GetPubvarByIndex(uint32_t index, sp_pubvar_t **pubvar)
   1.267 +{
   1.268 +	return m_pRuntime->GetPubvarByIndex(index, pubvar);
   1.269 +}
   1.270 +
   1.271 +int BaseContext::FindPubvarByName(const char *name, uint32_t *index)
   1.272 +{
   1.273 +	return m_pRuntime->FindPubvarByName(name, index);
   1.274 +}
   1.275 +
   1.276 +int BaseContext::GetPubvarAddrs(uint32_t index, cell_t *local_addr, cell_t **phys_addr)
   1.277 +{
   1.278 +	return m_pRuntime->GetPubvarAddrs(index, local_addr, phys_addr);
   1.279 +}
   1.280 +
   1.281 +uint32_t BaseContext::GetPubVarsNum()
   1.282 +{
   1.283 +	return m_pRuntime->GetPubVarsNum();
   1.284 +}
   1.285 +
   1.286 +int BaseContext::BindNatives(const sp_nativeinfo_t *natives, unsigned int num, int overwrite)
   1.287 +{
   1.288 +	return SP_ERROR_ABORTED;
   1.289 +}
   1.290 +
   1.291 +int BaseContext::BindNative(const sp_nativeinfo_t *native)
   1.292 +{
   1.293 +	return SP_ERROR_ABORTED;
   1.294 +}
   1.295 +
   1.296 +int BaseContext::BindNativeToIndex(uint32_t index, SPVM_NATIVE_FUNC func)
   1.297 +{
   1.298 +	return SP_ERROR_ABORTED;
   1.299 +}
   1.300 +
   1.301 +int BaseContext::BindNativeToAny(SPVM_NATIVE_FUNC native)
   1.302 +{
   1.303 +	return SP_ERROR_ABORTED;
   1.304 +}
   1.305 +
   1.306 +int BaseContext::LocalToPhysAddr(cell_t local_addr, cell_t **phys_addr)
   1.307 +{
   1.308 +	if (((local_addr >= m_ctx.hp) && (local_addr < m_ctx.sp)) 
   1.309 +		|| (local_addr < 0) || ((ucell_t)local_addr >= m_pPlugin->mem_size))
   1.310 +	{
   1.311 +		return SP_ERROR_INVALID_ADDRESS;
   1.312 +	}
   1.313 +
   1.314 +	if (phys_addr)
   1.315 +	{
   1.316 +		*phys_addr = (cell_t *)(m_pPlugin->memory + local_addr);
   1.317 +	}
   1.318 +
   1.319 +	return SP_ERROR_NONE;
   1.320 +}
   1.321 +
   1.322 +int BaseContext::PushCell(cell_t value)
   1.323 +{
   1.324 +	return SP_ERROR_ABORTED;
   1.325 +}
   1.326 +
   1.327 +int BaseContext::PushCellsFromArray(cell_t array[], unsigned int numcells)
   1.328 +{
   1.329 +	return SP_ERROR_ABORTED;
   1.330 +}
   1.331 +
   1.332 +int BaseContext::PushCellArray(cell_t *local_addr, cell_t **phys_addr, cell_t array[], unsigned int numcells)
   1.333 +{
   1.334 +	return SP_ERROR_ABORTED;
   1.335 +}
   1.336 +
   1.337 +int BaseContext::LocalToString(cell_t local_addr, char **addr)
   1.338 +{
   1.339 +	if (((local_addr >= m_ctx.hp) && (local_addr < m_ctx.sp))
   1.340 +		|| (local_addr < 0) || ((ucell_t)local_addr >= m_pPlugin->mem_size))
   1.341 +	{
   1.342 +		return SP_ERROR_INVALID_ADDRESS;
   1.343 +	}
   1.344 +	*addr = (char *)(m_pPlugin->memory + local_addr);
   1.345 +
   1.346 +	return SP_ERROR_NONE;
   1.347 +}
   1.348 +
   1.349 +int BaseContext::PushString(cell_t *local_addr, char **phys_addr, const char *string)
   1.350 +{
   1.351 +	return SP_ERROR_ABORTED;
   1.352 +}
   1.353 +
   1.354 +int BaseContext::StringToLocal(cell_t local_addr, size_t bytes, const char *source)
   1.355 +{
   1.356 +	char *dest;
   1.357 +	size_t len;
   1.358 +
   1.359 +	if (((local_addr >= m_ctx.hp) && (local_addr < m_ctx.sp))
   1.360 +		|| (local_addr < 0) || ((ucell_t)local_addr >= m_pPlugin->mem_size))
   1.361 +	{
   1.362 +		return SP_ERROR_INVALID_ADDRESS;
   1.363 +	}
   1.364 +
   1.365 +	if (bytes == 0)
   1.366 +	{
   1.367 +		return SP_ERROR_NONE;
   1.368 +	}
   1.369 +
   1.370 +	len = strlen(source);
   1.371 +	dest = (char *)(m_pPlugin->memory + local_addr);
   1.372 +
   1.373 +	if (len >= bytes)
   1.374 +	{
   1.375 +		len = bytes - 1;
   1.376 +	}
   1.377 +
   1.378 +	memmove(dest, source, len);
   1.379 +	dest[len] = '\0';
   1.380 +
   1.381 +	return SP_ERROR_NONE;
   1.382 +}
   1.383 +
   1.384 +inline int __CheckValidChar(char *c)
   1.385 +{
   1.386 +	int count;
   1.387 +	int bytecount = 0;
   1.388 +
   1.389 +	for (count=1; (*c & 0xC0) == 0x80; count++)
   1.390 +	{
   1.391 +		c--;
   1.392 +	}
   1.393 +
   1.394 +	switch (*c & 0xF0)
   1.395 +	{
   1.396 +	case 0xC0:
   1.397 +	case 0xD0:
   1.398 +		{
   1.399 +			bytecount = 2;
   1.400 +			break;
   1.401 +		}
   1.402 +	case 0xE0:
   1.403 +		{
   1.404 +			bytecount = 3;
   1.405 +			break;
   1.406 +		}
   1.407 +	case 0xF0:
   1.408 +		{
   1.409 +			bytecount = 4;
   1.410 +			break;
   1.411 +		}
   1.412 +	}
   1.413 +
   1.414 +	if (bytecount != count)
   1.415 +	{
   1.416 +		return count;
   1.417 +	}
   1.418 +
   1.419 +	return 0;
   1.420 +}
   1.421 +
   1.422 +int BaseContext::StringToLocalUTF8(cell_t local_addr, size_t maxbytes, const char *source, size_t *wrtnbytes)
   1.423 +{
   1.424 +	char *dest;
   1.425 +	size_t len;
   1.426 +	bool needtocheck = false;
   1.427 +
   1.428 +	if (((local_addr >= m_ctx.hp) && (local_addr < m_ctx.sp))
   1.429 +		|| (local_addr < 0)
   1.430 +		|| ((ucell_t)local_addr >= m_pPlugin->mem_size))
   1.431 +	{
   1.432 +		return SP_ERROR_INVALID_ADDRESS;
   1.433 +	}
   1.434 +	
   1.435 +	if (maxbytes == 0)
   1.436 +	{
   1.437 +		return SP_ERROR_NONE;
   1.438 +	}
   1.439 +
   1.440 +	len = strlen(source);
   1.441 +	dest = (char *)(m_pPlugin->memory + local_addr);
   1.442 +
   1.443 +	if ((size_t)len >= maxbytes)
   1.444 +	{
   1.445 +		len = maxbytes - 1;
   1.446 +		needtocheck = true;
   1.447 +	}
   1.448 +
   1.449 +	memmove(dest, source, len);
   1.450 +	if ((dest[len-1] & 1<<7) && needtocheck)
   1.451 +	{
   1.452 +		len -= __CheckValidChar(dest+len-1);
   1.453 +	}
   1.454 +	dest[len] = '\0';
   1.455 +
   1.456 +	if (wrtnbytes)
   1.457 +	{
   1.458 +		*wrtnbytes = len;
   1.459 +	}
   1.460 +
   1.461 +	return SP_ERROR_NONE;
   1.462 +}
   1.463 +
   1.464 +IPluginFunction *BaseContext::GetFunctionById(funcid_t func_id)
   1.465 +{
   1.466 +	return m_pRuntime->GetFunctionById(func_id);
   1.467 +}
   1.468 +
   1.469 +IPluginFunction *BaseContext::GetFunctionByName(const char *public_name)
   1.470 +{
   1.471 +	return m_pRuntime->GetFunctionByName(public_name);
   1.472 +}
   1.473 +
   1.474 +int BaseContext::LocalToStringNULL(cell_t local_addr, char **addr)
   1.475 +{
   1.476 +	int err;
   1.477 +	if ((err = LocalToString(local_addr, addr)) != SP_ERROR_NONE)
   1.478 +	{
   1.479 +		return err;
   1.480 +	}
   1.481 +
   1.482 +	if ((cell_t *)*addr == m_pNullString)
   1.483 +	{
   1.484 +		*addr = NULL;
   1.485 +	}
   1.486 +
   1.487 +	return SP_ERROR_NONE;
   1.488 +}
   1.489 +
   1.490 +SourceMod::IdentityToken_t *BaseContext::GetIdentity()
   1.491 +{
   1.492 +	SourceMod::IdentityToken_t *tok;
   1.493 +
   1.494 +	if (GetKey(1, (void **)&tok))
   1.495 +	{
   1.496 +		return tok;
   1.497 +	}
   1.498 +
   1.499 +	return NULL;
   1.500 +}
   1.501 +
   1.502 +cell_t *BaseContext::GetNullRef(SP_NULL_TYPE type)
   1.503 +{
   1.504 +	if (type == SP_NULL_VECTOR)
   1.505 +	{
   1.506 +		return m_pNullVec;
   1.507 +	}
   1.508 +
   1.509 +	return NULL;
   1.510 +}
   1.511 +
   1.512 +bool BaseContext::IsInExec()
   1.513 +{
   1.514 +	return m_InExec;
   1.515 +}
   1.516 +
   1.517 +int BaseContext::Execute2(IPluginFunction *function, const cell_t *params, unsigned int num_params, cell_t *result)
   1.518 +{
   1.519 +	int ir;
   1.520 +	int serial;
   1.521 +	cell_t *sp;
   1.522 +	funcid_t fnid;
   1.523 +	sp_public_t *pubfunc;
   1.524 +	cell_t _ignore_result;
   1.525 +
   1.526 +	fnid = function->GetFunctionID();
   1.527 +
   1.528 +	if (fnid & 1)
   1.529 +	{
   1.530 +		unsigned int public_id;
   1.531 +		
   1.532 +		public_id = fnid >> 1;
   1.533 +
   1.534 +		if (m_pRuntime->GetPublicByIndex(public_id, &pubfunc) != SP_ERROR_NONE)
   1.535 +		{
   1.536 +			return SP_ERROR_NOT_FOUND;
   1.537 +		}
   1.538 +	}
   1.539 +	else
   1.540 +	{
   1.541 +		return SP_ERROR_INVALID_ADDRESS;
   1.542 +	}
   1.543 +
   1.544 +	if (m_pRuntime->IsPaused())
   1.545 +	{
   1.546 +		return SP_ERROR_NOT_RUNNABLE;
   1.547 +	}
   1.548 +
   1.549 +	if ((cell_t)(m_ctx.hp + 16*sizeof(cell_t)) > (cell_t)(m_ctx.sp - (sizeof(cell_t) * (num_params + 1))))
   1.550 +	{
   1.551 +		return SP_ERROR_STACKLOW;
   1.552 +	}
   1.553 +
   1.554 +	if (result == NULL)
   1.555 +	{
   1.556 +		result = &_ignore_result;
   1.557 +	}
   1.558 +
   1.559 +	/* We got this far.  It's time to start profiling. */
   1.560 +	
   1.561 +	if ((m_pPlugin->prof_flags & SP_PROF_CALLBACKS) == SP_PROF_CALLBACKS)
   1.562 +	{
   1.563 +		serial = m_pPlugin->profiler->OnCallbackBegin(this, pubfunc);
   1.564 +	}
   1.565 +
   1.566 +	/* Save our previous state. */
   1.567 +
   1.568 +	bool save_exec;
   1.569 +	uint32_t save_n_idx;
   1.570 +	cell_t save_sp, save_hp;
   1.571 +
   1.572 +	save_sp = m_ctx.sp;
   1.573 +	save_hp = m_ctx.hp;
   1.574 +	save_exec = m_InExec;
   1.575 +	save_n_idx = m_ctx.n_idx;
   1.576 +
   1.577 +	/* Push parameters */
   1.578 +
   1.579 +	m_ctx.sp -= sizeof(cell_t) * (num_params + 1);
   1.580 +	sp = (cell_t *)(m_pPlugin->memory + m_ctx.sp);
   1.581 +
   1.582 +	sp[0] = num_params;
   1.583 +	for (unsigned int i = 0; i < num_params; i++)
   1.584 +	{
   1.585 +		sp[i + 1] = params[i];
   1.586 +	}
   1.587 +
   1.588 +	/* Clear internal state */
   1.589 +	m_ctx.n_err = SP_ERROR_NONE;
   1.590 +	m_ctx.n_idx = 0;
   1.591 +	m_MsgCache[0] = '\0';
   1.592 +	m_CustomMsg = false;
   1.593 +	m_InExec = false;
   1.594 +
   1.595 +	/* Start the tracer */
   1.596 +
   1.597 +	g_engine1.PushTracer(this);
   1.598 +
   1.599 +	/* Execute the function */
   1.600 +
   1.601 +	ir = g_Jit1.ContextExecute(m_pPlugin, &m_ctx, pubfunc->code_offs, result);
   1.602 +
   1.603 +	/* Restore some states, stop tracing */
   1.604 +
   1.605 +	m_InExec = save_exec;
   1.606 +
   1.607 +	if (ir == SP_ERROR_NONE)
   1.608 +	{
   1.609 +		m_ctx.n_err = SP_ERROR_NONE;
   1.610 +		if (m_ctx.sp != save_sp)
   1.611 +		{
   1.612 +			ir = SP_ERROR_STACKLEAK;
   1.613 +			_SetErrorMessage("Stack leak detected: sp:%d should be %d!", 
   1.614 +				m_ctx.sp, 
   1.615 +				save_sp);
   1.616 +		}
   1.617 +		if (m_ctx.hp != save_hp)
   1.618 +		{
   1.619 +			ir = SP_ERROR_HEAPLEAK;
   1.620 +			_SetErrorMessage("Heap leak detected: hp:%d should be %d!", 
   1.621 +				m_ctx.hp, 
   1.622 +				save_hp);
   1.623 +		}
   1.624 +	}
   1.625 +
   1.626 +	m_ctx.sp = save_sp;
   1.627 +	m_ctx.hp = save_hp;
   1.628 +
   1.629 +	g_engine1.PopTracer(ir, m_CustomMsg ? m_MsgCache : NULL);
   1.630 +
   1.631 +	if ((m_pPlugin->prof_flags & SP_PROF_CALLBACKS) == SP_PROF_CALLBACKS)
   1.632 +	{
   1.633 +		m_pPlugin->profiler->OnCallbackEnd(serial);
   1.634 +	}
   1.635 +
   1.636 +	m_ctx.n_idx = save_n_idx;
   1.637 +	m_ctx.n_err = SP_ERROR_NONE;
   1.638 +	m_MsgCache[0] = '\0';
   1.639 +	m_CustomMsg = false;
   1.640 +
   1.641 +	return ir;
   1.642 +}
   1.643 +
   1.644 +IPluginRuntime *BaseContext::GetRuntime()
   1.645 +{
   1.646 +	return m_pRuntime;
   1.647 +}
   1.648 +
   1.649 +int BaseRuntime::ApplyCompilationOptions(ICompilation *co)
   1.650 +{
   1.651 +	int err;
   1.652 +
   1.653 +	/* The JIT does not destroy anything until it is guaranteed to succeed. */
   1.654 +	if (!g_Jit1.Compile(co, this, &err))
   1.655 +	{
   1.656 +		return err;
   1.657 +	}
   1.658 +
   1.659 +	RefreshFunctionCache();
   1.660 +
   1.661 +	m_pCtx->Refresh();
   1.662 +
   1.663 +	return SP_ERROR_NONE;
   1.664 +}
   1.665 +
   1.666 +DebugInfo::DebugInfo(sp_plugin_t *plugin) : m_pPlugin(plugin)
   1.667 +{
   1.668 +}
   1.669 +
   1.670 +#define USHR(x) ((unsigned int)(x)>>1)
   1.671 +
   1.672 +int DebugInfo::LookupFile(ucell_t addr, const char **filename)
   1.673 +{
   1.674 +	int high, low, mid;
   1.675 +
   1.676 +	high = m_pPlugin->debug.files_num;
   1.677 +	low = -1;
   1.678 +
   1.679 +	while (high - low > 1)
   1.680 +	{
   1.681 +		mid = USHR(low + high);
   1.682 +		if (m_pPlugin->files[mid].addr <= addr)
   1.683 +		{
   1.684 +			low = mid;
   1.685 +		} else {
   1.686 +			high = mid;
   1.687 +		}
   1.688 +	}
   1.689 +
   1.690 +	if (low == -1)
   1.691 +	{
   1.692 +		return SP_ERROR_NOT_FOUND;
   1.693 +	}
   1.694 +
   1.695 +	*filename = m_pPlugin->files[low].name;
   1.696 +
   1.697 +	return SP_ERROR_NONE;
   1.698 +}
   1.699 +
   1.700 +int DebugInfo::LookupFunction(ucell_t addr, const char **name)
   1.701 +{
   1.702 +	uint32_t iter, max = m_pPlugin->debug.syms_num;
   1.703 +
   1.704 +	for (iter=0; iter<max; iter++)
   1.705 +	{
   1.706 +		if ((m_pPlugin->symbols[iter].sym->ident == SP_SYM_FUNCTION) 
   1.707 +			&& (m_pPlugin->symbols[iter].codestart <= addr) 
   1.708 +			&& (m_pPlugin->symbols[iter].codeend > addr))
   1.709 +		{
   1.710 +			break;
   1.711 +		}
   1.712 +	}
   1.713 +
   1.714 +	if (iter >= max)
   1.715 +	{
   1.716 +		return SP_ERROR_NOT_FOUND;
   1.717 +	}
   1.718 +
   1.719 +	*name = m_pPlugin->symbols[iter].name;
   1.720 +
   1.721 +	return SP_ERROR_NONE;
   1.722 +}
   1.723 +
   1.724 +int DebugInfo::LookupLine(ucell_t addr, uint32_t *line)
   1.725 +{
   1.726 +	int high, low, mid;
   1.727 +
   1.728 +	high = m_pPlugin->debug.lines_num;
   1.729 +	low = -1;
   1.730 +
   1.731 +	while (high - low > 1)
   1.732 +	{
   1.733 +		mid = USHR(low + high);
   1.734 +		if (m_pPlugin->lines[mid].addr <= addr)
   1.735 +		{
   1.736 +			low = mid;
   1.737 +		} else {
   1.738 +			high = mid;
   1.739 +		}
   1.740 +	}
   1.741 +
   1.742 +	if (low == -1)
   1.743 +	{
   1.744 +		return SP_ERROR_NOT_FOUND;
   1.745 +	}
   1.746 +
   1.747 +	/* Since the CIP occurs BEFORE the line, we have to add one */
   1.748 +	*line = m_pPlugin->lines[low].line + 1;
   1.749 +
   1.750 +	return SP_ERROR_NONE;
   1.751 +}
   1.752 +
   1.753 +#undef USHR
   1.754 +
   1.755 +int BaseContext::GetLastNativeError()
   1.756 +{
   1.757 +	return m_ctx.n_err;
   1.758 +}
   1.759 +
   1.760 +cell_t *BaseContext::GetLocalParams()
   1.761 +{
   1.762 +	return (cell_t *)(m_pPlugin->memory + m_ctx.frm + (2 * sizeof(cell_t)));
   1.763 +}
   1.764 +
   1.765 +void BaseContext::SetKey(int k, void *value)
   1.766 +{
   1.767 +	if (k < 1 || k > 4)
   1.768 +	{
   1.769 +		return;
   1.770 +	}
   1.771 +
   1.772 +	m_keys[k - 1] = value;
   1.773 +	m_keys_set[k - 1] = true;
   1.774 +}
   1.775 +
   1.776 +bool BaseContext::GetKey(int k, void **value)
   1.777 +{
   1.778 +	if (k < 1 || k > 4 || m_keys_set[k - 1] == false)
   1.779 +	{
   1.780 +		return false;
   1.781 +	}
   1.782 +
   1.783 +	*value = m_keys[k - 1];
   1.784 +
   1.785 +	return true;
   1.786 +}
   1.787 +
   1.788 +void BaseContext::Refresh()
   1.789 +{
   1.790 +	/* Initialize the null references */
   1.791 +	uint32_t index;
   1.792 +	if (FindPubvarByName("NULL_VECTOR", &index) == SP_ERROR_NONE)
   1.793 +	{
   1.794 +		sp_pubvar_t *pubvar;
   1.795 +		GetPubvarByIndex(index, &pubvar);
   1.796 +		m_pNullVec = pubvar->offs;
   1.797 +	}
   1.798 +	else
   1.799 +	{
   1.800 +		m_pNullVec = NULL;
   1.801 +	}
   1.802 +
   1.803 +	if (FindPubvarByName("NULL_STRING", &index) == SP_ERROR_NONE)
   1.804 +	{
   1.805 +		sp_pubvar_t *pubvar;
   1.806 +		GetPubvarByIndex(index, &pubvar);
   1.807 +		m_pNullString = pubvar->offs;
   1.808 +	}
   1.809 +	else
   1.810 +	{
   1.811 +		m_pNullString = NULL;
   1.812 +	}
   1.813 +}