sourcepawn/jit/sp_vm_basecontext.cpp
author David Anderson <dvander@alliedmods.net>
Fri Aug 15 05:22:26 2008 +0000 (2008-08-15)
changeset 2226 d10b38524be3
parent 2214 2b31563dec08
child 2378 d812052c5821
permissions -rw-r--r--
Landed sourcepawn-1.2. The big changes:

1) JIT compilation/optimization now occurs per-function, and only when functions are first used. We're now officially a whole-method JIT rather than an AOT compiler (albiet, still a simple JIT). This has two implications: Functions are now much better abstracted internally, and loading a plugin is now much less expensive. If a function contains calls to other functions, THOSE functions are only compiled when they're invoked as well.

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