sourcepawn/jit/sp_vm_basecontext.cpp
author David Anderson <dvander@alliedmods.net>
Mon Jul 07 06:24:54 2008 +0000 (2008-07-07)
branchrefac-jit
changeset 2174 01c5adfae757
parent 2173 c38e83232dcc
child 2180 aae5f448b508
permissions -rw-r--r--
more api for core
sets profiler+debugger now
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@2171
    39
#include "x86/jit_x86.h"
dvander@2168
    40
dvander@2168
    41
using namespace SourcePawn;
dvander@2168
    42
dvander@2168
    43
#define CELLBOUNDMAX	(INT_MAX/sizeof(cell_t))
dvander@2168
    44
#define STACKMARGIN		((cell_t)(16*sizeof(cell_t)))
dvander@2168
    45
dvander@2171
    46
BaseContext::BaseContext(BaseRuntime *pRuntime)
dvander@2168
    47
{
dvander@2171
    48
	m_pRuntime = pRuntime;
dvander@2168
    49
dvander@2168
    50
	m_InExec = false;
dvander@2168
    51
	m_CustomMsg = false;
dvander@2168
    52
dvander@2168
    53
	/* Initialize the null references */
dvander@2168
    54
	uint32_t index;
dvander@2168
    55
	if (FindPubvarByName("NULL_VECTOR", &index) == SP_ERROR_NONE)
dvander@2168
    56
	{
dvander@2168
    57
		sp_pubvar_t *pubvar;
dvander@2168
    58
		GetPubvarByIndex(index, &pubvar);
dvander@2168
    59
		m_pNullVec = pubvar->offs;
dvander@2171
    60
	}
dvander@2171
    61
	else
dvander@2171
    62
	{
dvander@2168
    63
		m_pNullVec = NULL;
dvander@2168
    64
	}
dvander@2168
    65
dvander@2168
    66
	if (FindPubvarByName("NULL_STRING", &index) == SP_ERROR_NONE)
dvander@2168
    67
	{
dvander@2168
    68
		sp_pubvar_t *pubvar;
dvander@2168
    69
		GetPubvarByIndex(index, &pubvar);
dvander@2168
    70
		m_pNullString = pubvar->offs;
dvander@2171
    71
	}
dvander@2171
    72
	else
dvander@2171
    73
	{
dvander@2168
    74
		m_pNullString = NULL;
dvander@2168
    75
	}
dvander@2168
    76
}
dvander@2168
    77
dvander@2168
    78
BaseContext::~BaseContext()
dvander@2168
    79
{
dvander@2168
    80
}
dvander@2168
    81
dvander@2168
    82
IVirtualMachine *BaseContext::GetVirtualMachine()
dvander@2168
    83
{
dvander@2171
    84
	return NULL;
dvander@2168
    85
}
dvander@2168
    86
dvander@2168
    87
sp_context_t *BaseContext::GetContext()
dvander@2168
    88
{
dvander@2171
    89
	return &m_ctx;
dvander@2168
    90
}
dvander@2168
    91
dvander@2168
    92
bool BaseContext::IsDebugging()
dvander@2168
    93
{
dvander@2171
    94
	return m_pRuntime->IsDebugging();
dvander@2168
    95
}
dvander@2168
    96
dvander@2171
    97
int BaseContext::SetDebugBreak(void *newpfn, void *oldpfn)
dvander@2168
    98
{
dvander@2171
    99
	return SP_ERROR_ABORTED;
dvander@2168
   100
}
dvander@2168
   101
dvander@2168
   102
IPluginDebugInfo *BaseContext::GetDebugInfo()
dvander@2168
   103
{
dvander@2171
   104
	return NULL;
dvander@2168
   105
}
dvander@2168
   106
dvander@2168
   107
int BaseContext::Execute(uint32_t code_addr, cell_t *result)
dvander@2168
   108
{
dvander@2171
   109
	return SP_ERROR_ABORTED;
dvander@2168
   110
}
dvander@2168
   111
dvander@2168
   112
void BaseContext::SetErrorMessage(const char *msg, va_list ap)
dvander@2168
   113
{
dvander@2168
   114
	m_CustomMsg = true;
dvander@2168
   115
dvander@2168
   116
	vsnprintf(m_MsgCache, sizeof(m_MsgCache), msg, ap);
dvander@2168
   117
}
dvander@2168
   118
dvander@2171
   119
void BaseContext::_SetErrorMessage(const char *msg, ...)
dvander@2171
   120
{
dvander@2171
   121
	va_list ap;
dvander@2171
   122
	va_start(ap, msg);
dvander@2171
   123
	SetErrorMessage(msg, ap);
dvander@2171
   124
	va_end(ap);
dvander@2171
   125
}
dvander@2171
   126
dvander@2168
   127
cell_t BaseContext::ThrowNativeErrorEx(int error, const char *msg, ...)
dvander@2168
   128
{
dvander@2168
   129
	if (!m_InExec)
dvander@2168
   130
	{
dvander@2168
   131
		return 0;
dvander@2168
   132
	}
dvander@2168
   133
dvander@2171
   134
	m_ctx.n_err = error;
dvander@2168
   135
	
dvander@2168
   136
	if (msg)
dvander@2168
   137
	{
dvander@2168
   138
		va_list ap;
dvander@2168
   139
		va_start(ap, msg);
dvander@2168
   140
		SetErrorMessage(msg, ap);
dvander@2168
   141
		va_end(ap);
dvander@2168
   142
	}
dvander@2168
   143
dvander@2168
   144
	return 0;
dvander@2168
   145
}
dvander@2168
   146
dvander@2168
   147
cell_t BaseContext::ThrowNativeError(const char *msg, ...)
dvander@2168
   148
{
dvander@2168
   149
	if (!m_InExec)
dvander@2168
   150
	{
dvander@2168
   151
		return 0;
dvander@2168
   152
	}
dvander@2168
   153
dvander@2171
   154
	m_ctx.n_err = SP_ERROR_NATIVE;
dvander@2168
   155
dvander@2168
   156
	if (msg)
dvander@2168
   157
	{
dvander@2168
   158
		va_list ap;
dvander@2168
   159
		va_start(ap, msg);
dvander@2168
   160
		SetErrorMessage(msg, ap);
dvander@2168
   161
		va_end(ap);
dvander@2168
   162
	}
dvander@2168
   163
dvander@2168
   164
	return 0;
dvander@2168
   165
}
dvander@2168
   166
dvander@2168
   167
int BaseContext::HeapAlloc(unsigned int cells, cell_t *local_addr, cell_t **phys_addr)
dvander@2168
   168
{
dvander@2168
   169
	cell_t *addr;
dvander@2168
   170
	ucell_t realmem;
dvander@2168
   171
dvander@2168
   172
#if 0
dvander@2168
   173
	if (cells > CELLBOUNDMAX)
dvander@2168
   174
	{
dvander@2168
   175
		return SP_ERROR_ARAM;
dvander@2168
   176
	}
dvander@2168
   177
#else
dvander@2168
   178
	assert(cells < CELLBOUNDMAX);
dvander@2168
   179
#endif
dvander@2168
   180
dvander@2168
   181
	realmem = cells * sizeof(cell_t);
dvander@2168
   182
dvander@2168
   183
	/**
dvander@2168
   184
	 * Check if the space between the heap and stack is sufficient.
dvander@2168
   185
	 */
dvander@2171
   186
	if ((cell_t)(m_ctx.sp - m_ctx.hp - realmem) < STACKMARGIN)
dvander@2168
   187
	{
dvander@2168
   188
		return SP_ERROR_HEAPLOW;
dvander@2168
   189
	}
dvander@2168
   190
dvander@2171
   191
	addr = (cell_t *)(m_pPlugin->memory + m_ctx.hp);
dvander@2168
   192
	/* store size of allocation in cells */
dvander@2168
   193
	*addr = (cell_t)cells;
dvander@2168
   194
	addr++;
dvander@2171
   195
	m_ctx.hp += sizeof(cell_t);
dvander@2168
   196
dvander@2171
   197
	*local_addr = m_ctx.hp;
dvander@2168
   198
dvander@2168
   199
	if (phys_addr)
dvander@2168
   200
	{
dvander@2168
   201
		*phys_addr = addr;
dvander@2168
   202
	}
dvander@2168
   203
dvander@2171
   204
	m_ctx.hp += realmem;
dvander@2168
   205
dvander@2168
   206
	return SP_ERROR_NONE;
dvander@2168
   207
}
dvander@2168
   208
dvander@2168
   209
int BaseContext::HeapPop(cell_t local_addr)
dvander@2168
   210
{
dvander@2168
   211
	cell_t cellcount;
dvander@2168
   212
	cell_t *addr;
dvander@2168
   213
dvander@2168
   214
	/* check the bounds of this address */
dvander@2168
   215
	local_addr -= sizeof(cell_t);
dvander@2171
   216
	if (local_addr < (cell_t)m_pPlugin->data_size || local_addr >= m_ctx.sp)
dvander@2168
   217
	{
dvander@2168
   218
		return SP_ERROR_INVALID_ADDRESS;
dvander@2168
   219
	}
dvander@2168
   220
dvander@2171
   221
	addr = (cell_t *)(m_pPlugin->memory + local_addr);
dvander@2168
   222
	cellcount = (*addr) * sizeof(cell_t);
dvander@2168
   223
	/* check if this memory count looks valid */
dvander@2171
   224
	if ((signed)(m_ctx.hp - cellcount - sizeof(cell_t)) != local_addr)
dvander@2168
   225
	{
dvander@2168
   226
		return SP_ERROR_INVALID_ADDRESS;
dvander@2168
   227
	}
dvander@2168
   228
dvander@2171
   229
	m_ctx.hp = local_addr;
dvander@2168
   230
dvander@2168
   231
	return SP_ERROR_NONE;
dvander@2168
   232
}
dvander@2168
   233
dvander@2168
   234
dvander@2168
   235
int BaseContext::HeapRelease(cell_t local_addr)
dvander@2168
   236
{
dvander@2171
   237
	if (local_addr < (cell_t)m_pPlugin->data_size)
dvander@2168
   238
	{
dvander@2168
   239
		return SP_ERROR_INVALID_ADDRESS;
dvander@2168
   240
	}
dvander@2168
   241
dvander@2171
   242
	m_ctx.hp = local_addr - sizeof(cell_t);
dvander@2168
   243
dvander@2168
   244
	return SP_ERROR_NONE;
dvander@2168
   245
}
dvander@2168
   246
dvander@2168
   247
int BaseContext::FindNativeByName(const char *name, uint32_t *index)
dvander@2168
   248
{
dvander@2171
   249
	return m_pRuntime->FindNativeByName(name, index);
dvander@2168
   250
}
dvander@2168
   251
dvander@2168
   252
int BaseContext::GetNativeByIndex(uint32_t index, sp_native_t **native)
dvander@2168
   253
{
dvander@2171
   254
	return m_pRuntime->GetNativeByIndex(index, native);
dvander@2168
   255
}
dvander@2168
   256
dvander@2168
   257
dvander@2168
   258
uint32_t BaseContext::GetNativesNum()
dvander@2168
   259
{
dvander@2171
   260
	return m_pRuntime->GetNativesNum();
dvander@2168
   261
}
dvander@2168
   262
dvander@2168
   263
int BaseContext::FindPublicByName(const char *name, uint32_t *index)
dvander@2168
   264
{
dvander@2171
   265
	return m_pRuntime->FindPublicByName(name, index);
dvander@2168
   266
}
dvander@2168
   267
dvander@2168
   268
int BaseContext::GetPublicByIndex(uint32_t index, sp_public_t **pblic)
dvander@2168
   269
{
dvander@2171
   270
	return m_pRuntime->GetPublicByIndex(index, pblic);
dvander@2168
   271
}
dvander@2168
   272
dvander@2168
   273
uint32_t BaseContext::GetPublicsNum()
dvander@2168
   274
{
dvander@2171
   275
	return m_pRuntime->GetPublicsNum();
dvander@2168
   276
}
dvander@2168
   277
dvander@2168
   278
int BaseContext::GetPubvarByIndex(uint32_t index, sp_pubvar_t **pubvar)
dvander@2168
   279
{
dvander@2171
   280
	return m_pRuntime->GetPubvarByIndex(index, pubvar);
dvander@2168
   281
}
dvander@2168
   282
dvander@2168
   283
int BaseContext::FindPubvarByName(const char *name, uint32_t *index)
dvander@2168
   284
{
dvander@2171
   285
	return m_pRuntime->FindPublicByName(name, index);
dvander@2168
   286
}
dvander@2168
   287
dvander@2168
   288
int BaseContext::GetPubvarAddrs(uint32_t index, cell_t *local_addr, cell_t **phys_addr)
dvander@2168
   289
{
dvander@2171
   290
	return m_pRuntime->GetPubvarAddrs(index, local_addr, phys_addr);
dvander@2168
   291
}
dvander@2168
   292
dvander@2168
   293
uint32_t BaseContext::GetPubVarsNum()
dvander@2168
   294
{
dvander@2171
   295
	return m_pRuntime->GetPubVarsNum();
dvander@2168
   296
}
dvander@2168
   297
dvander@2168
   298
int BaseContext::BindNatives(const sp_nativeinfo_t *natives, unsigned int num, int overwrite)
dvander@2168
   299
{
dvander@2171
   300
	return SP_ERROR_ABORTED;
dvander@2168
   301
}
dvander@2168
   302
dvander@2168
   303
int BaseContext::BindNative(const sp_nativeinfo_t *native)
dvander@2168
   304
{
dvander@2171
   305
	return SP_ERROR_ABORTED;
dvander@2168
   306
}
dvander@2168
   307
dvander@2168
   308
int BaseContext::BindNativeToIndex(uint32_t index, SPVM_NATIVE_FUNC func)
dvander@2168
   309
{
dvander@2171
   310
	return SP_ERROR_ABORTED;
dvander@2168
   311
}
dvander@2168
   312
dvander@2168
   313
int BaseContext::BindNativeToAny(SPVM_NATIVE_FUNC native)
dvander@2168
   314
{
dvander@2171
   315
	return SP_ERROR_ABORTED;
dvander@2168
   316
}
dvander@2168
   317
dvander@2168
   318
int BaseContext::LocalToPhysAddr(cell_t local_addr, cell_t **phys_addr)
dvander@2168
   319
{
dvander@2171
   320
	if (((local_addr >= m_ctx.hp) && (local_addr < m_ctx.sp)) 
dvander@2171
   321
		|| (local_addr < 0) || ((ucell_t)local_addr >= m_pPlugin->mem_size))
dvander@2168
   322
	{
dvander@2168
   323
		return SP_ERROR_INVALID_ADDRESS;
dvander@2168
   324
	}
dvander@2168
   325
dvander@2168
   326
	if (phys_addr)
dvander@2168
   327
	{
dvander@2171
   328
		*phys_addr = (cell_t *)(m_pPlugin->memory + local_addr);
dvander@2168
   329
	}
dvander@2168
   330
dvander@2168
   331
	return SP_ERROR_NONE;
dvander@2168
   332
}
dvander@2168
   333
dvander@2168
   334
int BaseContext::PushCell(cell_t value)
dvander@2168
   335
{
dvander@2171
   336
	return SP_ERROR_ABORTED;
dvander@2168
   337
}
dvander@2168
   338
dvander@2168
   339
int BaseContext::PushCellsFromArray(cell_t array[], unsigned int numcells)
dvander@2168
   340
{
dvander@2171
   341
	return SP_ERROR_ABORTED;
dvander@2168
   342
}
dvander@2168
   343
dvander@2168
   344
int BaseContext::PushCellArray(cell_t *local_addr, cell_t **phys_addr, cell_t array[], unsigned int numcells)
dvander@2168
   345
{
dvander@2171
   346
	return SP_ERROR_ABORTED;
dvander@2168
   347
}
dvander@2168
   348
dvander@2168
   349
int BaseContext::LocalToString(cell_t local_addr, char **addr)
dvander@2168
   350
{
dvander@2171
   351
	if (((local_addr >= m_ctx.hp) && (local_addr < m_ctx.sp))
dvander@2171
   352
		|| (local_addr < 0) || ((ucell_t)local_addr >= m_pPlugin->mem_size))
dvander@2168
   353
	{
dvander@2168
   354
		return SP_ERROR_INVALID_ADDRESS;
dvander@2168
   355
	}
dvander@2171
   356
	*addr = (char *)(m_pPlugin->memory + local_addr);
dvander@2168
   357
dvander@2168
   358
	return SP_ERROR_NONE;
dvander@2168
   359
}
dvander@2168
   360
dvander@2168
   361
int BaseContext::PushString(cell_t *local_addr, char **phys_addr, const char *string)
dvander@2168
   362
{
dvander@2171
   363
	return SP_ERROR_ABORTED;
dvander@2168
   364
}
dvander@2168
   365
dvander@2168
   366
int BaseContext::StringToLocal(cell_t local_addr, size_t bytes, const char *source)
dvander@2168
   367
{
dvander@2168
   368
	char *dest;
dvander@2168
   369
	size_t len;
dvander@2168
   370
dvander@2171
   371
	if (((local_addr >= m_ctx.hp) && (local_addr < m_ctx.sp))
dvander@2171
   372
		|| (local_addr < 0) || ((ucell_t)local_addr >= m_pPlugin->mem_size))
dvander@2168
   373
	{
dvander@2168
   374
		return SP_ERROR_INVALID_ADDRESS;
dvander@2168
   375
	}
dvander@2168
   376
dvander@2168
   377
	if (bytes == 0)
dvander@2168
   378
	{
dvander@2168
   379
		return SP_ERROR_NONE;
dvander@2168
   380
	}
dvander@2168
   381
dvander@2168
   382
	len = strlen(source);
dvander@2171
   383
	dest = (char *)(m_pPlugin->memory + local_addr);
dvander@2168
   384
dvander@2168
   385
	if (len >= bytes)
dvander@2168
   386
	{
dvander@2168
   387
		len = bytes - 1;
dvander@2168
   388
	}
dvander@2168
   389
dvander@2168
   390
	memmove(dest, source, len);
dvander@2168
   391
	dest[len] = '\0';
dvander@2168
   392
dvander@2168
   393
	return SP_ERROR_NONE;
dvander@2168
   394
}
dvander@2168
   395
dvander@2168
   396
inline int __CheckValidChar(char *c)
dvander@2168
   397
{
dvander@2168
   398
	int count;
dvander@2168
   399
	int bytecount = 0;
dvander@2168
   400
dvander@2168
   401
	for (count=1; (*c & 0xC0) == 0x80; count++)
dvander@2168
   402
	{
dvander@2168
   403
		c--;
dvander@2168
   404
	}
dvander@2168
   405
dvander@2168
   406
	switch (*c & 0xF0)
dvander@2168
   407
	{
dvander@2168
   408
	case 0xC0:
dvander@2168
   409
	case 0xD0:
dvander@2168
   410
		{
dvander@2168
   411
			bytecount = 2;
dvander@2168
   412
			break;
dvander@2168
   413
		}
dvander@2168
   414
	case 0xE0:
dvander@2168
   415
		{
dvander@2168
   416
			bytecount = 3;
dvander@2168
   417
			break;
dvander@2168
   418
		}
dvander@2168
   419
	case 0xF0:
dvander@2168
   420
		{
dvander@2168
   421
			bytecount = 4;
dvander@2168
   422
			break;
dvander@2168
   423
		}
dvander@2168
   424
	}
dvander@2168
   425
dvander@2168
   426
	if (bytecount != count)
dvander@2168
   427
	{
dvander@2168
   428
		return count;
dvander@2168
   429
	}
dvander@2168
   430
dvander@2168
   431
	return 0;
dvander@2168
   432
}
dvander@2168
   433
dvander@2168
   434
int BaseContext::StringToLocalUTF8(cell_t local_addr, size_t maxbytes, const char *source, size_t *wrtnbytes)
dvander@2168
   435
{
dvander@2168
   436
	char *dest;
dvander@2168
   437
	size_t len;
dvander@2168
   438
	bool needtocheck = false;
dvander@2168
   439
dvander@2171
   440
	if (((local_addr >= m_ctx.hp) && (local_addr < m_ctx.sp))
dvander@2171
   441
		|| (local_addr < 0)
dvander@2171
   442
		|| ((ucell_t)local_addr >= m_pPlugin->mem_size))
dvander@2168
   443
	{
dvander@2168
   444
		return SP_ERROR_INVALID_ADDRESS;
dvander@2168
   445
	}
dvander@2168
   446
	
dvander@2168
   447
	if (maxbytes == 0)
dvander@2168
   448
	{
dvander@2168
   449
		return SP_ERROR_NONE;
dvander@2168
   450
	}
dvander@2168
   451
dvander@2168
   452
	len = strlen(source);
dvander@2171
   453
	dest = (char *)(m_pPlugin->memory + local_addr);
dvander@2168
   454
dvander@2168
   455
	if ((size_t)len >= maxbytes)
dvander@2168
   456
	{
dvander@2168
   457
		len = maxbytes - 1;
dvander@2168
   458
		needtocheck = true;
dvander@2168
   459
	}
dvander@2168
   460
dvander@2168
   461
	memmove(dest, source, len);
dvander@2168
   462
	if ((dest[len-1] & 1<<7) && needtocheck)
dvander@2168
   463
	{
dvander@2168
   464
		len -= __CheckValidChar(dest+len-1);
dvander@2168
   465
	}
dvander@2168
   466
	dest[len] = '\0';
dvander@2168
   467
dvander@2168
   468
	if (wrtnbytes)
dvander@2168
   469
	{
dvander@2168
   470
		*wrtnbytes = len;
dvander@2168
   471
	}
dvander@2168
   472
dvander@2168
   473
	return SP_ERROR_NONE;
dvander@2168
   474
}
dvander@2168
   475
dvander@2168
   476
IPluginFunction *BaseContext::GetFunctionById(funcid_t func_id)
dvander@2168
   477
{
dvander@2171
   478
	return m_pRuntime->GetFunctionById(func_id);
dvander@2168
   479
}
dvander@2168
   480
dvander@2168
   481
IPluginFunction *BaseContext::GetFunctionByName(const char *public_name)
dvander@2168
   482
{
dvander@2171
   483
	return m_pRuntime->GetFunctionByName(public_name);
dvander@2168
   484
}
dvander@2168
   485
dvander@2168
   486
int BaseContext::LocalToStringNULL(cell_t local_addr, char **addr)
dvander@2168
   487
{
dvander@2168
   488
	int err;
dvander@2168
   489
	if ((err = LocalToString(local_addr, addr)) != SP_ERROR_NONE)
dvander@2168
   490
	{
dvander@2168
   491
		return err;
dvander@2168
   492
	}
dvander@2168
   493
dvander@2168
   494
	if ((cell_t *)*addr == m_pNullString)
dvander@2168
   495
	{
dvander@2168
   496
		*addr = NULL;
dvander@2168
   497
	}
dvander@2168
   498
dvander@2168
   499
	return SP_ERROR_NONE;
dvander@2168
   500
}
dvander@2168
   501
dvander@2168
   502
SourceMod::IdentityToken_t *BaseContext::GetIdentity()
dvander@2168
   503
{
dvander@2168
   504
	return m_pToken;
dvander@2168
   505
}
dvander@2168
   506
dvander@2168
   507
void BaseContext::SetIdentity(SourceMod::IdentityToken_t *token)
dvander@2168
   508
{
dvander@2168
   509
	m_pToken = token;
dvander@2168
   510
}
dvander@2168
   511
dvander@2168
   512
cell_t *BaseContext::GetNullRef(SP_NULL_TYPE type)
dvander@2168
   513
{
dvander@2168
   514
	if (type == SP_NULL_VECTOR)
dvander@2168
   515
	{
dvander@2168
   516
		return m_pNullVec;
dvander@2168
   517
	}
dvander@2168
   518
dvander@2168
   519
	return NULL;
dvander@2168
   520
}
dvander@2168
   521
dvander@2168
   522
bool BaseContext::IsInExec()
dvander@2168
   523
{
dvander@2168
   524
	return m_InExec;
dvander@2168
   525
}
dvander@2171
   526
dvander@2171
   527
int BaseContext::Execute(IPluginFunction *function, const cell_t *params, unsigned int num_params, cell_t *result)
dvander@2171
   528
{
dvander@2171
   529
	int ir;
dvander@2171
   530
	int serial;
dvander@2171
   531
	cell_t *sp;
dvander@2171
   532
	funcid_t fnid;
dvander@2171
   533
	sp_public_t *pubfunc;
dvander@2171
   534
	cell_t _ignore_result;
dvander@2171
   535
dvander@2171
   536
	fnid = function->GetFunctionID();
dvander@2171
   537
dvander@2171
   538
	if (fnid & 1)
dvander@2171
   539
	{
dvander@2171
   540
		unsigned int public_id;
dvander@2171
   541
		
dvander@2171
   542
		public_id = fnid >> 1;
dvander@2171
   543
dvander@2171
   544
		if (m_pRuntime->GetPublicByIndex(public_id, &pubfunc) != SP_ERROR_NONE)
dvander@2171
   545
		{
dvander@2171
   546
			return SP_ERROR_NOT_FOUND;
dvander@2171
   547
		}
dvander@2171
   548
	}
dvander@2171
   549
	else
dvander@2171
   550
	{
dvander@2171
   551
		return SP_ERROR_INVALID_ADDRESS;
dvander@2171
   552
	}
dvander@2171
   553
dvander@2171
   554
	if (m_pRuntime->IsPaused())
dvander@2171
   555
	{
dvander@2171
   556
		return SP_ERROR_NOT_RUNNABLE;
dvander@2171
   557
	}
dvander@2171
   558
dvander@2171
   559
	if (m_ctx.hp + 16*sizeof(cell_t) > (cell_t)(m_ctx.sp - (sizeof(cell_t) * (num_params + 1))))
dvander@2171
   560
	{
dvander@2171
   561
		return SP_ERROR_STACKLOW;
dvander@2171
   562
	}
dvander@2171
   563
dvander@2171
   564
	if (result == NULL)
dvander@2171
   565
	{
dvander@2171
   566
		result = &_ignore_result;
dvander@2171
   567
	}
dvander@2171
   568
dvander@2171
   569
	/* We got this far.  It's time to start profiling. */
dvander@2171
   570
	
dvander@2171
   571
	if ((m_pPlugin->prof_flags & SP_PROF_CALLBACKS) == SP_PROF_CALLBACKS)
dvander@2171
   572
	{
dvander@2171
   573
		serial = m_pPlugin->profiler->OnCallbackBegin(this, pubfunc);
dvander@2171
   574
	}
dvander@2171
   575
dvander@2171
   576
	/* Save our previous state. */
dvander@2171
   577
dvander@2171
   578
	bool save_exec;
dvander@2171
   579
	uint32_t save_n_idx;
dvander@2171
   580
	cell_t save_sp, save_hp;
dvander@2171
   581
dvander@2171
   582
	save_sp = m_ctx.sp;
dvander@2171
   583
	save_hp = m_ctx.hp;
dvander@2171
   584
	save_exec = m_InExec;
dvander@2171
   585
	save_n_idx = m_ctx.n_idx;
dvander@2171
   586
dvander@2171
   587
	/* Push parameters */
dvander@2171
   588
dvander@2171
   589
	m_ctx.sp -= sizeof(cell_t) * (num_params + 1);
dvander@2171
   590
	sp = (cell_t *)(m_pPlugin->memory + m_ctx.sp);
dvander@2171
   591
dvander@2171
   592
	sp[0] = num_params;
dvander@2171
   593
	for (unsigned int i = 0; i < num_params; i++)
dvander@2171
   594
	{
dvander@2171
   595
		sp[i + 1] = params[i];
dvander@2171
   596
	}
dvander@2171
   597
dvander@2171
   598
	/* Clear internal state */
dvander@2171
   599
	m_ctx.n_err = SP_ERROR_NONE;
dvander@2171
   600
	m_ctx.n_idx = 0;
dvander@2171
   601
	m_MsgCache[0] = '\0';
dvander@2171
   602
	m_CustomMsg = false;
dvander@2171
   603
	m_InExec = false;
dvander@2171
   604
dvander@2171
   605
	/* Start the tracer */
dvander@2171
   606
dvander@2171
   607
	g_engine1.PushTracer(this);
dvander@2171
   608
dvander@2171
   609
	/* Execute the function */
dvander@2171
   610
dvander@2171
   611
	ir = g_Jit1.ContextExecute(m_pPlugin, &m_ctx, pubfunc->code_offs, result);
dvander@2171
   612
dvander@2171
   613
	/* Restore some states, stop tracing */
dvander@2171
   614
dvander@2171
   615
	m_InExec = save_exec;
dvander@2171
   616
dvander@2171
   617
	if (ir == SP_ERROR_NONE)
dvander@2171
   618
	{
dvander@2171
   619
		m_ctx.n_err = SP_ERROR_NONE;
dvander@2171
   620
		if (m_ctx.sp != save_sp)
dvander@2171
   621
		{
dvander@2171
   622
			ir = SP_ERROR_STACKLEAK;
dvander@2171
   623
			_SetErrorMessage("Stack leak detected: sp:%d should be %d!", 
dvander@2171
   624
				m_ctx.sp, 
dvander@2171
   625
				save_sp);
dvander@2171
   626
		}
dvander@2171
   627
		if (m_ctx.hp != save_hp)
dvander@2171
   628
		{
dvander@2171
   629
			ir = SP_ERROR_HEAPLEAK;
dvander@2171
   630
			_SetErrorMessage("Heap leak detected: hp:%d should be %d!", 
dvander@2171
   631
				m_ctx.hp, 
dvander@2171
   632
				save_hp);
dvander@2171
   633
		}
dvander@2171
   634
	}
dvander@2171
   635
dvander@2171
   636
	m_ctx.sp = save_sp;
dvander@2171
   637
	m_ctx.hp = save_hp;
dvander@2171
   638
dvander@2171
   639
	g_engine1.PopTracer(ir, m_CustomMsg ? m_MsgCache : NULL);
dvander@2171
   640
dvander@2171
   641
	if ((m_pPlugin->prof_flags & SP_PROF_CALLBACKS) == SP_PROF_CALLBACKS)
dvander@2171
   642
	{
dvander@2171
   643
		m_pPlugin->profiler->OnCallbackEnd(serial);
dvander@2171
   644
	}
dvander@2171
   645
dvander@2171
   646
	m_ctx.n_idx = save_n_idx;
dvander@2171
   647
	m_ctx.n_err = SP_ERROR_NONE;
dvander@2171
   648
	m_MsgCache[0] = '\0';
dvander@2171
   649
	m_CustomMsg = false;
dvander@2171
   650
dvander@2171
   651
	return ir;
dvander@2171
   652
}
dvander@2171
   653
dvander@2171
   654
IPluginRuntime *BaseContext::GetRuntime()
dvander@2171
   655
{
dvander@2171
   656
	return m_pRuntime;
dvander@2171
   657
}
dvander@2171
   658
dvander@2171
   659
int BaseRuntime::ApplyCompilationOptions(ICompilation *co)
dvander@2171
   660
{
dvander@2171
   661
	int err;
dvander@2171
   662
dvander@2171
   663
	/* The JIT does not destroy anything until it is guaranteed to succeed. */
dvander@2171
   664
	if (!g_Jit1.Compile(co, this, &err))
dvander@2171
   665
	{
dvander@2171
   666
		return err;
dvander@2171
   667
	}
dvander@2171
   668
dvander@2171
   669
	RefreshFunctionCache();
dvander@2171
   670
dvander@2171
   671
	return SP_ERROR_NONE;
dvander@2171
   672
}
dvander@2171
   673
dvander@2171
   674
DebugInfo::DebugInfo(sp_plugin_t *plugin) : m_pPlugin(plugin)
dvander@2171
   675
{
dvander@2171
   676
}
dvander@2171
   677
dvander@2171
   678
#define USHR(x) ((unsigned int)(x)>>1)
dvander@2171
   679
dvander@2171
   680
int DebugInfo::LookupFile(ucell_t addr, const char **filename)
dvander@2171
   681
{
dvander@2171
   682
	int high, low, mid;
dvander@2171
   683
dvander@2171
   684
	high = m_pPlugin->debug.files_num;
dvander@2171
   685
	low = -1;
dvander@2171
   686
dvander@2171
   687
	while (high - low > 1)
dvander@2171
   688
	{
dvander@2171
   689
		mid = USHR(low + high);
dvander@2171
   690
		if (m_pPlugin->files[mid].addr <= addr)
dvander@2171
   691
		{
dvander@2171
   692
			low = mid;
dvander@2171
   693
		} else {
dvander@2171
   694
			high = mid;
dvander@2171
   695
		}
dvander@2171
   696
	}
dvander@2171
   697
dvander@2171
   698
	if (low == -1)
dvander@2171
   699
	{
dvander@2171
   700
		return SP_ERROR_NOT_FOUND;
dvander@2171
   701
	}
dvander@2171
   702
dvander@2171
   703
	*filename = m_pPlugin->files[low].name;
dvander@2171
   704
dvander@2171
   705
	return SP_ERROR_NONE;
dvander@2171
   706
}
dvander@2171
   707
dvander@2171
   708
int DebugInfo::LookupFunction(ucell_t addr, const char **name)
dvander@2171
   709
{
dvander@2171
   710
	uint32_t iter, max = m_pPlugin->debug.syms_num;
dvander@2171
   711
dvander@2171
   712
	for (iter=0; iter<max; iter++)
dvander@2171
   713
	{
dvander@2171
   714
		if ((m_pPlugin->symbols[iter].sym->ident == SP_SYM_FUNCTION) 
dvander@2171
   715
			&& (m_pPlugin->symbols[iter].codestart <= addr) 
dvander@2171
   716
			&& (m_pPlugin->symbols[iter].codeend > addr))
dvander@2171
   717
		{
dvander@2171
   718
			break;
dvander@2171
   719
		}
dvander@2171
   720
	}
dvander@2171
   721
dvander@2171
   722
	if (iter >= max)
dvander@2171
   723
	{
dvander@2171
   724
		return SP_ERROR_NOT_FOUND;
dvander@2171
   725
	}
dvander@2171
   726
dvander@2171
   727
	*name = m_pPlugin->symbols[iter].name;
dvander@2171
   728
dvander@2171
   729
	return SP_ERROR_NONE;
dvander@2171
   730
}
dvander@2171
   731
dvander@2171
   732
int DebugInfo::LookupLine(ucell_t addr, uint32_t *line)
dvander@2171
   733
{
dvander@2171
   734
	int high, low, mid;
dvander@2171
   735
dvander@2171
   736
	high = m_pPlugin->debug.lines_num;
dvander@2171
   737
	low = -1;
dvander@2171
   738
dvander@2171
   739
	while (high - low > 1)
dvander@2171
   740
	{
dvander@2171
   741
		mid = USHR(low + high);
dvander@2171
   742
		if (m_pPlugin->lines[mid].addr <= addr)
dvander@2171
   743
		{
dvander@2171
   744
			low = mid;
dvander@2171
   745
		} else {
dvander@2171
   746
			high = mid;
dvander@2171
   747
		}
dvander@2171
   748
	}
dvander@2171
   749
dvander@2171
   750
	if (low == -1)
dvander@2171
   751
	{
dvander@2171
   752
		return SP_ERROR_NOT_FOUND;
dvander@2171
   753
	}
dvander@2171
   754
dvander@2171
   755
	/* Since the CIP occurs BEFORE the line, we have to add one */
dvander@2171
   756
	*line = m_pPlugin->lines[low].line + 1;
dvander@2171
   757
dvander@2171
   758
	return SP_ERROR_NONE;
dvander@2171
   759
}
dvander@2171
   760
dvander@2171
   761
#undef USHR
dvander@2173
   762
dvander@2173
   763
int BaseContext::GetLastNativeError()
dvander@2173
   764
{
dvander@2173
   765
	return m_ctx.n_err;
dvander@2173
   766
}
dvander@2173
   767
dvander@2173
   768
cell_t *BaseContext::GetLocalParams()
dvander@2173
   769
{
dvander@2173
   770
	return (cell_t *)(m_pPlugin->memory + m_ctx.frm + (2 * sizeof(cell_t)));
dvander@2173
   771
}
dvander@2174
   772
dvander@2174
   773
void BaseContext::SetKey(int k, void *value)
dvander@2174
   774
{
dvander@2174
   775
	if (k < 1 || k > 4)
dvander@2174
   776
	{
dvander@2174
   777
		return;
dvander@2174
   778
	}
dvander@2174
   779
dvander@2174
   780
	m_keys[k - 1] = value;
dvander@2174
   781
	m_keys_set[k - 1] = true;
dvander@2174
   782
}
dvander@2174
   783
dvander@2174
   784
bool BaseContext::GetKey(int k, void **value)
dvander@2174
   785
{
dvander@2174
   786
	if (k < 1 || k > 4 || m_keys_set[k - 1] == false)
dvander@2174
   787
	{
dvander@2174
   788
		return false;
dvander@2174
   789
	}
dvander@2174
   790
dvander@2174
   791
	*value = m_keys[k - 1];
dvander@2174
   792
dvander@2174
   793
	return true;
dvander@2174
   794
}