sourcepawn/jit/sp_vm_basecontext.cpp
author David Anderson <danderson@mozilla.com>
Thu Aug 08 09:41:24 2013 -0700 (2013-08-08)
changeset 3977 fca2b54741ca
parent 2545 9cb1a1fefc2c
child 3990 c7fb79059d7a
permissions -rw-r--r--
Refactor the JIT to use a newer, simpler macro assembler. (bug 5827, r=ann)
dvander@2193
     1
/**
danderson@3977
     2
 * vim: set ts=4 sw=4 tw=99 noet:
dvander@2193
     3
 * =============================================================================
dvander@2193
     4
 * SourcePawn
dvander@2193
     5
 * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
dvander@2193
     6
 * =============================================================================
dvander@2193
     7
 *
dvander@2193
     8
 * This program is free software; you can redistribute it and/or modify it under
dvander@2193
     9
 * the terms of the GNU General Public License, version 3.0, as published by the
dvander@2193
    10
 * Free Software Foundation.
dvander@2193
    11
 * 
dvander@2193
    12
 * This program is distributed in the hope that it will be useful, but WITHOUT
dvander@2193
    13
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
dvander@2193
    14
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
dvander@2193
    15
 * details.
dvander@2193
    16
 *
dvander@2193
    17
 * You should have received a copy of the GNU General Public License along with
dvander@2193
    18
 * this program.  If not, see <http://www.gnu.org/licenses/>.
dvander@2193
    19
 *
dvander@2193
    20
 * As a special exception, AlliedModders LLC gives you permission to link the
dvander@2193
    21
 * code of this program (as well as its derivative works) to "Half-Life 2," the
dvander@2193
    22
 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
dvander@2193
    23
 * by the Valve Corporation.  You must obey the GNU General Public License in
dvander@2193
    24
 * all respects for all other code used.  Additionally, AlliedModders LLC grants
dvander@2193
    25
 * this exception to all derivative works.  AlliedModders LLC defines further
dvander@2193
    26
 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
dvander@2193
    27
 * or <http://www.sourcemod.net/license.php>.
dvander@2193
    28
 *
dvander@2193
    29
 * Version: $Id$
dvander@2193
    30
 */
dvander@2193
    31
dvander@2193
    32
#include <string.h>
dvander@2193
    33
#include <stdarg.h>
dvander@2193
    34
#include <assert.h>
dvander@2193
    35
#include <limits.h>
dvander@2193
    36
#include "sp_vm_api.h"
dvander@2193
    37
#include "sp_vm_basecontext.h"
dvander@2193
    38
#include "sp_vm_engine.h"
dvander@2193
    39
#include "x86/jit_x86.h"
dvander@2193
    40
dvander@2193
    41
using namespace SourcePawn;
dvander@2193
    42
dvander@2193
    43
#define CELLBOUNDMAX	(INT_MAX/sizeof(cell_t))
dvander@2193
    44
#define STACKMARGIN		((cell_t)(16*sizeof(cell_t)))
dvander@2193
    45
dvander@2193
    46
BaseContext::BaseContext(BaseRuntime *pRuntime)
dvander@2193
    47
{
dvander@2193
    48
	m_pRuntime = pRuntime;
dvander@2193
    49
dvander@2193
    50
	m_InExec = false;
dvander@2193
    51
	m_CustomMsg = false;
dvander@2193
    52
dvander@2226
    53
	/* Initialize the null references */
dvander@2226
    54
	uint32_t index;
dvander@2226
    55
	if (FindPubvarByName("NULL_VECTOR", &index) == SP_ERROR_NONE)
dvander@2226
    56
	{
dvander@2226
    57
		sp_pubvar_t *pubvar;
dvander@2226
    58
		GetPubvarByIndex(index, &pubvar);
dvander@2226
    59
		m_pNullVec = pubvar->offs;
dvander@2226
    60
	}
dvander@2226
    61
	else
dvander@2226
    62
	{
dvander@2226
    63
		m_pNullVec = NULL;
dvander@2226
    64
	}
dvander@2226
    65
dvander@2226
    66
	if (FindPubvarByName("NULL_STRING", &index) == SP_ERROR_NONE)
dvander@2226
    67
	{
dvander@2226
    68
		sp_pubvar_t *pubvar;
dvander@2226
    69
		GetPubvarByIndex(index, &pubvar);
dvander@2226
    70
		m_pNullString = pubvar->offs;
dvander@2226
    71
	}
dvander@2226
    72
	else
dvander@2226
    73
	{
dvander@2226
    74
		m_pNullString = NULL;
dvander@2226
    75
	}
dvander@2226
    76
danderson@3977
    77
	m_ctx.hp = m_pRuntime->plugin()->data_size;
danderson@3977
    78
	m_ctx.sp = m_pRuntime->plugin()->mem_size - sizeof(cell_t);
dvander@2226
    79
	m_ctx.frm = m_ctx.sp;
dvander@2226
    80
	m_ctx.n_err = SP_ERROR_NONE;
dvander@2226
    81
	m_ctx.n_idx = SP_ERROR_NONE;
dvander@2226
    82
	m_ctx.rp = 0;
dvander@2226
    83
dvander@2226
    84
	g_Jit.SetupContextVars(m_pRuntime, this, &m_ctx);
dvander@2193
    85
}
dvander@2193
    86
dvander@2193
    87
BaseContext::~BaseContext()
dvander@2193
    88
{
dvander@2226
    89
	g_Jit.FreeContextVars(&m_ctx);
dvander@2193
    90
}
dvander@2193
    91
dvander@2193
    92
IVirtualMachine *BaseContext::GetVirtualMachine()
dvander@2193
    93
{
dvander@2193
    94
	return NULL;
dvander@2193
    95
}
dvander@2193
    96
dvander@2193
    97
sp_context_t *BaseContext::GetContext()
dvander@2193
    98
{
dvander@2193
    99
	return reinterpret_cast<sp_context_t *>((IPluginContext * )this);
dvander@2193
   100
}
dvander@2193
   101
dvander@2193
   102
sp_context_t *BaseContext::GetCtx()
dvander@2193
   103
{
dvander@2193
   104
	return &m_ctx;
dvander@2193
   105
}
dvander@2193
   106
dvander@2193
   107
bool BaseContext::IsDebugging()
dvander@2193
   108
{
dvander@2226
   109
	return true;
dvander@2193
   110
}
dvander@2193
   111
dvander@2193
   112
int BaseContext::SetDebugBreak(void *newpfn, void *oldpfn)
dvander@2193
   113
{
dvander@2193
   114
	return SP_ERROR_ABORTED;
dvander@2193
   115
}
dvander@2193
   116
dvander@2193
   117
IPluginDebugInfo *BaseContext::GetDebugInfo()
dvander@2193
   118
{
dvander@2193
   119
	return NULL;
dvander@2193
   120
}
dvander@2193
   121
dvander@2193
   122
int BaseContext::Execute(uint32_t code_addr, cell_t *result)
dvander@2193
   123
{
dvander@2193
   124
	return SP_ERROR_ABORTED;
dvander@2193
   125
}
dvander@2193
   126
dvander@2193
   127
void BaseContext::SetErrorMessage(const char *msg, va_list ap)
dvander@2193
   128
{
dvander@2193
   129
	m_CustomMsg = true;
dvander@2193
   130
dvander@2193
   131
	vsnprintf(m_MsgCache, sizeof(m_MsgCache), msg, ap);
dvander@2193
   132
}
dvander@2193
   133
dvander@2193
   134
void BaseContext::_SetErrorMessage(const char *msg, ...)
dvander@2193
   135
{
dvander@2193
   136
	va_list ap;
dvander@2193
   137
	va_start(ap, msg);
dvander@2193
   138
	SetErrorMessage(msg, ap);
dvander@2193
   139
	va_end(ap);
dvander@2193
   140
}
dvander@2193
   141
dvander@2193
   142
cell_t BaseContext::ThrowNativeErrorEx(int error, const char *msg, ...)
dvander@2193
   143
{
dvander@2193
   144
	if (!m_InExec)
dvander@2193
   145
	{
dvander@2193
   146
		return 0;
dvander@2193
   147
	}
dvander@2193
   148
dvander@2193
   149
	m_ctx.n_err = error;
dvander@2193
   150
	
dvander@2193
   151
	if (msg)
dvander@2193
   152
	{
dvander@2193
   153
		va_list ap;
dvander@2193
   154
		va_start(ap, msg);
dvander@2193
   155
		SetErrorMessage(msg, ap);
dvander@2193
   156
		va_end(ap);
dvander@2193
   157
	}
dvander@2193
   158
dvander@2193
   159
	return 0;
dvander@2193
   160
}
dvander@2193
   161
dvander@2193
   162
cell_t BaseContext::ThrowNativeError(const char *msg, ...)
dvander@2193
   163
{
dvander@2193
   164
	if (!m_InExec)
dvander@2193
   165
	{
dvander@2193
   166
		return 0;
dvander@2193
   167
	}
dvander@2193
   168
dvander@2193
   169
	m_ctx.n_err = SP_ERROR_NATIVE;
dvander@2193
   170
dvander@2193
   171
	if (msg)
dvander@2193
   172
	{
dvander@2193
   173
		va_list ap;
dvander@2193
   174
		va_start(ap, msg);
dvander@2193
   175
		SetErrorMessage(msg, ap);
dvander@2193
   176
		va_end(ap);
dvander@2193
   177
	}
dvander@2193
   178
dvander@2193
   179
	return 0;
dvander@2193
   180
}
dvander@2193
   181
dvander@2193
   182
int BaseContext::HeapAlloc(unsigned int cells, cell_t *local_addr, cell_t **phys_addr)
dvander@2193
   183
{
dvander@2193
   184
	cell_t *addr;
dvander@2193
   185
	ucell_t realmem;
dvander@2193
   186
dvander@2193
   187
#if 0
dvander@2193
   188
	if (cells > CELLBOUNDMAX)
dvander@2193
   189
	{
dvander@2193
   190
		return SP_ERROR_ARAM;
dvander@2193
   191
	}
dvander@2193
   192
#else
dvander@2193
   193
	assert(cells < CELLBOUNDMAX);
dvander@2193
   194
#endif
dvander@2193
   195
dvander@2193
   196
	realmem = cells * sizeof(cell_t);
dvander@2193
   197
dvander@2193
   198
	/**
dvander@2193
   199
	 * Check if the space between the heap and stack is sufficient.
dvander@2193
   200
	 */
dvander@2193
   201
	if ((cell_t)(m_ctx.sp - m_ctx.hp - realmem) < STACKMARGIN)
dvander@2193
   202
	{
dvander@2193
   203
		return SP_ERROR_HEAPLOW;
dvander@2193
   204
	}
dvander@2193
   205
danderson@3977
   206
	addr = (cell_t *)(m_pRuntime->plugin()->memory + m_ctx.hp);
dvander@2193
   207
	/* store size of allocation in cells */
dvander@2193
   208
	*addr = (cell_t)cells;
dvander@2193
   209
	addr++;
dvander@2193
   210
	m_ctx.hp += sizeof(cell_t);
dvander@2193
   211
dvander@2193
   212
	*local_addr = m_ctx.hp;
dvander@2193
   213
dvander@2193
   214
	if (phys_addr)
dvander@2193
   215
	{
dvander@2193
   216
		*phys_addr = addr;
dvander@2193
   217
	}
dvander@2193
   218
dvander@2193
   219
	m_ctx.hp += realmem;
dvander@2193
   220
dvander@2193
   221
	return SP_ERROR_NONE;
dvander@2193
   222
}
dvander@2193
   223
dvander@2193
   224
int BaseContext::HeapPop(cell_t local_addr)
dvander@2193
   225
{
dvander@2193
   226
	cell_t cellcount;
dvander@2193
   227
	cell_t *addr;
dvander@2193
   228
dvander@2193
   229
	/* check the bounds of this address */
dvander@2193
   230
	local_addr -= sizeof(cell_t);
danderson@3977
   231
	if (local_addr < (cell_t)m_pRuntime->plugin()->data_size || local_addr >= m_ctx.sp)
dvander@2193
   232
	{
dvander@2193
   233
		return SP_ERROR_INVALID_ADDRESS;
dvander@2193
   234
	}
dvander@2193
   235
danderson@3977
   236
	addr = (cell_t *)(m_pRuntime->plugin()->memory + local_addr);
dvander@2193
   237
	cellcount = (*addr) * sizeof(cell_t);
dvander@2193
   238
	/* check if this memory count looks valid */
dvander@2193
   239
	if ((signed)(m_ctx.hp - cellcount - sizeof(cell_t)) != local_addr)
dvander@2193
   240
	{
dvander@2193
   241
		return SP_ERROR_INVALID_ADDRESS;
dvander@2193
   242
	}
dvander@2193
   243
dvander@2193
   244
	m_ctx.hp = local_addr;
dvander@2193
   245
dvander@2193
   246
	return SP_ERROR_NONE;
dvander@2193
   247
}
dvander@2193
   248
dvander@2193
   249
dvander@2193
   250
int BaseContext::HeapRelease(cell_t local_addr)
dvander@2193
   251
{
danderson@3977
   252
	if (local_addr < (cell_t)m_pRuntime->plugin()->data_size)
dvander@2193
   253
	{
dvander@2193
   254
		return SP_ERROR_INVALID_ADDRESS;
dvander@2193
   255
	}
dvander@2193
   256
dvander@2193
   257
	m_ctx.hp = local_addr - sizeof(cell_t);
dvander@2193
   258
dvander@2193
   259
	return SP_ERROR_NONE;
dvander@2193
   260
}
dvander@2193
   261
dvander@2193
   262
int BaseContext::FindNativeByName(const char *name, uint32_t *index)
dvander@2193
   263
{
dvander@2193
   264
	return m_pRuntime->FindNativeByName(name, index);
dvander@2193
   265
}
dvander@2193
   266
dvander@2193
   267
int BaseContext::GetNativeByIndex(uint32_t index, sp_native_t **native)
dvander@2193
   268
{
dvander@2193
   269
	return m_pRuntime->GetNativeByIndex(index, native);
dvander@2193
   270
}
dvander@2193
   271
dvander@2193
   272
dvander@2193
   273
uint32_t BaseContext::GetNativesNum()
dvander@2193
   274
{
dvander@2193
   275
	return m_pRuntime->GetNativesNum();
dvander@2193
   276
}
dvander@2193
   277
dvander@2193
   278
int BaseContext::FindPublicByName(const char *name, uint32_t *index)
dvander@2193
   279
{
dvander@2193
   280
	return m_pRuntime->FindPublicByName(name, index);
dvander@2193
   281
}
dvander@2193
   282
dvander@2193
   283
int BaseContext::GetPublicByIndex(uint32_t index, sp_public_t **pblic)
dvander@2193
   284
{
dvander@2193
   285
	return m_pRuntime->GetPublicByIndex(index, pblic);
dvander@2193
   286
}
dvander@2193
   287
dvander@2193
   288
uint32_t BaseContext::GetPublicsNum()
dvander@2193
   289
{
dvander@2193
   290
	return m_pRuntime->GetPublicsNum();
dvander@2193
   291
}
dvander@2193
   292
dvander@2193
   293
int BaseContext::GetPubvarByIndex(uint32_t index, sp_pubvar_t **pubvar)
dvander@2193
   294
{
dvander@2193
   295
	return m_pRuntime->GetPubvarByIndex(index, pubvar);
dvander@2193
   296
}
dvander@2193
   297
dvander@2193
   298
int BaseContext::FindPubvarByName(const char *name, uint32_t *index)
dvander@2193
   299
{
dvander@2193
   300
	return m_pRuntime->FindPubvarByName(name, index);
dvander@2193
   301
}
dvander@2193
   302
dvander@2193
   303
int BaseContext::GetPubvarAddrs(uint32_t index, cell_t *local_addr, cell_t **phys_addr)
dvander@2193
   304
{
dvander@2193
   305
	return m_pRuntime->GetPubvarAddrs(index, local_addr, phys_addr);
dvander@2193
   306
}
dvander@2193
   307
dvander@2193
   308
uint32_t BaseContext::GetPubVarsNum()
dvander@2193
   309
{
dvander@2193
   310
	return m_pRuntime->GetPubVarsNum();
dvander@2193
   311
}
dvander@2193
   312
dvander@2193
   313
int BaseContext::BindNatives(const sp_nativeinfo_t *natives, unsigned int num, int overwrite)
dvander@2193
   314
{
dvander@2193
   315
	return SP_ERROR_ABORTED;
dvander@2193
   316
}
dvander@2193
   317
dvander@2193
   318
int BaseContext::BindNative(const sp_nativeinfo_t *native)
dvander@2193
   319
{
dvander@2193
   320
	return SP_ERROR_ABORTED;
dvander@2193
   321
}
dvander@2193
   322
dvander@2193
   323
int BaseContext::BindNativeToIndex(uint32_t index, SPVM_NATIVE_FUNC func)
dvander@2193
   324
{
dvander@2193
   325
	return SP_ERROR_ABORTED;
dvander@2193
   326
}
dvander@2193
   327
dvander@2193
   328
int BaseContext::BindNativeToAny(SPVM_NATIVE_FUNC native)
dvander@2193
   329
{
dvander@2193
   330
	return SP_ERROR_ABORTED;
dvander@2193
   331
}
dvander@2193
   332
dvander@2193
   333
int BaseContext::LocalToPhysAddr(cell_t local_addr, cell_t **phys_addr)
dvander@2193
   334
{
dvander@2193
   335
	if (((local_addr >= m_ctx.hp) && (local_addr < m_ctx.sp)) 
danderson@3977
   336
		|| (local_addr < 0) || ((ucell_t)local_addr >= m_pRuntime->plugin()->mem_size))
dvander@2193
   337
	{
dvander@2193
   338
		return SP_ERROR_INVALID_ADDRESS;
dvander@2193
   339
	}
dvander@2193
   340
dvander@2193
   341
	if (phys_addr)
dvander@2193
   342
	{
danderson@3977
   343
		*phys_addr = (cell_t *)(m_pRuntime->plugin()->memory + local_addr);
dvander@2193
   344
	}
dvander@2193
   345
dvander@2193
   346
	return SP_ERROR_NONE;
dvander@2193
   347
}
dvander@2193
   348
dvander@2193
   349
int BaseContext::PushCell(cell_t value)
dvander@2193
   350
{
dvander@2193
   351
	return SP_ERROR_ABORTED;
dvander@2193
   352
}
dvander@2193
   353
dvander@2193
   354
int BaseContext::PushCellsFromArray(cell_t array[], unsigned int numcells)
dvander@2193
   355
{
dvander@2193
   356
	return SP_ERROR_ABORTED;
dvander@2193
   357
}
dvander@2193
   358
dvander@2193
   359
int BaseContext::PushCellArray(cell_t *local_addr, cell_t **phys_addr, cell_t array[], unsigned int numcells)
dvander@2193
   360
{
dvander@2193
   361
	return SP_ERROR_ABORTED;
dvander@2193
   362
}
dvander@2193
   363
dvander@2193
   364
int BaseContext::LocalToString(cell_t local_addr, char **addr)
dvander@2193
   365
{
dvander@2193
   366
	if (((local_addr >= m_ctx.hp) && (local_addr < m_ctx.sp))
danderson@3977
   367
		|| (local_addr < 0) || ((ucell_t)local_addr >= m_pRuntime->plugin()->mem_size))
dvander@2193
   368
	{
dvander@2193
   369
		return SP_ERROR_INVALID_ADDRESS;
dvander@2193
   370
	}
danderson@3977
   371
	*addr = (char *)(m_pRuntime->plugin()->memory + local_addr);
dvander@2193
   372
dvander@2193
   373
	return SP_ERROR_NONE;
dvander@2193
   374
}
dvander@2193
   375
dvander@2193
   376
int BaseContext::PushString(cell_t *local_addr, char **phys_addr, const char *string)
dvander@2193
   377
{
dvander@2193
   378
	return SP_ERROR_ABORTED;
dvander@2193
   379
}
dvander@2193
   380
dvander@2193
   381
int BaseContext::StringToLocal(cell_t local_addr, size_t bytes, const char *source)
dvander@2193
   382
{
dvander@2193
   383
	char *dest;
dvander@2193
   384
	size_t len;
dvander@2193
   385
dvander@2193
   386
	if (((local_addr >= m_ctx.hp) && (local_addr < m_ctx.sp))
danderson@3977
   387
		|| (local_addr < 0) || ((ucell_t)local_addr >= m_pRuntime->plugin()->mem_size))
dvander@2193
   388
	{
dvander@2193
   389
		return SP_ERROR_INVALID_ADDRESS;
dvander@2193
   390
	}
dvander@2193
   391
dvander@2193
   392
	if (bytes == 0)
dvander@2193
   393
	{
dvander@2193
   394
		return SP_ERROR_NONE;
dvander@2193
   395
	}
dvander@2193
   396
dvander@2193
   397
	len = strlen(source);
danderson@3977
   398
	dest = (char *)(m_pRuntime->plugin()->memory + local_addr);
dvander@2193
   399
dvander@2193
   400
	if (len >= bytes)
dvander@2193
   401
	{
dvander@2193
   402
		len = bytes - 1;
dvander@2193
   403
	}
dvander@2193
   404
dvander@2193
   405
	memmove(dest, source, len);
dvander@2193
   406
	dest[len] = '\0';
dvander@2193
   407
dvander@2193
   408
	return SP_ERROR_NONE;
dvander@2193
   409
}
dvander@2193
   410
dvander@2193
   411
inline int __CheckValidChar(char *c)
dvander@2193
   412
{
dvander@2193
   413
	int count;
dvander@2193
   414
	int bytecount = 0;
dvander@2193
   415
dvander@2193
   416
	for (count=1; (*c & 0xC0) == 0x80; count++)
dvander@2193
   417
	{
dvander@2193
   418
		c--;
dvander@2193
   419
	}
dvander@2193
   420
dvander@2193
   421
	switch (*c & 0xF0)
dvander@2193
   422
	{
dvander@2193
   423
	case 0xC0:
dvander@2193
   424
	case 0xD0:
dvander@2193
   425
		{
dvander@2193
   426
			bytecount = 2;
dvander@2193
   427
			break;
dvander@2193
   428
		}
dvander@2193
   429
	case 0xE0:
dvander@2193
   430
		{
dvander@2193
   431
			bytecount = 3;
dvander@2193
   432
			break;
dvander@2193
   433
		}
dvander@2193
   434
	case 0xF0:
dvander@2193
   435
		{
dvander@2193
   436
			bytecount = 4;
dvander@2193
   437
			break;
dvander@2193
   438
		}
dvander@2193
   439
	}
dvander@2193
   440
dvander@2193
   441
	if (bytecount != count)
dvander@2193
   442
	{
dvander@2193
   443
		return count;
dvander@2193
   444
	}
dvander@2193
   445
dvander@2193
   446
	return 0;
dvander@2193
   447
}
dvander@2193
   448
dvander@2193
   449
int BaseContext::StringToLocalUTF8(cell_t local_addr, size_t maxbytes, const char *source, size_t *wrtnbytes)
dvander@2193
   450
{
dvander@2193
   451
	char *dest;
dvander@2193
   452
	size_t len;
dvander@2193
   453
	bool needtocheck = false;
dvander@2193
   454
dvander@2193
   455
	if (((local_addr >= m_ctx.hp) && (local_addr < m_ctx.sp))
dvander@2193
   456
		|| (local_addr < 0)
danderson@3977
   457
		|| ((ucell_t)local_addr >= m_pRuntime->plugin()->mem_size))
dvander@2193
   458
	{
dvander@2193
   459
		return SP_ERROR_INVALID_ADDRESS;
dvander@2193
   460
	}
dvander@2193
   461
	
dvander@2193
   462
	if (maxbytes == 0)
dvander@2193
   463
	{
dvander@2193
   464
		return SP_ERROR_NONE;
dvander@2193
   465
	}
dvander@2193
   466
dvander@2193
   467
	len = strlen(source);
danderson@3977
   468
	dest = (char *)(m_pRuntime->plugin()->memory + local_addr);
dvander@2193
   469
dvander@2193
   470
	if ((size_t)len >= maxbytes)
dvander@2193
   471
	{
dvander@2193
   472
		len = maxbytes - 1;
dvander@2193
   473
		needtocheck = true;
dvander@2193
   474
	}
dvander@2193
   475
dvander@2193
   476
	memmove(dest, source, len);
dvander@2193
   477
	if ((dest[len-1] & 1<<7) && needtocheck)
dvander@2193
   478
	{
dvander@2193
   479
		len -= __CheckValidChar(dest+len-1);
dvander@2193
   480
	}
dvander@2193
   481
	dest[len] = '\0';
dvander@2193
   482
dvander@2193
   483
	if (wrtnbytes)
dvander@2193
   484
	{
dvander@2193
   485
		*wrtnbytes = len;
dvander@2193
   486
	}
dvander@2193
   487
dvander@2193
   488
	return SP_ERROR_NONE;
dvander@2193
   489
}
dvander@2193
   490
dvander@2193
   491
IPluginFunction *BaseContext::GetFunctionById(funcid_t func_id)
dvander@2193
   492
{
dvander@2193
   493
	return m_pRuntime->GetFunctionById(func_id);
dvander@2193
   494
}
dvander@2193
   495
dvander@2193
   496
IPluginFunction *BaseContext::GetFunctionByName(const char *public_name)
dvander@2193
   497
{
dvander@2193
   498
	return m_pRuntime->GetFunctionByName(public_name);
dvander@2193
   499
}
dvander@2193
   500
dvander@2193
   501
int BaseContext::LocalToStringNULL(cell_t local_addr, char **addr)
dvander@2193
   502
{
dvander@2193
   503
	int err;
dvander@2193
   504
	if ((err = LocalToString(local_addr, addr)) != SP_ERROR_NONE)
dvander@2193
   505
	{
dvander@2193
   506
		return err;
dvander@2193
   507
	}
dvander@2193
   508
dvander@2193
   509
	if ((cell_t *)*addr == m_pNullString)
dvander@2193
   510
	{
dvander@2193
   511
		*addr = NULL;
dvander@2193
   512
	}
dvander@2193
   513
dvander@2193
   514
	return SP_ERROR_NONE;
dvander@2193
   515
}
dvander@2193
   516
dvander@2193
   517
SourceMod::IdentityToken_t *BaseContext::GetIdentity()
dvander@2193
   518
{
dvander@2193
   519
	SourceMod::IdentityToken_t *tok;
dvander@2193
   520
dvander@2193
   521
	if (GetKey(1, (void **)&tok))
dvander@2193
   522
	{
dvander@2193
   523
		return tok;
dvander@2193
   524
	}
dvander@2193
   525
dvander@2193
   526
	return NULL;
dvander@2193
   527
}
dvander@2193
   528
dvander@2193
   529
cell_t *BaseContext::GetNullRef(SP_NULL_TYPE type)
dvander@2193
   530
{
dvander@2193
   531
	if (type == SP_NULL_VECTOR)
dvander@2193
   532
	{
dvander@2193
   533
		return m_pNullVec;
dvander@2193
   534
	}
dvander@2193
   535
dvander@2193
   536
	return NULL;
dvander@2193
   537
}
dvander@2193
   538
dvander@2193
   539
bool BaseContext::IsInExec()
dvander@2193
   540
{
dvander@2193
   541
	return m_InExec;
dvander@2193
   542
}
dvander@2193
   543
dvander@2193
   544
int BaseContext::Execute2(IPluginFunction *function, const cell_t *params, unsigned int num_params, cell_t *result)
dvander@2193
   545
{
dvander@2193
   546
	int ir;
dvander@2193
   547
	int serial;
dvander@2193
   548
	cell_t *sp;
dvander@2193
   549
	funcid_t fnid;
dvander@2226
   550
	JitFunction *fn;
dvander@2193
   551
	sp_public_t *pubfunc;
dvander@2193
   552
	cell_t _ignore_result;
dvander@2226
   553
	unsigned int public_id;
dvander@2193
   554
dvander@2193
   555
	fnid = function->GetFunctionID();
dvander@2193
   556
dvander@2193
   557
	if (fnid & 1)
dvander@2226
   558
	{	
dvander@2193
   559
		public_id = fnid >> 1;
dvander@2193
   560
dvander@2193
   561
		if (m_pRuntime->GetPublicByIndex(public_id, &pubfunc) != SP_ERROR_NONE)
dvander@2193
   562
		{
dvander@2193
   563
			return SP_ERROR_NOT_FOUND;
dvander@2193
   564
		}
dvander@2193
   565
	}
dvander@2193
   566
	else
dvander@2193
   567
	{
dvander@2193
   568
		return SP_ERROR_INVALID_ADDRESS;
dvander@2193
   569
	}
dvander@2193
   570
dvander@2193
   571
	if (m_pRuntime->IsPaused())
dvander@2193
   572
	{
dvander@2193
   573
		return SP_ERROR_NOT_RUNNABLE;
dvander@2193
   574
	}
dvander@2193
   575
dvander@2193
   576
	if ((cell_t)(m_ctx.hp + 16*sizeof(cell_t)) > (cell_t)(m_ctx.sp - (sizeof(cell_t) * (num_params + 1))))
dvander@2193
   577
	{
dvander@2193
   578
		return SP_ERROR_STACKLOW;
dvander@2193
   579
	}
dvander@2193
   580
dvander@2193
   581
	if (result == NULL)
dvander@2193
   582
	{
dvander@2193
   583
		result = &_ignore_result;
dvander@2193
   584
	}
dvander@2193
   585
dvander@2193
   586
	/* We got this far.  It's time to start profiling. */
dvander@2193
   587
	
danderson@3977
   588
	if ((m_pRuntime->plugin()->prof_flags & SP_PROF_CALLBACKS) == SP_PROF_CALLBACKS)
dvander@2193
   589
	{
danderson@3977
   590
		serial = m_pRuntime->plugin()->profiler->OnCallbackBegin(this, pubfunc);
dvander@2193
   591
	}
dvander@2193
   592
dvander@2226
   593
	/* See if we have to compile the callee. */
dvander@2226
   594
	if ((fn = m_pRuntime->m_PubJitFuncs[public_id]) == NULL)
dvander@2226
   595
	{
dvander@2226
   596
		/* We might not have to - check pcode offset. */
danderson@3977
   597
		fn = m_pRuntime->GetJittedFunctionByOffset(pubfunc->code_offs);
danderson@3977
   598
		if (fn)
dvander@2226
   599
		{
dvander@2226
   600
			m_pRuntime->m_PubJitFuncs[public_id] = fn;
dvander@2226
   601
		}
dvander@2226
   602
		else
dvander@2226
   603
		{
dvander@2226
   604
			if ((fn = g_Jit.CompileFunction(m_pRuntime, pubfunc->code_offs, &ir)) == NULL)
dvander@2226
   605
			{
dvander@2226
   606
				return ir;
dvander@2226
   607
			}
dvander@2226
   608
			m_pRuntime->m_PubJitFuncs[public_id] = fn;
dvander@2226
   609
		}
dvander@2226
   610
	}
dvander@2226
   611
dvander@2193
   612
	/* Save our previous state. */
dvander@2193
   613
dvander@2193
   614
	bool save_exec;
dvander@2193
   615
	uint32_t save_n_idx;
dvander@2226
   616
	cell_t save_sp, save_hp, save_rp, save_cip;
dvander@2193
   617
dvander@2193
   618
	save_sp = m_ctx.sp;
dvander@2193
   619
	save_hp = m_ctx.hp;
dvander@2193
   620
	save_exec = m_InExec;
dvander@2193
   621
	save_n_idx = m_ctx.n_idx;
dvander@2226
   622
	save_rp = m_ctx.rp;
dvander@2226
   623
	save_cip = m_ctx.err_cip;
dvander@2193
   624
dvander@2193
   625
	/* Push parameters */
dvander@2193
   626
dvander@2193
   627
	m_ctx.sp -= sizeof(cell_t) * (num_params + 1);
danderson@3977
   628
	sp = (cell_t *)(m_pRuntime->plugin()->memory + m_ctx.sp);
dvander@2193
   629
dvander@2193
   630
	sp[0] = num_params;
dvander@2193
   631
	for (unsigned int i = 0; i < num_params; i++)
dvander@2193
   632
	{
dvander@2193
   633
		sp[i + 1] = params[i];
dvander@2193
   634
	}
dvander@2193
   635
dvander@2193
   636
	/* Clear internal state */
dvander@2193
   637
	m_ctx.n_err = SP_ERROR_NONE;
dvander@2193
   638
	m_ctx.n_idx = 0;
dvander@2193
   639
	m_MsgCache[0] = '\0';
dvander@2193
   640
	m_CustomMsg = false;
dvander@2214
   641
	m_InExec = true;
dvander@2193
   642
dvander@2226
   643
	/* Start the frame tracer */
dvander@2193
   644
dvander@2226
   645
	ir = g_Jit.InvokeFunction(m_pRuntime, fn, result);
dvander@2193
   646
dvander@2226
   647
	/* Restore some states, stop the frame tracer */
dvander@2193
   648
dvander@2193
   649
	m_InExec = save_exec;
dvander@2193
   650
dvander@2193
   651
	if (ir == SP_ERROR_NONE)
dvander@2193
   652
	{
dvander@2193
   653
		m_ctx.n_err = SP_ERROR_NONE;
dvander@2193
   654
		if (m_ctx.sp != save_sp)
dvander@2193
   655
		{
dvander@2193
   656
			ir = SP_ERROR_STACKLEAK;
dvander@2193
   657
			_SetErrorMessage("Stack leak detected: sp:%d should be %d!", 
dvander@2193
   658
				m_ctx.sp, 
dvander@2193
   659
				save_sp);
dvander@2193
   660
		}
dvander@2193
   661
		if (m_ctx.hp != save_hp)
dvander@2193
   662
		{
dvander@2193
   663
			ir = SP_ERROR_HEAPLEAK;
dvander@2193
   664
			_SetErrorMessage("Heap leak detected: hp:%d should be %d!", 
dvander@2193
   665
				m_ctx.hp, 
dvander@2193
   666
				save_hp);
dvander@2193
   667
		}
dvander@2226
   668
		if (m_ctx.rp != save_rp)
dvander@2226
   669
		{
dvander@2226
   670
			ir = SP_ERROR_STACKLEAK;
dvander@2226
   671
			_SetErrorMessage("Return stack leak detected: rp:%d should be %d!",
dvander@2226
   672
				m_ctx.rp,
dvander@2226
   673
				save_rp);
dvander@2226
   674
		}
dvander@2226
   675
	}
dvander@2226
   676
dvander@2226
   677
	if (ir != SP_ERROR_NONE)
dvander@2226
   678
	{
dvander@2226
   679
		g_engine1.ReportError(m_pRuntime, ir, m_MsgCache, save_rp);
dvander@2193
   680
	}
dvander@2193
   681
dvander@2193
   682
	m_ctx.sp = save_sp;
dvander@2193
   683
	m_ctx.hp = save_hp;
dvander@2226
   684
	m_ctx.rp = save_rp;
dvander@2226
   685
	
danderson@3977
   686
	if ((m_pRuntime->plugin()->prof_flags & SP_PROF_CALLBACKS) == SP_PROF_CALLBACKS)
dvander@2193
   687
	{
danderson@3977
   688
		m_pRuntime->plugin()->profiler->OnCallbackEnd(serial);
dvander@2193
   689
	}
dvander@2193
   690
dvander@2226
   691
	m_ctx.err_cip = save_cip;
dvander@2193
   692
	m_ctx.n_idx = save_n_idx;
dvander@2193
   693
	m_ctx.n_err = SP_ERROR_NONE;
dvander@2193
   694
	m_MsgCache[0] = '\0';
dvander@2193
   695
	m_CustomMsg = false;
dvander@2193
   696
dvander@2193
   697
	return ir;
dvander@2193
   698
}
dvander@2193
   699
dvander@2193
   700
IPluginRuntime *BaseContext::GetRuntime()
dvander@2193
   701
{
dvander@2193
   702
	return m_pRuntime;
dvander@2193
   703
}
dvander@2193
   704
dvander@2193
   705
DebugInfo::DebugInfo(sp_plugin_t *plugin) : m_pPlugin(plugin)
dvander@2193
   706
{
dvander@2193
   707
}
dvander@2193
   708
dvander@2193
   709
#define USHR(x) ((unsigned int)(x)>>1)
dvander@2193
   710
dvander@2193
   711
int DebugInfo::LookupFile(ucell_t addr, const char **filename)
dvander@2193
   712
{
dvander@2193
   713
	int high, low, mid;
dvander@2193
   714
dvander@2193
   715
	high = m_pPlugin->debug.files_num;
dvander@2193
   716
	low = -1;
dvander@2193
   717
dvander@2193
   718
	while (high - low > 1)
dvander@2193
   719
	{
dvander@2193
   720
		mid = USHR(low + high);
dvander@2226
   721
		if (m_pPlugin->debug.files[mid].addr <= addr)
dvander@2193
   722
		{
dvander@2193
   723
			low = mid;
dvander@2193
   724
		} else {
dvander@2193
   725
			high = mid;
dvander@2193
   726
		}
dvander@2193
   727
	}
dvander@2193
   728
dvander@2193
   729
	if (low == -1)
dvander@2193
   730
	{
dvander@2193
   731
		return SP_ERROR_NOT_FOUND;
dvander@2193
   732
	}
dvander@2193
   733
dvander@2226
   734
	*filename = m_pPlugin->debug.stringbase + m_pPlugin->debug.files[low].name;
dvander@2193
   735
dvander@2193
   736
	return SP_ERROR_NONE;
dvander@2193
   737
}
dvander@2193
   738
dvander@2193
   739
int DebugInfo::LookupFunction(ucell_t addr, const char **name)
dvander@2193
   740
{
dvander@2378
   741
	if (!m_pPlugin->debug.unpacked)
dvander@2193
   742
	{
dvander@2378
   743
		uint32_t max, iter;
dvander@2378
   744
		sp_fdbg_symbol_t *sym;
dvander@2378
   745
		uint8_t *cursor = (uint8_t *)(m_pPlugin->debug.symbols);
dvander@2378
   746
dvander@2378
   747
		max = m_pPlugin->debug.syms_num;
dvander@2378
   748
		for (iter = 0; iter < max; iter++)
dvander@2378
   749
		{
dvander@2378
   750
			sym = (sp_fdbg_symbol_t *)cursor;
dvander@2226
   751
dvander@2378
   752
			if (sym->ident == SP_SYM_FUNCTION
dvander@2378
   753
				&& sym->codestart <= addr 
dvander@2378
   754
				&& sym->codeend > addr)
dvander@2378
   755
			{
dvander@2378
   756
				*name = m_pPlugin->debug.stringbase + sym->name;
dvander@2378
   757
				return SP_ERROR_NONE;
dvander@2378
   758
			}
dvander@2378
   759
dvander@2378
   760
			if (sym->dimcount > 0)
dvander@2378
   761
			{
dvander@2378
   762
				cursor += sizeof(sp_fdbg_symbol_t);
dvander@2378
   763
				cursor += sizeof(sp_fdbg_arraydim_t) * sym->dimcount;
dvander@2378
   764
				continue;
dvander@2378
   765
			}
dvander@2378
   766
dvander@2378
   767
			cursor += sizeof(sp_fdbg_symbol_t);
dvander@2193
   768
		}
dvander@2226
   769
dvander@2378
   770
		return SP_ERROR_NOT_FOUND;
dvander@2378
   771
	}
dvander@2378
   772
	else
dvander@2378
   773
	{
dvander@2378
   774
		uint32_t max, iter;
dvander@2378
   775
		sp_u_fdbg_symbol_t *sym;
dvander@2378
   776
		uint8_t *cursor = (uint8_t *)(m_pPlugin->debug.symbols);
dvander@2378
   777
dvander@2378
   778
		max = m_pPlugin->debug.syms_num;
dvander@2378
   779
		for (iter = 0; iter < max; iter++)
dvander@2226
   780
		{
dvander@2378
   781
			sym = (sp_u_fdbg_symbol_t *)cursor;
dvander@2378
   782
dvander@2378
   783
			if (sym->ident == SP_SYM_FUNCTION
dvander@2378
   784
				&& sym->codestart <= addr 
dvander@2378
   785
				&& sym->codeend > addr)
dvander@2378
   786
			{
dvander@2378
   787
				*name = m_pPlugin->debug.stringbase + sym->name;
dvander@2378
   788
				return SP_ERROR_NONE;
dvander@2378
   789
			}
dvander@2378
   790
dvander@2378
   791
			if (sym->dimcount > 0)
dvander@2378
   792
			{
dvander@2378
   793
				cursor += sizeof(sp_u_fdbg_symbol_t);
dvander@2378
   794
				cursor += sizeof(sp_u_fdbg_arraydim_t) * sym->dimcount;
dvander@2378
   795
				continue;
dvander@2378
   796
			}
dvander@2378
   797
dvander@2378
   798
			cursor += sizeof(sp_u_fdbg_symbol_t);
dvander@2226
   799
		}
dvander@2226
   800
dvander@2378
   801
		return SP_ERROR_NOT_FOUND;
dvander@2193
   802
	}
dvander@2193
   803
}
dvander@2193
   804
dvander@2193
   805
int DebugInfo::LookupLine(ucell_t addr, uint32_t *line)
dvander@2193
   806
{
dvander@2193
   807
	int high, low, mid;
dvander@2193
   808
dvander@2193
   809
	high = m_pPlugin->debug.lines_num;
dvander@2193
   810
	low = -1;
dvander@2193
   811
dvander@2193
   812
	while (high - low > 1)
dvander@2193
   813
	{
dvander@2193
   814
		mid = USHR(low + high);
dvander@2226
   815
		if (m_pPlugin->debug.lines[mid].addr <= addr)
dvander@2193
   816
		{
dvander@2193
   817
			low = mid;
dvander@2193
   818
		} else {
dvander@2193
   819
			high = mid;
dvander@2193
   820
		}
dvander@2193
   821
	}
dvander@2193
   822
dvander@2193
   823
	if (low == -1)
dvander@2193
   824
	{
dvander@2193
   825
		return SP_ERROR_NOT_FOUND;
dvander@2193
   826
	}
dvander@2193
   827
dvander@2193
   828
	/* Since the CIP occurs BEFORE the line, we have to add one */
dvander@2226
   829
	*line = m_pPlugin->debug.lines[low].line + 1;
dvander@2193
   830
dvander@2193
   831
	return SP_ERROR_NONE;
dvander@2193
   832
}
dvander@2193
   833
dvander@2193
   834
#undef USHR
dvander@2193
   835
dvander@2193
   836
int BaseContext::GetLastNativeError()
dvander@2193
   837
{
dvander@2193
   838
	return m_ctx.n_err;
dvander@2193
   839
}
dvander@2193
   840
dvander@2193
   841
cell_t *BaseContext::GetLocalParams()
dvander@2193
   842
{
danderson@3977
   843
	return (cell_t *)(m_pRuntime->plugin()->memory + m_ctx.frm + (2 * sizeof(cell_t)));
dvander@2193
   844
}
dvander@2193
   845
dvander@2193
   846
void BaseContext::SetKey(int k, void *value)
dvander@2193
   847
{
dvander@2193
   848
	if (k < 1 || k > 4)
dvander@2193
   849
	{
dvander@2193
   850
		return;
dvander@2193
   851
	}
dvander@2193
   852
dvander@2193
   853
	m_keys[k - 1] = value;
dvander@2193
   854
	m_keys_set[k - 1] = true;
dvander@2193
   855
}
dvander@2193
   856
dvander@2193
   857
bool BaseContext::GetKey(int k, void **value)
dvander@2193
   858
{
dvander@2193
   859
	if (k < 1 || k > 4 || m_keys_set[k - 1] == false)
dvander@2193
   860
	{
dvander@2193
   861
		return false;
dvander@2193
   862
	}
dvander@2193
   863
dvander@2193
   864
	*value = m_keys[k - 1];
dvander@2193
   865
dvander@2193
   866
	return true;
dvander@2193
   867
}
dvander@2545
   868
dvander@2545
   869
void BaseContext::ClearLastNativeError()
dvander@2545
   870
{
dvander@2545
   871
	m_ctx.n_err = SP_ERROR_NONE;
dvander@2545
   872
}