sourcepawn/jit/sp_vm_basecontext.cpp
author David Anderson <dvander@alliedmods.net>
Sun Jul 06 04:59:39 2008 +0000 (2008-07-06)
branchrefac-jit
changeset 2169 d1e225d141fb
parent 2168 core/vm/sp_vm_basecontext.cpp@c24a6fa957db
child 2171 0885b66fcf81
permissions -rw-r--r--
moved files around pre-emptively
dvander@2168
     1
/**
dvander@2168
     2
 * vim: set ts=4 :
dvander@2168
     3
 * =============================================================================
dvander@2168
     4
 * SourcePawn
dvander@2168
     5
 * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
dvander@2168
     6
 * =============================================================================
dvander@2168
     7
 *
dvander@2168
     8
 * This program is free software; you can redistribute it and/or modify it under
dvander@2168
     9
 * the terms of the GNU General Public License, version 3.0, as published by the
dvander@2168
    10
 * Free Software Foundation.
dvander@2168
    11
 * 
dvander@2168
    12
 * This program is distributed in the hope that it will be useful, but WITHOUT
dvander@2168
    13
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
dvander@2168
    14
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
dvander@2168
    15
 * details.
dvander@2168
    16
 *
dvander@2168
    17
 * You should have received a copy of the GNU General Public License along with
dvander@2168
    18
 * this program.  If not, see <http://www.gnu.org/licenses/>.
dvander@2168
    19
 *
dvander@2168
    20
 * As a special exception, AlliedModders LLC gives you permission to link the
dvander@2168
    21
 * code of this program (as well as its derivative works) to "Half-Life 2," the
dvander@2168
    22
 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
dvander@2168
    23
 * by the Valve Corporation.  You must obey the GNU General Public License in
dvander@2168
    24
 * all respects for all other code used.  Additionally, AlliedModders LLC grants
dvander@2168
    25
 * this exception to all derivative works.  AlliedModders LLC defines further
dvander@2168
    26
 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
dvander@2168
    27
 * or <http://www.sourcemod.net/license.php>.
dvander@2168
    28
 *
dvander@2168
    29
 * Version: $Id$
dvander@2168
    30
 */
dvander@2168
    31
dvander@2168
    32
#include <string.h>
dvander@2168
    33
#include <stdarg.h>
dvander@2168
    34
#include <assert.h>
dvander@2168
    35
#include <limits.h>
dvander@2168
    36
#include "sp_vm_api.h"
dvander@2168
    37
#include "sp_vm_basecontext.h"
dvander@2168
    38
#include "sp_vm_engine.h"
dvander@2168
    39
dvander@2168
    40
#ifdef SOURCEMOD_BUILD
dvander@2168
    41
#include "Logger.h"
dvander@2168
    42
#include "DebugReporter.h"
dvander@2168
    43
#endif
dvander@2168
    44
dvander@2168
    45
using namespace SourcePawn;
dvander@2168
    46
dvander@2168
    47
extern SourcePawnEngine g_SourcePawn;
dvander@2168
    48
dvander@2168
    49
#define CELLBOUNDMAX	(INT_MAX/sizeof(cell_t))
dvander@2168
    50
#define STACKMARGIN		((cell_t)(16*sizeof(cell_t)))
dvander@2168
    51
dvander@2168
    52
int GlobalDebugBreak(sp_context_t *ctx, uint32_t frm, uint32_t cip)
dvander@2168
    53
{
dvander@2168
    54
	g_SourcePawn.RunTracer(ctx, frm, cip);
dvander@2168
    55
dvander@2168
    56
	return SP_ERROR_NONE;
dvander@2168
    57
}
dvander@2168
    58
dvander@2168
    59
BaseContext::BaseContext(sp_context_t *_ctx)
dvander@2168
    60
{
dvander@2168
    61
	ctx = _ctx;
dvander@2168
    62
	ctx->context = this;
dvander@2168
    63
	ctx->dbreak = GlobalDebugBreak;
dvander@2168
    64
dvander@2168
    65
	if (ctx->prof_flags != 0)
dvander@2168
    66
	{
dvander@2168
    67
		ctx->profiler = sm_profiler;
dvander@2168
    68
	}
dvander@2168
    69
dvander@2168
    70
	m_InExec = false;
dvander@2168
    71
	m_CustomMsg = false;
dvander@2168
    72
	m_funcsnum = ctx->vmbase->FunctionCount(ctx);
dvander@2168
    73
#if 0
dvander@2168
    74
	m_priv_funcs = NULL;
dvander@2168
    75
#endif
dvander@2168
    76
	m_pub_funcs = NULL;
dvander@2168
    77
dvander@2168
    78
#if 0
dvander@2168
    79
	/**
dvander@2168
    80
	 * Note: Since the m_plugin member will never change,
dvander@2168
    81
	 * it is safe to assume the function count will never change
dvander@2168
    82
	 */
dvander@2168
    83
	if (m_funcsnum && m_priv_funcs == NULL)
dvander@2168
    84
	{
dvander@2168
    85
		m_priv_funcs = new CFunction *[m_funcsnum];
dvander@2168
    86
		memset(m_priv_funcs, 0, sizeof(CFunction *) * m_funcsnum);
dvander@2168
    87
	} else {
dvander@2168
    88
		m_priv_funcs = NULL;
dvander@2168
    89
	}
dvander@2168
    90
#endif
dvander@2168
    91
dvander@2168
    92
	if (ctx->plugin->info.publics_num && m_pub_funcs == NULL)
dvander@2168
    93
	{
dvander@2168
    94
		m_pub_funcs = new CFunction *[ctx->plugin->info.publics_num];
dvander@2168
    95
		memset(m_pub_funcs, 0, sizeof(CFunction *) * ctx->plugin->info.publics_num);
dvander@2168
    96
	} else {
dvander@2168
    97
		m_pub_funcs = NULL;
dvander@2168
    98
	}
dvander@2168
    99
dvander@2168
   100
	/* Initialize the null references */
dvander@2168
   101
	uint32_t index;
dvander@2168
   102
	if (FindPubvarByName("NULL_VECTOR", &index) == SP_ERROR_NONE)
dvander@2168
   103
	{
dvander@2168
   104
		sp_pubvar_t *pubvar;
dvander@2168
   105
		GetPubvarByIndex(index, &pubvar);
dvander@2168
   106
		m_pNullVec = pubvar->offs;
dvander@2168
   107
	} else {
dvander@2168
   108
		m_pNullVec = NULL;
dvander@2168
   109
	}
dvander@2168
   110
dvander@2168
   111
	if (FindPubvarByName("NULL_STRING", &index) == SP_ERROR_NONE)
dvander@2168
   112
	{
dvander@2168
   113
		sp_pubvar_t *pubvar;
dvander@2168
   114
		GetPubvarByIndex(index, &pubvar);
dvander@2168
   115
		m_pNullString = pubvar->offs;
dvander@2168
   116
	} else {
dvander@2168
   117
		m_pNullString = NULL;
dvander@2168
   118
	}
dvander@2168
   119
}
dvander@2168
   120
dvander@2168
   121
void BaseContext::FlushFunctionCache()
dvander@2168
   122
{
dvander@2168
   123
	if (m_pub_funcs)
dvander@2168
   124
	{
dvander@2168
   125
		for (uint32_t i=0; i<ctx->plugin->info.publics_num; i++)
dvander@2168
   126
		{
dvander@2168
   127
			delete m_pub_funcs[i];
dvander@2168
   128
			m_pub_funcs[i] = NULL;
dvander@2168
   129
		}
dvander@2168
   130
	}
dvander@2168
   131
dvander@2168
   132
#if 0
dvander@2168
   133
	if (m_priv_funcs)
dvander@2168
   134
	{
dvander@2168
   135
		for (unsigned int i=0; i<m_funcsnum; i++)
dvander@2168
   136
		{
dvander@2168
   137
			delete m_priv_funcs[i];
dvander@2168
   138
			m_priv_funcs[i] = NULL;
dvander@2168
   139
		}
dvander@2168
   140
	}
dvander@2168
   141
#endif
dvander@2168
   142
}
dvander@2168
   143
dvander@2168
   144
void BaseContext::RefreshFunctionCache()
dvander@2168
   145
{
dvander@2168
   146
	if (m_pub_funcs)
dvander@2168
   147
	{
dvander@2168
   148
		sp_public_t *pub;
dvander@2168
   149
		for (uint32_t i=0; i<ctx->plugin->info.publics_num; i++)
dvander@2168
   150
		{
dvander@2168
   151
			if (!m_pub_funcs[i])
dvander@2168
   152
			{
dvander@2168
   153
				continue;
dvander@2168
   154
			}
dvander@2168
   155
			if (GetPublicByIndex(i, &pub) != SP_ERROR_NONE)
dvander@2168
   156
			{
dvander@2168
   157
				continue;
dvander@2168
   158
			}
dvander@2168
   159
			m_pub_funcs[i]->Set(pub->code_offs, this, pub->funcid, i);
dvander@2168
   160
		}
dvander@2168
   161
	}
dvander@2168
   162
dvander@2168
   163
#if 0
dvander@2168
   164
	if (m_priv_funcs)
dvander@2168
   165
	{
dvander@2168
   166
		for (unsigned int i=0; i<m_funcsnum; i++)
dvander@2168
   167
		{
dvander@2168
   168
			if (!m_priv_funcs[i])
dvander@2168
   169
			{
dvander@2168
   170
				continue;
dvander@2168
   171
			}
dvander@2168
   172
			g_pVM->
dvander@2168
   173
		}
dvander@2168
   174
	}
dvander@2168
   175
#endif
dvander@2168
   176
}
dvander@2168
   177
dvander@2168
   178
BaseContext::~BaseContext()
dvander@2168
   179
{
dvander@2168
   180
	FlushFunctionCache();
dvander@2168
   181
	delete [] m_pub_funcs;
dvander@2168
   182
	m_pub_funcs = NULL;
dvander@2168
   183
#if 0
dvander@2168
   184
	delete [] m_priv_funcs;
dvander@2168
   185
	m_priv_funcs = NULL;
dvander@2168
   186
#endif
dvander@2168
   187
}
dvander@2168
   188
dvander@2168
   189
void BaseContext::SetContext(sp_context_t *_ctx)
dvander@2168
   190
{
dvander@2168
   191
	if (!_ctx)
dvander@2168
   192
	{
dvander@2168
   193
		return;
dvander@2168
   194
	}
dvander@2168
   195
dvander@2168
   196
	ctx = _ctx;
dvander@2168
   197
	ctx->context = this;
dvander@2168
   198
	ctx->dbreak = GlobalDebugBreak;
dvander@2168
   199
dvander@2168
   200
	if (ctx->prof_flags != 0)
dvander@2168
   201
	{
dvander@2168
   202
		ctx->profiler = sm_profiler;
dvander@2168
   203
	}
dvander@2168
   204
dvander@2168
   205
	RefreshFunctionCache();
dvander@2168
   206
}
dvander@2168
   207
dvander@2168
   208
IVirtualMachine *BaseContext::GetVirtualMachine()
dvander@2168
   209
{
dvander@2168
   210
	return (IVirtualMachine *)ctx->vmbase;
dvander@2168
   211
}
dvander@2168
   212
dvander@2168
   213
sp_context_t *BaseContext::GetContext()
dvander@2168
   214
{
dvander@2168
   215
	return ctx;
dvander@2168
   216
}
dvander@2168
   217
dvander@2168
   218
bool BaseContext::IsDebugging()
dvander@2168
   219
{
dvander@2168
   220
	return (ctx->flags & SPFLAG_PLUGIN_DEBUG);
dvander@2168
   221
}
dvander@2168
   222
dvander@2168
   223
int BaseContext::SetDebugBreak(SPVM_DEBUGBREAK newpfn, SPVM_DEBUGBREAK *oldpfn)
dvander@2168
   224
{
dvander@2168
   225
	if (!IsDebugging())
dvander@2168
   226
	{
dvander@2168
   227
		return SP_ERROR_NOTDEBUGGING;
dvander@2168
   228
	}
dvander@2168
   229
dvander@2168
   230
	*oldpfn = ctx->dbreak;
dvander@2168
   231
	ctx->dbreak = newpfn;
dvander@2168
   232
dvander@2168
   233
	return SP_ERROR_NONE;
dvander@2168
   234
}
dvander@2168
   235
dvander@2168
   236
IPluginDebugInfo *BaseContext::GetDebugInfo()
dvander@2168
   237
{
dvander@2168
   238
	if (!IsDebugging())
dvander@2168
   239
	{
dvander@2168
   240
		return NULL;
dvander@2168
   241
	}
dvander@2168
   242
	return this;
dvander@2168
   243
}
dvander@2168
   244
dvander@2168
   245
int BaseContext::Execute(uint32_t code_addr, cell_t *result)
dvander@2168
   246
{
dvander@2168
   247
	if ((ctx->flags & SPFLAG_PLUGIN_PAUSED) == SPFLAG_PLUGIN_PAUSED)
dvander@2168
   248
	{
dvander@2168
   249
		return SP_ERROR_NOT_RUNNABLE;
dvander@2168
   250
	}
dvander@2168
   251
dvander@2168
   252
	/* tada, prevent a crash */
dvander@2168
   253
	cell_t _ignore_result;
dvander@2168
   254
	if (!result)
dvander@2168
   255
	{
dvander@2168
   256
		result = &_ignore_result;
dvander@2168
   257
	}
dvander@2168
   258
dvander@2168
   259
	IVirtualMachine *vm = (IVirtualMachine *)ctx->vmbase;
dvander@2168
   260
dvander@2168
   261
	uint32_t pushcount = ctx->pushcount;
dvander@2168
   262
	int err;
dvander@2168
   263
dvander@2168
   264
	if ((err = PushCell(pushcount++)) != SP_ERROR_NONE)
dvander@2168
   265
	{
dvander@2168
   266
#if defined SOURCEMOD_BUILD
dvander@2168
   267
		g_DbgReporter.GenerateCodeError(this, code_addr, err, "Stack error; cannot complete execution!");
dvander@2168
   268
#endif
dvander@2168
   269
		return SP_ERROR_NOT_RUNNABLE;
dvander@2168
   270
	}
dvander@2168
   271
	ctx->pushcount = 0;
dvander@2168
   272
dvander@2168
   273
	cell_t save_sp = ctx->sp + (pushcount * sizeof(cell_t));
dvander@2168
   274
	cell_t save_hp = ctx->hp;
dvander@2168
   275
	uint32_t n_idx = ctx->n_idx;
dvander@2168
   276
dvander@2168
   277
	bool wasExec = m_InExec;
dvander@2168
   278
dvander@2168
   279
	/* Clear the error state, if any */
dvander@2168
   280
	ctx->n_err = SP_ERROR_NONE;
dvander@2168
   281
	ctx->n_idx = 0;
dvander@2168
   282
	m_InExec = true;
dvander@2168
   283
	m_MsgCache[0] = '\0';
dvander@2168
   284
	m_CustomMsg = false;
dvander@2168
   285
dvander@2168
   286
	g_SourcePawn.PushTracer(ctx);
dvander@2168
   287
dvander@2168
   288
	err = vm->ContextExecute(ctx, code_addr, result);
dvander@2168
   289
dvander@2168
   290
	m_InExec = wasExec;
dvander@2168
   291
dvander@2168
   292
	/**
dvander@2168
   293
	 * :TODO: Calling from a plugin in here will erase the cached message...
dvander@2168
   294
	 * Should that be documented?
dvander@2168
   295
	 */
dvander@2168
   296
	g_SourcePawn.PopTracer(err, m_CustomMsg ? m_MsgCache : NULL);
dvander@2168
   297
dvander@2168
   298
#if defined SOURCEMOD_BUILD
dvander@2168
   299
	if (err == SP_ERROR_NONE)
dvander@2168
   300
	{
dvander@2168
   301
		if (ctx->sp != save_sp)
dvander@2168
   302
		{
dvander@2168
   303
			g_DbgReporter.GenerateCodeError(this,
dvander@2168
   304
				code_addr,
dvander@2168
   305
				SP_ERROR_STACKLEAK,
dvander@2168
   306
				"Stack leak detected: sp:%d should be %d!",
dvander@2168
   307
				ctx->sp,
dvander@2168
   308
				save_sp);
dvander@2168
   309
		}
dvander@2168
   310
		if (ctx->hp != save_hp)
dvander@2168
   311
		{
dvander@2168
   312
			g_DbgReporter.GenerateCodeError(this,
dvander@2168
   313
				code_addr,
dvander@2168
   314
				SP_ERROR_HEAPLEAK,
dvander@2168
   315
				"Heap leak detected: sp:%d should be %d!",
dvander@2168
   316
				ctx->hp,
dvander@2168
   317
				save_hp);
dvander@2168
   318
		}
dvander@2168
   319
	}
dvander@2168
   320
#endif
dvander@2168
   321
dvander@2168
   322
	if (err != SP_ERROR_NONE)
dvander@2168
   323
	{
dvander@2168
   324
		ctx->sp = save_sp;
dvander@2168
   325
		ctx->hp = save_hp;
dvander@2168
   326
	}
dvander@2168
   327
dvander@2168
   328
	ctx->n_idx = n_idx;
dvander@2168
   329
	ctx->n_err = SP_ERROR_NONE;
dvander@2168
   330
	m_MsgCache[0] = '\0';
dvander@2168
   331
	m_CustomMsg = false;
dvander@2168
   332
dvander@2168
   333
	return err;
dvander@2168
   334
}
dvander@2168
   335
dvander@2168
   336
void BaseContext::SetErrorMessage(const char *msg, va_list ap)
dvander@2168
   337
{
dvander@2168
   338
	m_CustomMsg = true;
dvander@2168
   339
dvander@2168
   340
	vsnprintf(m_MsgCache, sizeof(m_MsgCache), msg, ap);
dvander@2168
   341
}
dvander@2168
   342
dvander@2168
   343
cell_t BaseContext::ThrowNativeErrorEx(int error, const char *msg, ...)
dvander@2168
   344
{
dvander@2168
   345
	if (!m_InExec)
dvander@2168
   346
	{
dvander@2168
   347
		return 0;
dvander@2168
   348
	}
dvander@2168
   349
dvander@2168
   350
	ctx->n_err = error;
dvander@2168
   351
	
dvander@2168
   352
	if (msg)
dvander@2168
   353
	{
dvander@2168
   354
		va_list ap;
dvander@2168
   355
		va_start(ap, msg);
dvander@2168
   356
		SetErrorMessage(msg, ap);
dvander@2168
   357
		va_end(ap);
dvander@2168
   358
	}
dvander@2168
   359
dvander@2168
   360
	return 0;
dvander@2168
   361
}
dvander@2168
   362
dvander@2168
   363
cell_t BaseContext::ThrowNativeError(const char *msg, ...)
dvander@2168
   364
{
dvander@2168
   365
	if (!m_InExec)
dvander@2168
   366
	{
dvander@2168
   367
		return 0;
dvander@2168
   368
	}
dvander@2168
   369
dvander@2168
   370
	ctx->n_err = SP_ERROR_NATIVE;
dvander@2168
   371
dvander@2168
   372
	if (msg)
dvander@2168
   373
	{
dvander@2168
   374
		va_list ap;
dvander@2168
   375
		va_start(ap, msg);
dvander@2168
   376
		SetErrorMessage(msg, ap);
dvander@2168
   377
		va_end(ap);
dvander@2168
   378
	}
dvander@2168
   379
dvander@2168
   380
	return 0;
dvander@2168
   381
}
dvander@2168
   382
dvander@2168
   383
int BaseContext::HeapAlloc(unsigned int cells, cell_t *local_addr, cell_t **phys_addr)
dvander@2168
   384
{
dvander@2168
   385
	cell_t *addr;
dvander@2168
   386
	ucell_t realmem;
dvander@2168
   387
dvander@2168
   388
#if 0
dvander@2168
   389
	if (cells > CELLBOUNDMAX)
dvander@2168
   390
	{
dvander@2168
   391
		return SP_ERROR_ARAM;
dvander@2168
   392
	}
dvander@2168
   393
#else
dvander@2168
   394
	assert(cells < CELLBOUNDMAX);
dvander@2168
   395
#endif
dvander@2168
   396
dvander@2168
   397
	realmem = cells * sizeof(cell_t);
dvander@2168
   398
dvander@2168
   399
	/**
dvander@2168
   400
	 * Check if the space between the heap and stack is sufficient.
dvander@2168
   401
	 */
dvander@2168
   402
	if ((cell_t)(ctx->sp - ctx->hp - realmem) < STACKMARGIN)
dvander@2168
   403
	{
dvander@2168
   404
		return SP_ERROR_HEAPLOW;
dvander@2168
   405
	}
dvander@2168
   406
dvander@2168
   407
	addr = (cell_t *)(ctx->memory + ctx->hp);
dvander@2168
   408
	/* store size of allocation in cells */
dvander@2168
   409
	*addr = (cell_t)cells;
dvander@2168
   410
	addr++;
dvander@2168
   411
	ctx->hp += sizeof(cell_t);
dvander@2168
   412
dvander@2168
   413
	*local_addr = ctx->hp;
dvander@2168
   414
dvander@2168
   415
	if (phys_addr)
dvander@2168
   416
	{
dvander@2168
   417
		*phys_addr = addr;
dvander@2168
   418
	}
dvander@2168
   419
dvander@2168
   420
	ctx->hp += realmem;
dvander@2168
   421
dvander@2168
   422
	return SP_ERROR_NONE;
dvander@2168
   423
}
dvander@2168
   424
dvander@2168
   425
int BaseContext::HeapPop(cell_t local_addr)
dvander@2168
   426
{
dvander@2168
   427
	cell_t cellcount;
dvander@2168
   428
	cell_t *addr;
dvander@2168
   429
dvander@2168
   430
	/* check the bounds of this address */
dvander@2168
   431
	local_addr -= sizeof(cell_t);
dvander@2168
   432
	if (local_addr < ctx->heap_base || local_addr >= ctx->sp)
dvander@2168
   433
	{
dvander@2168
   434
		return SP_ERROR_INVALID_ADDRESS;
dvander@2168
   435
	}
dvander@2168
   436
dvander@2168
   437
	addr = (cell_t *)(ctx->memory + local_addr);
dvander@2168
   438
	cellcount = (*addr) * sizeof(cell_t);
dvander@2168
   439
	/* check if this memory count looks valid */
dvander@2168
   440
	if ((signed)(ctx->hp - cellcount - sizeof(cell_t)) != local_addr)
dvander@2168
   441
	{
dvander@2168
   442
		return SP_ERROR_INVALID_ADDRESS;
dvander@2168
   443
	}
dvander@2168
   444
dvander@2168
   445
	ctx->hp = local_addr;
dvander@2168
   446
dvander@2168
   447
	return SP_ERROR_NONE;
dvander@2168
   448
}
dvander@2168
   449
dvander@2168
   450
dvander@2168
   451
int BaseContext::HeapRelease(cell_t local_addr)
dvander@2168
   452
{
dvander@2168
   453
	if (local_addr < ctx->heap_base)
dvander@2168
   454
	{
dvander@2168
   455
		return SP_ERROR_INVALID_ADDRESS;
dvander@2168
   456
	}
dvander@2168
   457
dvander@2168
   458
	ctx->hp = local_addr - sizeof(cell_t);
dvander@2168
   459
dvander@2168
   460
	return SP_ERROR_NONE;
dvander@2168
   461
}
dvander@2168
   462
dvander@2168
   463
int BaseContext::FindNativeByName(const char *name, uint32_t *index)
dvander@2168
   464
{
dvander@2168
   465
	int high;
dvander@2168
   466
dvander@2168
   467
	high = ctx->plugin->info.natives_num - 1;
dvander@2168
   468
dvander@2168
   469
	for (uint32_t i=0; i<ctx->plugin->info.natives_num; i++)
dvander@2168
   470
	{
dvander@2168
   471
		if (strcmp(ctx->natives[i].name, name) == 0)
dvander@2168
   472
		{
dvander@2168
   473
			if (index)
dvander@2168
   474
			{
dvander@2168
   475
				*index = i;
dvander@2168
   476
			}
dvander@2168
   477
			return SP_ERROR_NONE;
dvander@2168
   478
		}
dvander@2168
   479
	}
dvander@2168
   480
dvander@2168
   481
	return SP_ERROR_NOT_FOUND;
dvander@2168
   482
}
dvander@2168
   483
dvander@2168
   484
int BaseContext::GetNativeByIndex(uint32_t index, sp_native_t **native)
dvander@2168
   485
{
dvander@2168
   486
	if (index >= ctx->plugin->info.natives_num)
dvander@2168
   487
	{
dvander@2168
   488
		return SP_ERROR_INDEX;
dvander@2168
   489
	}
dvander@2168
   490
dvander@2168
   491
	if (native)
dvander@2168
   492
	{
dvander@2168
   493
		*native = &(ctx->natives[index]);
dvander@2168
   494
	}
dvander@2168
   495
dvander@2168
   496
	return SP_ERROR_NONE;
dvander@2168
   497
}
dvander@2168
   498
dvander@2168
   499
dvander@2168
   500
uint32_t BaseContext::GetNativesNum()
dvander@2168
   501
{
dvander@2168
   502
	return ctx->plugin->info.natives_num;
dvander@2168
   503
}
dvander@2168
   504
dvander@2168
   505
int BaseContext::FindPublicByName(const char *name, uint32_t *index)
dvander@2168
   506
{
dvander@2168
   507
	int diff, high, low;
dvander@2168
   508
	uint32_t mid;
dvander@2168
   509
dvander@2168
   510
	high = ctx->plugin->info.publics_num - 1;
dvander@2168
   511
	low = 0;
dvander@2168
   512
dvander@2168
   513
	while (low <= high)
dvander@2168
   514
	{
dvander@2168
   515
		mid = (low + high) / 2;
dvander@2168
   516
		diff = strcmp(ctx->publics[mid].name, name);
dvander@2168
   517
		if (diff == 0)
dvander@2168
   518
		{
dvander@2168
   519
			if (index)
dvander@2168
   520
			{
dvander@2168
   521
				*index = mid;
dvander@2168
   522
			}
dvander@2168
   523
			return SP_ERROR_NONE;
dvander@2168
   524
		} else if (diff < 0) {
dvander@2168
   525
			low = mid + 1;
dvander@2168
   526
		} else {
dvander@2168
   527
			high = mid - 1;
dvander@2168
   528
		}
dvander@2168
   529
	}
dvander@2168
   530
dvander@2168
   531
	return SP_ERROR_NOT_FOUND;
dvander@2168
   532
}
dvander@2168
   533
dvander@2168
   534
int BaseContext::GetPublicByIndex(uint32_t index, sp_public_t **pblic)
dvander@2168
   535
{
dvander@2168
   536
	if (index >= ctx->plugin->info.publics_num)
dvander@2168
   537
	{
dvander@2168
   538
		return SP_ERROR_INDEX;
dvander@2168
   539
	}
dvander@2168
   540
dvander@2168
   541
	if (pblic)
dvander@2168
   542
	{
dvander@2168
   543
		*pblic = &(ctx->publics[index]);
dvander@2168
   544
	}
dvander@2168
   545
dvander@2168
   546
	return SP_ERROR_NONE;
dvander@2168
   547
}
dvander@2168
   548
dvander@2168
   549
uint32_t BaseContext::GetPublicsNum()
dvander@2168
   550
{
dvander@2168
   551
	return ctx->plugin->info.publics_num;
dvander@2168
   552
}
dvander@2168
   553
dvander@2168
   554
int BaseContext::GetPubvarByIndex(uint32_t index, sp_pubvar_t **pubvar)
dvander@2168
   555
{
dvander@2168
   556
	if (index >= ctx->plugin->info.pubvars_num)
dvander@2168
   557
	{
dvander@2168
   558
		return SP_ERROR_INDEX;
dvander@2168
   559
	}
dvander@2168
   560
dvander@2168
   561
	if (pubvar)
dvander@2168
   562
	{
dvander@2168
   563
		*pubvar = &(ctx->pubvars[index]);
dvander@2168
   564
	}
dvander@2168
   565
dvander@2168
   566
	return SP_ERROR_NONE;
dvander@2168
   567
}
dvander@2168
   568
dvander@2168
   569
int BaseContext::FindPubvarByName(const char *name, uint32_t *index)
dvander@2168
   570
{
dvander@2168
   571
	int diff, high, low;
dvander@2168
   572
	uint32_t mid;
dvander@2168
   573
dvander@2168
   574
	high = ctx->plugin->info.pubvars_num - 1;
dvander@2168
   575
	low = 0;
dvander@2168
   576
dvander@2168
   577
	while (low <= high)
dvander@2168
   578
	{
dvander@2168
   579
		mid = (low + high) / 2;
dvander@2168
   580
		diff = strcmp(ctx->pubvars[mid].name, name);
dvander@2168
   581
		if (diff == 0)
dvander@2168
   582
		{
dvander@2168
   583
			if (index)
dvander@2168
   584
			{
dvander@2168
   585
				*index = mid;
dvander@2168
   586
			}
dvander@2168
   587
			return SP_ERROR_NONE;
dvander@2168
   588
		} else if (diff < 0) {
dvander@2168
   589
			low = mid + 1;
dvander@2168
   590
		} else {
dvander@2168
   591
			high = mid - 1;
dvander@2168
   592
		}
dvander@2168
   593
	}
dvander@2168
   594
dvander@2168
   595
	return SP_ERROR_NOT_FOUND;
dvander@2168
   596
}
dvander@2168
   597
dvander@2168
   598
int BaseContext::GetPubvarAddrs(uint32_t index, cell_t *local_addr, cell_t **phys_addr)
dvander@2168
   599
{
dvander@2168
   600
	if (index >= ctx->plugin->info.pubvars_num)
dvander@2168
   601
	{
dvander@2168
   602
		return SP_ERROR_INDEX;
dvander@2168
   603
	}
dvander@2168
   604
dvander@2168
   605
	*local_addr = ctx->plugin->info.pubvars[index].address;
dvander@2168
   606
	*phys_addr = ctx->pubvars[index].offs;
dvander@2168
   607
dvander@2168
   608
	return SP_ERROR_NONE;
dvander@2168
   609
}
dvander@2168
   610
dvander@2168
   611
uint32_t BaseContext::GetPubVarsNum()
dvander@2168
   612
{
dvander@2168
   613
	return ctx->plugin->info.pubvars_num;
dvander@2168
   614
}
dvander@2168
   615
dvander@2168
   616
int BaseContext::BindNatives(const sp_nativeinfo_t *natives, unsigned int num, int overwrite)
dvander@2168
   617
{
dvander@2168
   618
	uint32_t i, j, max;
dvander@2168
   619
dvander@2168
   620
	max = ctx->plugin->info.natives_num;
dvander@2168
   621
dvander@2168
   622
	for (i=0; i<max; i++)
dvander@2168
   623
	{
dvander@2168
   624
		if ((ctx->natives[i].status == SP_NATIVE_BOUND) && !overwrite)
dvander@2168
   625
		{
dvander@2168
   626
			continue;
dvander@2168
   627
		}
dvander@2168
   628
dvander@2168
   629
		for (j=0; (natives[j].name) && (!num || j<num); j++)
dvander@2168
   630
		{
dvander@2168
   631
			if (!strcmp(ctx->natives[i].name, natives[j].name))
dvander@2168
   632
			{
dvander@2168
   633
				ctx->natives[i].pfn = natives[j].func;
dvander@2168
   634
				ctx->natives[i].status = SP_NATIVE_BOUND;
dvander@2168
   635
			}
dvander@2168
   636
		}
dvander@2168
   637
	}
dvander@2168
   638
dvander@2168
   639
	return SP_ERROR_NONE;
dvander@2168
   640
}
dvander@2168
   641
dvander@2168
   642
int BaseContext::BindNative(const sp_nativeinfo_t *native)
dvander@2168
   643
{
dvander@2168
   644
	uint32_t index;
dvander@2168
   645
	int err;
dvander@2168
   646
dvander@2168
   647
	if ((err = FindNativeByName(native->name, &index)) != SP_ERROR_NONE)
dvander@2168
   648
	{
dvander@2168
   649
		return err;
dvander@2168
   650
	}
dvander@2168
   651
dvander@2168
   652
	ctx->natives[index].pfn = native->func;
dvander@2168
   653
	ctx->natives[index].status = SP_NATIVE_BOUND;
dvander@2168
   654
dvander@2168
   655
	return SP_ERROR_NONE;
dvander@2168
   656
}
dvander@2168
   657
dvander@2168
   658
int BaseContext::BindNativeToIndex(uint32_t index, SPVM_NATIVE_FUNC func)
dvander@2168
   659
{
dvander@2168
   660
	int err;
dvander@2168
   661
	sp_native_t *native;
dvander@2168
   662
dvander@2168
   663
	if ((err = GetNativeByIndex(index, &native)) != SP_ERROR_NONE)
dvander@2168
   664
	{
dvander@2168
   665
		return err;
dvander@2168
   666
	}
dvander@2168
   667
dvander@2168
   668
	ctx->natives[index].pfn = func;
dvander@2168
   669
	ctx->natives[index].status = SP_NATIVE_BOUND;
dvander@2168
   670
dvander@2168
   671
	return SP_ERROR_NONE;
dvander@2168
   672
}
dvander@2168
   673
dvander@2168
   674
int BaseContext::BindNativeToAny(SPVM_NATIVE_FUNC native)
dvander@2168
   675
{
dvander@2168
   676
	uint32_t nativesnum, i;
dvander@2168
   677
dvander@2168
   678
	nativesnum = ctx->plugin->info.natives_num;
dvander@2168
   679
dvander@2168
   680
	for (i=0; i<nativesnum; i++)
dvander@2168
   681
	{
dvander@2168
   682
		if (ctx->natives[i].status == SP_NATIVE_UNBOUND)
dvander@2168
   683
		{
dvander@2168
   684
			ctx->natives[i].pfn = native;
dvander@2168
   685
			ctx->natives[i].status = SP_NATIVE_BOUND;
dvander@2168
   686
		}
dvander@2168
   687
	}
dvander@2168
   688
dvander@2168
   689
	return SP_ERROR_NONE;
dvander@2168
   690
}
dvander@2168
   691
dvander@2168
   692
int BaseContext::LocalToPhysAddr(cell_t local_addr, cell_t **phys_addr)
dvander@2168
   693
{
dvander@2168
   694
	if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->mem_size))
dvander@2168
   695
	{
dvander@2168
   696
		return SP_ERROR_INVALID_ADDRESS;
dvander@2168
   697
	}
dvander@2168
   698
dvander@2168
   699
	if (phys_addr)
dvander@2168
   700
	{
dvander@2168
   701
		*phys_addr = (cell_t *)(ctx->memory + local_addr);
dvander@2168
   702
	}
dvander@2168
   703
dvander@2168
   704
	return SP_ERROR_NONE;
dvander@2168
   705
}
dvander@2168
   706
dvander@2168
   707
int BaseContext::PushCell(cell_t value)
dvander@2168
   708
{
dvander@2168
   709
	if ((ctx->hp + STACKMARGIN) > (cell_t)(ctx->sp - sizeof(cell_t)))
dvander@2168
   710
	{
dvander@2168
   711
		return SP_ERROR_STACKLOW;
dvander@2168
   712
	}
dvander@2168
   713
dvander@2168
   714
	ctx->sp -= sizeof(cell_t);
dvander@2168
   715
	*(cell_t *)(ctx->memory + ctx->sp) = value;
dvander@2168
   716
	ctx->pushcount++;
dvander@2168
   717
dvander@2168
   718
	return SP_ERROR_NONE;
dvander@2168
   719
}
dvander@2168
   720
dvander@2168
   721
int BaseContext::PushCellsFromArray(cell_t array[], unsigned int numcells)
dvander@2168
   722
{
dvander@2168
   723
	unsigned int i;
dvander@2168
   724
	int err;
dvander@2168
   725
dvander@2168
   726
	for (i=0; i<numcells; i++)
dvander@2168
   727
	{
dvander@2168
   728
		if ((err = PushCell(array[i])) != SP_ERROR_NONE)
dvander@2168
   729
		{
dvander@2168
   730
			ctx->sp += (cell_t)(i * sizeof(cell_t));
dvander@2168
   731
			ctx->pushcount -= i;
dvander@2168
   732
			return err;
dvander@2168
   733
		}
dvander@2168
   734
	}
dvander@2168
   735
dvander@2168
   736
	return SP_ERROR_NONE;
dvander@2168
   737
}
dvander@2168
   738
dvander@2168
   739
int BaseContext::PushCellArray(cell_t *local_addr, cell_t **phys_addr, cell_t array[], unsigned int numcells)
dvander@2168
   740
{
dvander@2168
   741
	cell_t *ph_addr;
dvander@2168
   742
	int err;
dvander@2168
   743
dvander@2168
   744
	if ((err = HeapAlloc(numcells, local_addr, &ph_addr)) != SP_ERROR_NONE)
dvander@2168
   745
	{
dvander@2168
   746
		return err;
dvander@2168
   747
	}
dvander@2168
   748
dvander@2168
   749
	memcpy(ph_addr, array, numcells * sizeof(cell_t));
dvander@2168
   750
dvander@2168
   751
	if ((err = PushCell(*local_addr)) != SP_ERROR_NONE)
dvander@2168
   752
	{
dvander@2168
   753
		HeapRelease(*local_addr);
dvander@2168
   754
		return err;
dvander@2168
   755
	}
dvander@2168
   756
dvander@2168
   757
	if (phys_addr)
dvander@2168
   758
	{
dvander@2168
   759
		*phys_addr = ph_addr;
dvander@2168
   760
	}
dvander@2168
   761
dvander@2168
   762
	return SP_ERROR_NONE;
dvander@2168
   763
}
dvander@2168
   764
dvander@2168
   765
int BaseContext::LocalToString(cell_t local_addr, char **addr)
dvander@2168
   766
{
dvander@2168
   767
	if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->mem_size))
dvander@2168
   768
	{
dvander@2168
   769
		return SP_ERROR_INVALID_ADDRESS;
dvander@2168
   770
	}
dvander@2168
   771
	*addr = (char *)(ctx->memory + local_addr);
dvander@2168
   772
dvander@2168
   773
	return SP_ERROR_NONE;
dvander@2168
   774
}
dvander@2168
   775
dvander@2168
   776
int BaseContext::PushString(cell_t *local_addr, char **phys_addr, const char *string)
dvander@2168
   777
{
dvander@2168
   778
	char *ph_addr;
dvander@2168
   779
	int err;
dvander@2168
   780
	unsigned int len, numcells = ((len=strlen(string)) + sizeof(cell_t)) / sizeof(cell_t);
dvander@2168
   781
dvander@2168
   782
	if ((err = HeapAlloc(numcells, local_addr, (cell_t **)&ph_addr)) != SP_ERROR_NONE)
dvander@2168
   783
	{
dvander@2168
   784
		return err;
dvander@2168
   785
	}
dvander@2168
   786
dvander@2168
   787
	memcpy(ph_addr, string, len);
dvander@2168
   788
	ph_addr[len] = '\0';
dvander@2168
   789
dvander@2168
   790
	if ((err = PushCell(*local_addr)) != SP_ERROR_NONE)
dvander@2168
   791
	{
dvander@2168
   792
		HeapRelease(*local_addr);
dvander@2168
   793
		return err;
dvander@2168
   794
	}
dvander@2168
   795
dvander@2168
   796
	if (phys_addr)
dvander@2168
   797
	{
dvander@2168
   798
		*phys_addr = ph_addr;
dvander@2168
   799
	}
dvander@2168
   800
dvander@2168
   801
	return SP_ERROR_NONE;
dvander@2168
   802
}
dvander@2168
   803
dvander@2168
   804
int BaseContext::StringToLocal(cell_t local_addr, size_t bytes, const char *source)
dvander@2168
   805
{
dvander@2168
   806
	char *dest;
dvander@2168
   807
	size_t len;
dvander@2168
   808
dvander@2168
   809
	if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->mem_size))
dvander@2168
   810
	{
dvander@2168
   811
		return SP_ERROR_INVALID_ADDRESS;
dvander@2168
   812
	}
dvander@2168
   813
dvander@2168
   814
	if (bytes == 0)
dvander@2168
   815
	{
dvander@2168
   816
		return SP_ERROR_NONE;
dvander@2168
   817
	}
dvander@2168
   818
dvander@2168
   819
	len = strlen(source);
dvander@2168
   820
	dest = (char *)(ctx->memory + local_addr);
dvander@2168
   821
dvander@2168
   822
	if (len >= bytes)
dvander@2168
   823
	{
dvander@2168
   824
		len = bytes - 1;
dvander@2168
   825
	}
dvander@2168
   826
dvander@2168
   827
	memmove(dest, source, len);
dvander@2168
   828
	dest[len] = '\0';
dvander@2168
   829
dvander@2168
   830
	return SP_ERROR_NONE;
dvander@2168
   831
}
dvander@2168
   832
dvander@2168
   833
inline int __CheckValidChar(char *c)
dvander@2168
   834
{
dvander@2168
   835
	int count;
dvander@2168
   836
	int bytecount = 0;
dvander@2168
   837
dvander@2168
   838
	for (count=1; (*c & 0xC0) == 0x80; count++)
dvander@2168
   839
	{
dvander@2168
   840
		c--;
dvander@2168
   841
	}
dvander@2168
   842
dvander@2168
   843
	switch (*c & 0xF0)
dvander@2168
   844
	{
dvander@2168
   845
	case 0xC0:
dvander@2168
   846
	case 0xD0:
dvander@2168
   847
		{
dvander@2168
   848
			bytecount = 2;
dvander@2168
   849
			break;
dvander@2168
   850
		}
dvander@2168
   851
	case 0xE0:
dvander@2168
   852
		{
dvander@2168
   853
			bytecount = 3;
dvander@2168
   854
			break;
dvander@2168
   855
		}
dvander@2168
   856
	case 0xF0:
dvander@2168
   857
		{
dvander@2168
   858
			bytecount = 4;
dvander@2168
   859
			break;
dvander@2168
   860
		}
dvander@2168
   861
	}
dvander@2168
   862
dvander@2168
   863
	if (bytecount != count)
dvander@2168
   864
	{
dvander@2168
   865
		return count;
dvander@2168
   866
	}
dvander@2168
   867
dvander@2168
   868
	return 0;
dvander@2168
   869
}
dvander@2168
   870
dvander@2168
   871
int BaseContext::StringToLocalUTF8(cell_t local_addr, size_t maxbytes, const char *source, size_t *wrtnbytes)
dvander@2168
   872
{
dvander@2168
   873
	char *dest;
dvander@2168
   874
	size_t len;
dvander@2168
   875
	bool needtocheck = false;
dvander@2168
   876
dvander@2168
   877
	if (((local_addr >= ctx->hp) && (local_addr < ctx->sp)) || (local_addr < 0) || ((ucell_t)local_addr >= ctx->mem_size))
dvander@2168
   878
	{
dvander@2168
   879
		return SP_ERROR_INVALID_ADDRESS;
dvander@2168
   880
	}
dvander@2168
   881
	
dvander@2168
   882
	if (maxbytes == 0)
dvander@2168
   883
	{
dvander@2168
   884
		return SP_ERROR_NONE;
dvander@2168
   885
	}
dvander@2168
   886
dvander@2168
   887
	len = strlen(source);
dvander@2168
   888
	dest = (char *)(ctx->memory + local_addr);
dvander@2168
   889
dvander@2168
   890
	if ((size_t)len >= maxbytes)
dvander@2168
   891
	{
dvander@2168
   892
		len = maxbytes - 1;
dvander@2168
   893
		needtocheck = true;
dvander@2168
   894
	}
dvander@2168
   895
dvander@2168
   896
	memmove(dest, source, len);
dvander@2168
   897
	if ((dest[len-1] & 1<<7) && needtocheck)
dvander@2168
   898
	{
dvander@2168
   899
		len -= __CheckValidChar(dest+len-1);
dvander@2168
   900
	}
dvander@2168
   901
	dest[len] = '\0';
dvander@2168
   902
dvander@2168
   903
	if (wrtnbytes)
dvander@2168
   904
	{
dvander@2168
   905
		*wrtnbytes = len;
dvander@2168
   906
	}
dvander@2168
   907
dvander@2168
   908
	return SP_ERROR_NONE;
dvander@2168
   909
}
dvander@2168
   910
dvander@2168
   911
#define USHR(x) ((unsigned int)(x)>>1)
dvander@2168
   912
dvander@2168
   913
int BaseContext::LookupFile(ucell_t addr, const char **filename)
dvander@2168
   914
{
dvander@2168
   915
	int high, low, mid;
dvander@2168
   916
dvander@2168
   917
	high = ctx->plugin->debug.files_num;
dvander@2168
   918
	low = -1;
dvander@2168
   919
dvander@2168
   920
	while (high - low > 1)
dvander@2168
   921
	{
dvander@2168
   922
		mid = USHR(low + high);
dvander@2168
   923
		if (ctx->files[mid].addr <= addr)
dvander@2168
   924
		{
dvander@2168
   925
			low = mid;
dvander@2168
   926
		} else {
dvander@2168
   927
			high = mid;
dvander@2168
   928
		}
dvander@2168
   929
	}
dvander@2168
   930
dvander@2168
   931
	if (low == -1)
dvander@2168
   932
	{
dvander@2168
   933
		return SP_ERROR_NOT_FOUND;
dvander@2168
   934
	}
dvander@2168
   935
dvander@2168
   936
	*filename = ctx->files[low].name;
dvander@2168
   937
dvander@2168
   938
	return SP_ERROR_NONE;
dvander@2168
   939
}
dvander@2168
   940
dvander@2168
   941
int BaseContext::LookupFunction(ucell_t addr, const char **name)
dvander@2168
   942
{
dvander@2168
   943
	uint32_t iter, max = ctx->plugin->debug.syms_num;
dvander@2168
   944
dvander@2168
   945
	for (iter=0; iter<max; iter++)
dvander@2168
   946
	{
dvander@2168
   947
		if ((ctx->symbols[iter].sym->ident == SP_SYM_FUNCTION) 
dvander@2168
   948
			&& (ctx->symbols[iter].codestart <= addr) 
dvander@2168
   949
			&& (ctx->symbols[iter].codeend > addr))
dvander@2168
   950
		{
dvander@2168
   951
			break;
dvander@2168
   952
		}
dvander@2168
   953
	}
dvander@2168
   954
dvander@2168
   955
	if (iter >= max)
dvander@2168
   956
	{
dvander@2168
   957
		return SP_ERROR_NOT_FOUND;
dvander@2168
   958
	}
dvander@2168
   959
dvander@2168
   960
	*name = ctx->symbols[iter].name;
dvander@2168
   961
dvander@2168
   962
	return SP_ERROR_NONE;
dvander@2168
   963
}
dvander@2168
   964
dvander@2168
   965
int BaseContext::LookupLine(ucell_t addr, uint32_t *line)
dvander@2168
   966
{
dvander@2168
   967
	int high, low, mid;
dvander@2168
   968
dvander@2168
   969
	high = ctx->plugin->debug.lines_num;
dvander@2168
   970
	low = -1;
dvander@2168
   971
dvander@2168
   972
	while (high - low > 1)
dvander@2168
   973
	{
dvander@2168
   974
		mid = USHR(low + high);
dvander@2168
   975
		if (ctx->lines[mid].addr <= addr)
dvander@2168
   976
		{
dvander@2168
   977
			low = mid;
dvander@2168
   978
		} else {
dvander@2168
   979
			high = mid;
dvander@2168
   980
		}
dvander@2168
   981
	}
dvander@2168
   982
dvander@2168
   983
	if (low == -1)
dvander@2168
   984
	{
dvander@2168
   985
		return SP_ERROR_NOT_FOUND;
dvander@2168
   986
	}
dvander@2168
   987
dvander@2168
   988
	/* Since the CIP occurs BEFORE the line, we have to add one */
dvander@2168
   989
	*line = ctx->lines[low].line + 1;
dvander@2168
   990
dvander@2168
   991
	return SP_ERROR_NONE;
dvander@2168
   992
}
dvander@2168
   993
dvander@2168
   994
IPluginFunction *BaseContext::GetFunctionById(funcid_t func_id)
dvander@2168
   995
{
dvander@2168
   996
	CFunction *pFunc = NULL;
dvander@2168
   997
dvander@2168
   998
	if (func_id & 1)
dvander@2168
   999
	{
dvander@2168
  1000
		func_id >>= 1;
dvander@2168
  1001
		if (func_id >= ctx->plugin->info.publics_num)
dvander@2168
  1002
		{
dvander@2168
  1003
			return NULL;
dvander@2168
  1004
		}
dvander@2168
  1005
		pFunc = m_pub_funcs[func_id];
dvander@2168
  1006
		if (!pFunc)
dvander@2168
  1007
		{
dvander@2168
  1008
			m_pub_funcs[func_id] = new CFunction(ctx->publics[func_id].code_offs, 
dvander@2168
  1009
												 this, 
dvander@2168
  1010
												 ctx->publics[func_id].funcid,
dvander@2168
  1011
												 func_id);
dvander@2168
  1012
			pFunc = m_pub_funcs[func_id];
dvander@2168
  1013
		}
dvander@2168
  1014
		else if (pFunc->IsInvalidated())
dvander@2168
  1015
		{
dvander@2168
  1016
			pFunc->Set(ctx->publics[func_id].code_offs, 
dvander@2168
  1017
				       this,
dvander@2168
  1018
					   ctx->publics[func_id].funcid,
dvander@2168
  1019
					   func_id);
dvander@2168
  1020
		}
dvander@2168
  1021
	} else {
dvander@2168
  1022
		/* :TODO: currently not used */
dvander@2168
  1023
#if 0
dvander@2168
  1024
		func_id >>= 1;
dvander@2168
  1025
		unsigned int index;
dvander@2168
  1026
		if (!g_pVM->FunctionLookup(ctx, func_id, &index))
dvander@2168
  1027
		{
dvander@2168
  1028
			return NULL;
dvander@2168
  1029
		}
dvander@2168
  1030
		pFunc = m_priv_funcs[func_id];
dvander@2168
  1031
		if (!pFunc)
dvander@2168
  1032
		{
dvander@2168
  1033
			m_priv_funcs[func_id] = new CFunction(save, this);
dvander@2168
  1034
			pFunc = m_priv_funcs[func_id];
dvander@2168
  1035
		}
dvander@2168
  1036
#endif
dvander@2168
  1037
	}
dvander@2168
  1038
dvander@2168
  1039
	return pFunc;
dvander@2168
  1040
}
dvander@2168
  1041
dvander@2168
  1042
IPluginFunction *BaseContext::GetFunctionByName(const char *public_name)
dvander@2168
  1043
{
dvander@2168
  1044
	uint32_t index;
dvander@2168
  1045
dvander@2168
  1046
	if (FindPublicByName(public_name, &index) != SP_ERROR_NONE)
dvander@2168
  1047
	{
dvander@2168
  1048
		return NULL;
dvander@2168
  1049
	}
dvander@2168
  1050
dvander@2168
  1051
	CFunction *pFunc = m_pub_funcs[index];
dvander@2168
  1052
	if (!pFunc)
dvander@2168
  1053
	{
dvander@2168
  1054
		sp_public_t *pub = NULL;
dvander@2168
  1055
		GetPublicByIndex(index, &pub);
dvander@2168
  1056
		if (pub)
dvander@2168
  1057
		{
dvander@2168
  1058
			m_pub_funcs[index] = new CFunction(pub->code_offs, this, pub->funcid, index);
dvander@2168
  1059
		}
dvander@2168
  1060
		pFunc = m_pub_funcs[index];
dvander@2168
  1061
	}
dvander@2168
  1062
	else if (pFunc->IsInvalidated())
dvander@2168
  1063
	{
dvander@2168
  1064
		sp_public_t *pub = NULL;
dvander@2168
  1065
		GetPublicByIndex(index, &pub);
dvander@2168
  1066
		if (pub)
dvander@2168
  1067
		{
dvander@2168
  1068
			pFunc->Set(pub->code_offs, this, pub->funcid, index);
dvander@2168
  1069
		}
dvander@2168
  1070
		else
dvander@2168
  1071
		{
dvander@2168
  1072
			pFunc = NULL;
dvander@2168
  1073
		}
dvander@2168
  1074
	}
dvander@2168
  1075
dvander@2168
  1076
	return pFunc;
dvander@2168
  1077
}
dvander@2168
  1078
dvander@2168
  1079
int BaseContext::LocalToStringNULL(cell_t local_addr, char **addr)
dvander@2168
  1080
{
dvander@2168
  1081
	int err;
dvander@2168
  1082
	if ((err = LocalToString(local_addr, addr)) != SP_ERROR_NONE)
dvander@2168
  1083
	{
dvander@2168
  1084
		return err;
dvander@2168
  1085
	}
dvander@2168
  1086
dvander@2168
  1087
	if ((cell_t *)*addr == m_pNullString)
dvander@2168
  1088
	{
dvander@2168
  1089
		*addr = NULL;
dvander@2168
  1090
	}
dvander@2168
  1091
dvander@2168
  1092
	return SP_ERROR_NONE;
dvander@2168
  1093
}
dvander@2168
  1094
dvander@2168
  1095
#if defined SOURCEMOD_BUILD
dvander@2168
  1096
SourceMod::IdentityToken_t *BaseContext::GetIdentity()
dvander@2168
  1097
{
dvander@2168
  1098
	return m_pToken;
dvander@2168
  1099
}
dvander@2168
  1100
dvander@2168
  1101
void BaseContext::SetIdentity(SourceMod::IdentityToken_t *token)
dvander@2168
  1102
{
dvander@2168
  1103
	m_pToken = token;
dvander@2168
  1104
}
dvander@2168
  1105
dvander@2168
  1106
cell_t *BaseContext::GetNullRef(SP_NULL_TYPE type)
dvander@2168
  1107
{
dvander@2168
  1108
	if (type == SP_NULL_VECTOR)
dvander@2168
  1109
	{
dvander@2168
  1110
		return m_pNullVec;
dvander@2168
  1111
	}
dvander@2168
  1112
dvander@2168
  1113
	return NULL;
dvander@2168
  1114
}
dvander@2168
  1115
#endif
dvander@2168
  1116
dvander@2168
  1117
bool BaseContext::IsInExec()
dvander@2168
  1118
{
dvander@2168
  1119
	return m_InExec;
dvander@2168
  1120
}