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