sourcepawn/jit/BaseRuntime.cpp
author Nicholas Hastings <skamonkey@gmail.com>
Fri Nov 04 10:01:33 2011 -0400 (2011-11-04)
changeset 3438 07a1b8a8a2ba
parent 2545 9cb1a1fefc2c
child 3601 d3a2fb7b3a1e
permissions -rw-r--r--
Updated TF2_OnIsHolidayActive ret behavior to match doc (bug 5155, r=fyren).
     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 #include <string.h>
     4 #include <assert.h>
     5 #include "BaseRuntime.h"
     6 #include "sp_vm_engine.h"
     7 #include "x86/jit_x86.h"
     8 #include "sp_vm_basecontext.h"
     9 #include "engine2.h"
    10 
    11 using namespace SourcePawn;
    12 
    13 BaseRuntime::BaseRuntime() : m_Debug(&m_plugin), m_pPlugin(&m_plugin), m_pCtx(NULL), 
    14 m_PubFuncs(NULL), m_PubJitFuncs(NULL), m_pCo(NULL), m_CompSerial(0)
    15 {
    16 	memset(&m_plugin, 0, sizeof(m_plugin));
    17 
    18 	m_FuncCache = NULL;
    19 	m_MaxFuncs = 0;
    20 	m_NumFuncs = 0;
    21 }
    22 
    23 BaseRuntime::~BaseRuntime()
    24 {
    25 	for (uint32_t i = 0; i < m_pPlugin->num_publics; i++)
    26 	{
    27 		delete m_PubFuncs[i];
    28 		m_PubFuncs[i] = NULL;
    29 	}
    30 	delete [] m_PubFuncs;
    31 	delete [] m_PubJitFuncs;
    32 
    33 	for (unsigned int i = 0; i < m_NumFuncs; i++)
    34 	{
    35 		delete m_FuncCache[i];
    36 	}
    37 	free(m_FuncCache);
    38 
    39 	delete m_pCtx;
    40 	if (m_pCo != NULL)
    41 	{
    42 		m_pCo->Abort();
    43 	}
    44 
    45 	free(m_pPlugin->base);
    46 	delete [] m_pPlugin->memory;
    47 	delete [] m_pPlugin->publics;
    48 	delete [] m_pPlugin->pubvars;
    49 	delete [] m_pPlugin->natives;
    50 	free(m_pPlugin->name);
    51 }
    52 
    53 static cell_t InvalidNative(IPluginContext *pCtx, const cell_t *params)
    54 {
    55 	return pCtx->ThrowNativeErrorEx(SP_ERROR_INVALID_NATIVE, "Invalid native");
    56 }
    57 
    58 int BaseRuntime::CreateFromMemory(sp_file_hdr_t *hdr, uint8_t *base)
    59 {
    60 	int set_err;
    61 	char *nameptr;
    62 	uint8_t sectnum = 0;
    63 	sp_plugin_t *plugin = m_pPlugin;
    64 	sp_file_section_t *secptr = (sp_file_section_t *)(base + sizeof(sp_file_hdr_t));
    65 
    66 	memset(plugin, 0, sizeof(sp_plugin_t));
    67 
    68 	plugin->base = base;
    69 	plugin->base_size = hdr->imagesize;
    70 	set_err = SP_ERROR_NONE;
    71 
    72 	if (hdr->version == 0x0101)
    73 	{
    74 		plugin->debug.unpacked = true;
    75 	}
    76 
    77 	/* We have to read the name section first */
    78 	for (sectnum = 0; sectnum < hdr->sections; sectnum++)
    79 	{
    80 		nameptr = (char *)(base + hdr->stringtab + secptr[sectnum].nameoffs);
    81 		if (strcmp(nameptr, ".names") == 0)
    82 		{
    83 			plugin->stringbase = (const char *)(base + secptr[sectnum].dataoffs);
    84 			break;
    85 		}
    86 	}
    87 
    88 	sectnum = 0;
    89 
    90 	/* Now read the rest of the sections */
    91 	while (sectnum < hdr->sections)
    92 	{
    93 		nameptr = (char *)(base + hdr->stringtab + secptr->nameoffs);
    94 
    95 		if (!(plugin->pcode) && !strcmp(nameptr, ".code"))
    96 		{
    97 			sp_file_code_t *cod = (sp_file_code_t *)(base + secptr->dataoffs);
    98 
    99 			if (cod->codeversion < SP_CODEVERS_JIT1)
   100 			{
   101 				return SP_ERROR_CODE_TOO_OLD;
   102 			}
   103 			else if (cod->codeversion > SP_CODEVERS_JIT2)
   104 			{
   105 				return SP_ERROR_CODE_TOO_NEW;
   106 			}
   107 
   108 			plugin->pcode = base + secptr->dataoffs + cod->code;
   109 			plugin->pcode_size = cod->codesize;
   110 			plugin->flags = cod->flags;
   111 			plugin->pcode_version = cod->codeversion;
   112 		}
   113 		else if (!(plugin->data) && !strcmp(nameptr, ".data"))
   114 		{
   115 			sp_file_data_t *dat = (sp_file_data_t *)(base + secptr->dataoffs);
   116 			plugin->data = base + secptr->dataoffs + dat->data;
   117 			plugin->data_size = dat->datasize;
   118 			plugin->mem_size = dat->memsize;
   119 			plugin->memory = new uint8_t[plugin->mem_size];
   120 			memcpy(plugin->memory, plugin->data, plugin->data_size);
   121 		}
   122 		else if ((plugin->publics == NULL) && !strcmp(nameptr, ".publics"))
   123 		{
   124 			sp_file_publics_t *publics;
   125 
   126 			publics = (sp_file_publics_t *)(base + secptr->dataoffs);
   127 			plugin->num_publics = secptr->size / sizeof(sp_file_publics_t);
   128 
   129 			if (plugin->num_publics > 0)
   130 			{
   131 				plugin->publics = new sp_public_t[plugin->num_publics];
   132 
   133 				for (uint32_t i = 0; i < plugin->num_publics; i++)
   134 				{
   135 					plugin->publics[i].code_offs = publics[i].address;
   136 					plugin->publics[i].funcid = (i << 1) | 1;
   137 					plugin->publics[i].name = plugin->stringbase + publics[i].name;
   138 				}
   139 			}
   140 		}
   141 		else if ((plugin->pubvars == NULL) && !strcmp(nameptr, ".pubvars"))
   142 		{
   143 			sp_file_pubvars_t *pubvars;
   144 
   145 			pubvars = (sp_file_pubvars_t *)(base + secptr->dataoffs);
   146 			plugin->num_pubvars = secptr->size / sizeof(sp_file_pubvars_t);
   147 
   148 			if (plugin->num_pubvars > 0)
   149 			{
   150 				plugin->pubvars = new sp_pubvar_t[plugin->num_pubvars];
   151 
   152 				for (uint32_t i = 0; i < plugin->num_pubvars; i++)
   153 				{
   154 					plugin->pubvars[i].name = plugin->stringbase + pubvars[i].name;
   155 					plugin->pubvars[i].offs = (cell_t *)(plugin->memory + pubvars[i].address);
   156 				}
   157 			}
   158 		}
   159 		else if ((plugin->natives == NULL) && !strcmp(nameptr, ".natives"))
   160 		{
   161 			sp_file_natives_t *natives;
   162 
   163 			natives = (sp_file_natives_t *)(base + secptr->dataoffs);
   164 			plugin->num_natives = secptr->size / sizeof(sp_file_natives_t);
   165 
   166 			if (plugin->num_natives > 0)
   167 			{
   168 				plugin->natives = new sp_native_t[plugin->num_natives];
   169 
   170 				for (uint32_t i = 0; i < plugin->num_natives; i++)
   171 				{
   172 					plugin->natives[i].flags = 0;
   173 					plugin->natives[i].pfn = InvalidNative;
   174 					plugin->natives[i].status = SP_NATIVE_UNBOUND;
   175 					plugin->natives[i].user = NULL;
   176 					plugin->natives[i].name = plugin->stringbase + natives[i].name;
   177 				}
   178 			}
   179 		}
   180 		else if (!(plugin->debug.files) && !strcmp(nameptr, ".dbg.files"))
   181 		{
   182 			plugin->debug.files = (sp_fdbg_file_t *)(base + secptr->dataoffs);
   183 		}
   184 		else if (!(plugin->debug.lines) && !strcmp(nameptr, ".dbg.lines"))
   185 		{
   186 			plugin->debug.lines = (sp_fdbg_line_t *)(base + secptr->dataoffs);
   187 		}
   188 		else if (!(plugin->debug.symbols) && !strcmp(nameptr, ".dbg.symbols"))
   189 		{
   190 			plugin->debug.symbols = (sp_fdbg_symbol_t *)(base + secptr->dataoffs);
   191 		}
   192 		else if (!(plugin->debug.lines_num) && !strcmp(nameptr, ".dbg.info"))
   193 		{
   194 			sp_fdbg_info_t *inf = (sp_fdbg_info_t *)(base + secptr->dataoffs);
   195 			plugin->debug.files_num = inf->num_files;
   196 			plugin->debug.lines_num = inf->num_lines;
   197 			plugin->debug.syms_num = inf->num_syms;
   198 		}
   199 		else if (!(plugin->debug.stringbase) && !strcmp(nameptr, ".dbg.strings"))
   200 		{
   201 			plugin->debug.stringbase = (const char *)(base + secptr->dataoffs);
   202 		}
   203 		else if (strcmp(nameptr, ".dbg.natives") == 0)
   204 		{
   205 			plugin->debug.unpacked = false;
   206 		}
   207 
   208 		secptr++;
   209 		sectnum++;
   210 	}
   211 
   212 	if (plugin->pcode == NULL || plugin->data == NULL)
   213 	{
   214 		return SP_ERROR_FILE_FORMAT;
   215 	}
   216 
   217 	if ((plugin->flags & SP_FLAG_DEBUG) && (!(plugin->debug.files) || !(plugin->debug.lines) || !(plugin->debug.symbols)))
   218 	{
   219 		return SP_ERROR_FILE_FORMAT;
   220 	}
   221 
   222 	if (m_pPlugin->num_publics > 0)
   223 	{
   224 		m_PubFuncs = new CFunction *[m_pPlugin->num_publics];
   225 		memset(m_PubFuncs, 0, sizeof(CFunction *) * m_pPlugin->num_publics);
   226 		m_PubJitFuncs = new JitFunction *[m_pPlugin->num_publics];
   227 		memset(m_PubJitFuncs, 0, sizeof(JitFunction *) * m_pPlugin->num_publics);
   228 	}
   229 
   230 	m_pPlugin->profiler = g_engine2.GetProfiler();
   231 	m_pCtx = new BaseContext(this);
   232 	m_pCo = g_Jit.StartCompilation(this);
   233 
   234 	return SP_ERROR_NONE;
   235 }
   236 
   237 int BaseRuntime::FindNativeByName(const char *name, uint32_t *index)
   238 {
   239 	int high;
   240 
   241 	high = m_pPlugin->num_natives - 1;
   242 
   243 	for (uint32_t i=0; i<m_pPlugin->num_natives; i++)
   244 	{
   245 		if (strcmp(m_pPlugin->natives[i].name, name) == 0)
   246 		{
   247 			if (index)
   248 			{
   249 				*index = i;
   250 			}
   251 			return SP_ERROR_NONE;
   252 		}
   253 	}
   254 
   255 	return SP_ERROR_NOT_FOUND;
   256 }
   257 
   258 int BaseRuntime::GetNativeByIndex(uint32_t index, sp_native_t **native)
   259 {
   260 	if (index >= m_pPlugin->num_natives)
   261 	{
   262 		return SP_ERROR_INDEX;
   263 	}
   264 
   265 	if (native)
   266 	{
   267 		*native = &(m_pPlugin->natives[index]);
   268 	}
   269 
   270 	return SP_ERROR_NONE;
   271 }
   272 
   273 
   274 uint32_t BaseRuntime::GetNativesNum()
   275 {
   276 	return m_pPlugin->num_natives;
   277 }
   278 
   279 int BaseRuntime::FindPublicByName(const char *name, uint32_t *index)
   280 {
   281 	int diff, high, low;
   282 	uint32_t mid;
   283 
   284 	high = m_pPlugin->num_publics - 1;
   285 	low = 0;
   286 
   287 	while (low <= high)
   288 	{
   289 		mid = (low + high) / 2;
   290 		diff = strcmp(m_pPlugin->publics[mid].name, name);
   291 		if (diff == 0)
   292 		{
   293 			if (index)
   294 			{
   295 				*index = mid;
   296 			}
   297 			return SP_ERROR_NONE;
   298 		} else if (diff < 0) {
   299 			low = mid + 1;
   300 		} else {
   301 			high = mid - 1;
   302 		}
   303 	}
   304 
   305 	return SP_ERROR_NOT_FOUND;
   306 }
   307 
   308 int BaseRuntime::GetPublicByIndex(uint32_t index, sp_public_t **pblic)
   309 {
   310 	if (index >= m_pPlugin->num_publics)
   311 	{
   312 		return SP_ERROR_INDEX;
   313 	}
   314 
   315 	if (pblic)
   316 	{
   317 		*pblic = &(m_pPlugin->publics[index]);
   318 	}
   319 
   320 	return SP_ERROR_NONE;
   321 }
   322 
   323 uint32_t BaseRuntime::GetPublicsNum()
   324 {
   325 	return m_pPlugin->num_publics;
   326 }
   327 
   328 int BaseRuntime::GetPubvarByIndex(uint32_t index, sp_pubvar_t **pubvar)
   329 {
   330 	if (index >= m_pPlugin->num_pubvars)
   331 	{
   332 		return SP_ERROR_INDEX;
   333 	}
   334 
   335 	if (pubvar)
   336 	{
   337 		*pubvar = &(m_pPlugin->pubvars[index]);
   338 	}
   339 
   340 	return SP_ERROR_NONE;
   341 }
   342 
   343 int BaseRuntime::FindPubvarByName(const char *name, uint32_t *index)
   344 {
   345 	int diff, high, low;
   346 	uint32_t mid;
   347 
   348 	high = m_pPlugin->num_pubvars - 1;
   349 	low = 0;
   350 
   351 	while (low <= high)
   352 	{
   353 		mid = (low + high) / 2;
   354 		diff = strcmp(m_pPlugin->pubvars[mid].name, name);
   355 		if (diff == 0)
   356 		{
   357 			if (index)
   358 			{
   359 				*index = mid;
   360 			}
   361 			return SP_ERROR_NONE;
   362 		}
   363 		else if (diff < 0)
   364 		{
   365 			low = mid + 1;
   366 		}
   367 		else
   368 		{
   369 			high = mid - 1;
   370 		}
   371 	}
   372 
   373 	return SP_ERROR_NOT_FOUND;
   374 }
   375 
   376 int BaseRuntime::GetPubvarAddrs(uint32_t index, cell_t *local_addr, cell_t **phys_addr)
   377 {
   378 	if (index >= m_pPlugin->num_pubvars)
   379 	{
   380 		return SP_ERROR_INDEX;
   381 	}
   382 
   383 	*local_addr = (uint8_t *)m_pPlugin->pubvars[index].offs - m_pPlugin->memory;
   384 	*phys_addr = m_pPlugin->pubvars[index].offs;
   385 
   386 	return SP_ERROR_NONE;
   387 }
   388 
   389 uint32_t BaseRuntime::GetPubVarsNum()
   390 {
   391 	return m_pPlugin->num_pubvars;
   392 }
   393 
   394 IPluginContext *BaseRuntime::GetDefaultContext()
   395 {
   396 	return m_pCtx;
   397 }
   398 
   399 IPluginDebugInfo *BaseRuntime::GetDebugInfo()
   400 {
   401 	return &m_Debug;
   402 }
   403 
   404 IPluginFunction *BaseRuntime::GetFunctionById(funcid_t func_id)
   405 {
   406 	CFunction *pFunc = NULL;
   407 
   408 	if (func_id & 1)
   409 	{
   410 		func_id >>= 1;
   411 		if (func_id >= m_pPlugin->num_publics)
   412 		{
   413 			return NULL;
   414 		}
   415 		pFunc = m_PubFuncs[func_id];
   416 		if (!pFunc)
   417 		{
   418 			m_PubFuncs[func_id] = new CFunction(this, 
   419 				(func_id << 1) | 1,
   420 				func_id);
   421 			pFunc = m_PubFuncs[func_id];
   422 		}
   423 	}
   424 
   425 	return pFunc;
   426 }
   427 
   428 IPluginFunction *BaseRuntime::GetFunctionByName(const char *public_name)
   429 {
   430 	uint32_t index;
   431 
   432 	if (FindPublicByName(public_name, &index) != SP_ERROR_NONE)
   433 	{
   434 		return NULL;
   435 	}
   436 
   437 	CFunction *pFunc = m_PubFuncs[index];
   438 	if (!pFunc)
   439 	{
   440 		sp_public_t *pub = NULL;
   441 		GetPublicByIndex(index, &pub);
   442 		if (pub)
   443 		{
   444 			m_PubFuncs[index] = new CFunction(this, (index << 1) | 1, index);
   445 		}
   446 		pFunc = m_PubFuncs[index];
   447 	}
   448 
   449 	return pFunc;
   450 }
   451 
   452 bool BaseRuntime::IsDebugging()
   453 {
   454 	return true;
   455 }
   456 
   457 void BaseRuntime::SetPauseState(bool paused)
   458 {
   459 	if (paused)
   460 	{
   461 		m_pPlugin->run_flags |= SPFLAG_PLUGIN_PAUSED;
   462 	}
   463 	else
   464 	{
   465 		m_pPlugin->run_flags &= ~SPFLAG_PLUGIN_PAUSED;
   466 	}
   467 }
   468 
   469 bool BaseRuntime::IsPaused()
   470 {
   471 	return ((m_pPlugin->run_flags & SPFLAG_PLUGIN_PAUSED) == SPFLAG_PLUGIN_PAUSED);
   472 }
   473 
   474 size_t BaseRuntime::GetMemUsage()
   475 {
   476 	size_t mem = 0;
   477 
   478 	mem += sizeof(this);
   479 	mem += sizeof(sp_plugin_t);
   480 	mem += sizeof(BaseContext);
   481 	mem += m_pPlugin->base_size;
   482 
   483 	return mem;
   484 }
   485 
   486 BaseContext *BaseRuntime::GetBaseContext()
   487 {
   488 	return m_pCtx;
   489 }
   490 
   491 int BaseRuntime::ApplyCompilationOptions(ICompilation *co)
   492 {
   493 	if (co == NULL)
   494 	{
   495 		return SP_ERROR_NONE;
   496 	}
   497 
   498 	m_pCo = g_Jit.ApplyOptions(m_pCo, co);
   499 	m_pPlugin->prof_flags = ((CompData *)m_pCo)->profile;
   500 
   501 	return SP_ERROR_NONE;
   502 }
   503 
   504 JitFunction *BaseRuntime::GetJittedFunction(uint32_t idx)
   505 {
   506 	assert(idx <= m_NumFuncs);
   507 
   508 	if (idx == 0 || idx > m_NumFuncs)
   509 	{
   510 		return NULL;
   511 	}
   512 
   513 	return m_FuncCache[idx - 1];
   514 }
   515 
   516 uint32_t BaseRuntime::AddJittedFunction(JitFunction *fn)
   517 {
   518 	if (m_NumFuncs + 1 > m_MaxFuncs)
   519 	{
   520 		if (m_MaxFuncs == 0)
   521 		{
   522 			m_MaxFuncs = 8;
   523 		}
   524 		else
   525 		{
   526 			m_MaxFuncs *= 2;
   527 		}
   528 
   529 		m_FuncCache = (JitFunction **)realloc(
   530 			m_FuncCache,
   531 			sizeof(JitFunction *) * m_MaxFuncs);
   532 	}
   533 
   534 	m_FuncCache[m_NumFuncs++] = fn;
   535 
   536 	return m_NumFuncs;
   537 }
   538 
   539 int BaseRuntime::CreateBlank(uint32_t heastk)
   540 {
   541 	memset(m_pPlugin, 0, sizeof(sp_plugin_t));
   542 
   543 	/* Align to cell_t bytes */
   544 	heastk += sizeof(cell_t);
   545 	heastk -= heastk % sizeof(cell_t);
   546 
   547 	m_pPlugin->mem_size = heastk;
   548 	m_pPlugin->memory = new uint8_t[heastk];
   549 
   550 	m_pPlugin->profiler = g_engine2.GetProfiler();
   551 	m_pCtx = new BaseContext(this);
   552 	m_pCo = g_Jit.StartCompilation(this);
   553 
   554 	return SP_ERROR_NONE;
   555 }