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