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