sourcepawn/jit/BaseRuntime.cpp
author David Anderson <dvander@alliedmods.net>
Sun Oct 26 23:50:54 2008 -0500 (2008-10-26)
changeset 2377 6ee3bbd6fbdf
parent 2249 a1ce7e3f08b7
child 2378 d812052c5821
permissions -rw-r--r--
Fixed leaking relocation table memory in JIT.
     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 	/* We have to read the name section first */
    73 	for (sectnum = 0; sectnum < hdr->sections; sectnum++)
    74 	{
    75 		nameptr = (char *)(base + hdr->stringtab + secptr[sectnum].nameoffs);
    76 		if (strcmp(nameptr, ".names") == 0)
    77 		{
    78 			plugin->stringbase = (const char *)(base + secptr[sectnum].dataoffs);
    79 			break;
    80 		}
    81 	}
    82 
    83 	sectnum = 0;
    84 
    85 	/* Now read the rest of the sections */
    86 	while (sectnum < hdr->sections)
    87 	{
    88 		nameptr = (char *)(base + hdr->stringtab + secptr->nameoffs);
    89 
    90 		if (!(plugin->pcode) && !strcmp(nameptr, ".code"))
    91 		{
    92 			sp_file_code_t *cod = (sp_file_code_t *)(base + secptr->dataoffs);
    93 
    94 			if (cod->codeversion < SP_CODEVERS_JIT1)
    95 			{
    96 				return SP_ERROR_CODE_TOO_OLD;
    97 			}
    98 			else if (cod->codeversion > SP_CODEVERS_JIT2)
    99 			{
   100 				return SP_ERROR_CODE_TOO_NEW;
   101 			}
   102 
   103 			plugin->pcode = base + secptr->dataoffs + cod->code;
   104 			plugin->pcode_size = cod->codesize;
   105 			plugin->flags = cod->flags;
   106 			plugin->pcode_version = cod->codeversion;
   107 		}
   108 		else if (!(plugin->data) && !strcmp(nameptr, ".data"))
   109 		{
   110 			sp_file_data_t *dat = (sp_file_data_t *)(base + secptr->dataoffs);
   111 			plugin->data = base + secptr->dataoffs + dat->data;
   112 			plugin->data_size = dat->datasize;
   113 			plugin->mem_size = dat->memsize;
   114 			plugin->memory = new uint8_t[plugin->mem_size];
   115 			memcpy(plugin->memory, plugin->data, plugin->data_size);
   116 		}
   117 		else if ((plugin->publics == NULL) && !strcmp(nameptr, ".publics"))
   118 		{
   119 			sp_file_publics_t *publics;
   120 
   121 			publics = (sp_file_publics_t *)(base + secptr->dataoffs);
   122 			plugin->num_publics = secptr->size / sizeof(sp_file_publics_t);
   123 
   124 			if (plugin->num_publics > 0)
   125 			{
   126 				plugin->publics = new sp_public_t[plugin->num_publics];
   127 
   128 				for (uint32_t i = 0; i < plugin->num_publics; i++)
   129 				{
   130 					plugin->publics[i].code_offs = publics[i].address;
   131 					plugin->publics[i].funcid = (i << 1) | 1;
   132 					plugin->publics[i].name = plugin->stringbase + publics[i].name;
   133 				}
   134 			}
   135 		}
   136 		else if ((plugin->pubvars == NULL) && !strcmp(nameptr, ".pubvars"))
   137 		{
   138 			sp_file_pubvars_t *pubvars;
   139 
   140 			pubvars = (sp_file_pubvars_t *)(base + secptr->dataoffs);
   141 			plugin->num_pubvars = secptr->size / sizeof(sp_file_pubvars_t);
   142 
   143 			if (plugin->num_pubvars > 0)
   144 			{
   145 				plugin->pubvars = new sp_pubvar_t[plugin->num_pubvars];
   146 
   147 				for (uint32_t i = 0; i < plugin->num_pubvars; i++)
   148 				{
   149 					plugin->pubvars[i].name = plugin->stringbase + pubvars[i].name;
   150 					plugin->pubvars[i].offs = (cell_t *)(plugin->memory + pubvars[i].address);
   151 				}
   152 			}
   153 		}
   154 		else if ((plugin->natives == NULL) && !strcmp(nameptr, ".natives"))
   155 		{
   156 			sp_file_natives_t *natives;
   157 
   158 			natives = (sp_file_natives_t *)(base + secptr->dataoffs);
   159 			plugin->num_natives = secptr->size / sizeof(sp_file_natives_t);
   160 
   161 			if (plugin->num_natives > 0)
   162 			{
   163 				plugin->natives = new sp_native_t[plugin->num_natives];
   164 
   165 				for (uint32_t i = 0; i < plugin->num_natives; i++)
   166 				{
   167 					plugin->natives[i].flags = 0;
   168 					plugin->natives[i].pfn = InvalidNative;
   169 					plugin->natives[i].status = SP_NATIVE_UNBOUND;
   170 					plugin->natives[i].user = NULL;
   171 					plugin->natives[i].name = plugin->stringbase + natives[i].name;
   172 				}
   173 			}
   174 		}
   175 		else if (!(plugin->debug.files) && !strcmp(nameptr, ".dbg.files"))
   176 		{
   177 			plugin->debug.files = (sp_fdbg_file_t *)(base + secptr->dataoffs);
   178 		}
   179 		else if (!(plugin->debug.lines) && !strcmp(nameptr, ".dbg.lines"))
   180 		{
   181 			plugin->debug.lines = (sp_fdbg_line_t *)(base + secptr->dataoffs);
   182 		}
   183 		else if (!(plugin->debug.symbols) && !strcmp(nameptr, ".dbg.symbols"))
   184 		{
   185 			plugin->debug.symbols = (sp_fdbg_symbol_t *)(base + secptr->dataoffs);
   186 		}
   187 		else if (!(plugin->debug.lines_num) && !strcmp(nameptr, ".dbg.info"))
   188 		{
   189 			sp_fdbg_info_t *inf = (sp_fdbg_info_t *)(base + secptr->dataoffs);
   190 			plugin->debug.files_num = inf->num_files;
   191 			plugin->debug.lines_num = inf->num_lines;
   192 			plugin->debug.syms_num = inf->num_syms;
   193 		}
   194 		else if (!(plugin->debug.stringbase) && !strcmp(nameptr, ".dbg.strings"))
   195 		{
   196 			plugin->debug.stringbase = (const char *)(base + secptr->dataoffs);
   197 		}
   198 
   199 		secptr++;
   200 		sectnum++;
   201 	}
   202 
   203 	if (plugin->pcode == NULL || plugin->data == NULL)
   204 	{
   205 		return SP_ERROR_FILE_FORMAT;
   206 	}
   207 
   208 	if ((plugin->flags & SP_FLAG_DEBUG) && (!(plugin->debug.files) || !(plugin->debug.lines) || !(plugin->debug.symbols)))
   209 	{
   210 		return SP_ERROR_FILE_FORMAT;
   211 	}
   212 
   213 	if (m_pPlugin->num_publics > 0)
   214 	{
   215 		m_PubFuncs = new CFunction *[m_pPlugin->num_publics];
   216 		memset(m_PubFuncs, 0, sizeof(CFunction *) * m_pPlugin->num_publics);
   217 		m_PubJitFuncs = new JitFunction *[m_pPlugin->num_publics];
   218 		memset(m_PubJitFuncs, 0, sizeof(JitFunction *) * m_pPlugin->num_publics);
   219 	}
   220 
   221 	m_pPlugin->profiler = g_engine2.GetProfiler();
   222 	m_pCtx = new BaseContext(this);
   223 	m_pCo = g_Jit.StartCompilation(this);
   224 
   225 	return SP_ERROR_NONE;
   226 }
   227 
   228 int BaseRuntime::FindNativeByName(const char *name, uint32_t *index)
   229 {
   230 	int high;
   231 
   232 	high = m_pPlugin->num_natives - 1;
   233 
   234 	for (uint32_t i=0; i<m_pPlugin->num_natives; i++)
   235 	{
   236 		if (strcmp(m_pPlugin->natives[i].name, name) == 0)
   237 		{
   238 			if (index)
   239 			{
   240 				*index = i;
   241 			}
   242 			return SP_ERROR_NONE;
   243 		}
   244 	}
   245 
   246 	return SP_ERROR_NOT_FOUND;
   247 }
   248 
   249 int BaseRuntime::GetNativeByIndex(uint32_t index, sp_native_t **native)
   250 {
   251 	if (index >= m_pPlugin->num_natives)
   252 	{
   253 		return SP_ERROR_INDEX;
   254 	}
   255 
   256 	if (native)
   257 	{
   258 		*native = &(m_pPlugin->natives[index]);
   259 	}
   260 
   261 	return SP_ERROR_NONE;
   262 }
   263 
   264 
   265 uint32_t BaseRuntime::GetNativesNum()
   266 {
   267 	return m_pPlugin->num_natives;
   268 }
   269 
   270 int BaseRuntime::FindPublicByName(const char *name, uint32_t *index)
   271 {
   272 	int diff, high, low;
   273 	uint32_t mid;
   274 
   275 	high = m_pPlugin->num_publics - 1;
   276 	low = 0;
   277 
   278 	while (low <= high)
   279 	{
   280 		mid = (low + high) / 2;
   281 		diff = strcmp(m_pPlugin->publics[mid].name, name);
   282 		if (diff == 0)
   283 		{
   284 			if (index)
   285 			{
   286 				*index = mid;
   287 			}
   288 			return SP_ERROR_NONE;
   289 		} else if (diff < 0) {
   290 			low = mid + 1;
   291 		} else {
   292 			high = mid - 1;
   293 		}
   294 	}
   295 
   296 	return SP_ERROR_NOT_FOUND;
   297 }
   298 
   299 int BaseRuntime::GetPublicByIndex(uint32_t index, sp_public_t **pblic)
   300 {
   301 	if (index >= m_pPlugin->num_publics)
   302 	{
   303 		return SP_ERROR_INDEX;
   304 	}
   305 
   306 	if (pblic)
   307 	{
   308 		*pblic = &(m_pPlugin->publics[index]);
   309 	}
   310 
   311 	return SP_ERROR_NONE;
   312 }
   313 
   314 uint32_t BaseRuntime::GetPublicsNum()
   315 {
   316 	return m_pPlugin->num_publics;
   317 }
   318 
   319 int BaseRuntime::GetPubvarByIndex(uint32_t index, sp_pubvar_t **pubvar)
   320 {
   321 	if (index >= m_pPlugin->num_pubvars)
   322 	{
   323 		return SP_ERROR_INDEX;
   324 	}
   325 
   326 	if (pubvar)
   327 	{
   328 		*pubvar = &(m_pPlugin->pubvars[index]);
   329 	}
   330 
   331 	return SP_ERROR_NONE;
   332 }
   333 
   334 int BaseRuntime::FindPubvarByName(const char *name, uint32_t *index)
   335 {
   336 	int diff, high, low;
   337 	uint32_t mid;
   338 
   339 	high = m_pPlugin->num_pubvars - 1;
   340 	low = 0;
   341 
   342 	while (low <= high)
   343 	{
   344 		mid = (low + high) / 2;
   345 		diff = strcmp(m_pPlugin->pubvars[mid].name, name);
   346 		if (diff == 0)
   347 		{
   348 			if (index)
   349 			{
   350 				*index = mid;
   351 			}
   352 			return SP_ERROR_NONE;
   353 		}
   354 		else if (diff < 0)
   355 		{
   356 			low = mid + 1;
   357 		}
   358 		else
   359 		{
   360 			high = mid - 1;
   361 		}
   362 	}
   363 
   364 	return SP_ERROR_NOT_FOUND;
   365 }
   366 
   367 int BaseRuntime::GetPubvarAddrs(uint32_t index, cell_t *local_addr, cell_t **phys_addr)
   368 {
   369 	if (index >= m_pPlugin->num_pubvars)
   370 	{
   371 		return SP_ERROR_INDEX;
   372 	}
   373 
   374 	*local_addr = (uint8_t *)m_pPlugin->pubvars[index].offs - m_pPlugin->memory;
   375 	*phys_addr = m_pPlugin->pubvars[index].offs;
   376 
   377 	return SP_ERROR_NONE;
   378 }
   379 
   380 uint32_t BaseRuntime::GetPubVarsNum()
   381 {
   382 	return m_pPlugin->num_pubvars;
   383 }
   384 
   385 IPluginContext *BaseRuntime::GetDefaultContext()
   386 {
   387 	return m_pCtx;
   388 }
   389 
   390 IPluginDebugInfo *BaseRuntime::GetDebugInfo()
   391 {
   392 	return &m_Debug;
   393 }
   394 
   395 IPluginFunction *BaseRuntime::GetFunctionById(funcid_t func_id)
   396 {
   397 	CFunction *pFunc = NULL;
   398 
   399 	if (func_id & 1)
   400 	{
   401 		func_id >>= 1;
   402 		if (func_id >= m_pPlugin->num_publics)
   403 		{
   404 			return NULL;
   405 		}
   406 		pFunc = m_PubFuncs[func_id];
   407 		if (!pFunc)
   408 		{
   409 			m_PubFuncs[func_id] = new CFunction(this, 
   410 				(func_id << 1) | 1,
   411 				func_id);
   412 			pFunc = m_PubFuncs[func_id];
   413 		}
   414 	}
   415 
   416 	return pFunc;
   417 }
   418 
   419 IPluginFunction *BaseRuntime::GetFunctionByName(const char *public_name)
   420 {
   421 	uint32_t index;
   422 
   423 	if (FindPublicByName(public_name, &index) != SP_ERROR_NONE)
   424 	{
   425 		return NULL;
   426 	}
   427 
   428 	CFunction *pFunc = m_PubFuncs[index];
   429 	if (!pFunc)
   430 	{
   431 		sp_public_t *pub = NULL;
   432 		GetPublicByIndex(index, &pub);
   433 		if (pub)
   434 		{
   435 			m_PubFuncs[index] = new CFunction(this, (index << 1) | 1, index);
   436 		}
   437 		pFunc = m_PubFuncs[index];
   438 	}
   439 
   440 	return pFunc;
   441 }
   442 
   443 bool BaseRuntime::IsDebugging()
   444 {
   445 	return true;
   446 }
   447 
   448 void BaseRuntime::SetPauseState(bool paused)
   449 {
   450 	if (paused)
   451 	{
   452 		m_pPlugin->run_flags |= SPFLAG_PLUGIN_PAUSED;
   453 	}
   454 	else
   455 	{
   456 		m_pPlugin->run_flags &= ~SPFLAG_PLUGIN_PAUSED;
   457 	}
   458 }
   459 
   460 bool BaseRuntime::IsPaused()
   461 {
   462 	return ((m_pPlugin->run_flags & SPFLAG_PLUGIN_PAUSED) == SPFLAG_PLUGIN_PAUSED);
   463 }
   464 
   465 size_t BaseRuntime::GetMemUsage()
   466 {
   467 	size_t mem = 0;
   468 
   469 	mem += sizeof(this);
   470 	mem += sizeof(sp_plugin_t);
   471 	mem += sizeof(BaseContext);
   472 	mem += m_pPlugin->base_size;
   473 
   474 	return mem;
   475 }
   476 
   477 BaseContext *BaseRuntime::GetBaseContext()
   478 {
   479 	return m_pCtx;
   480 }
   481 
   482 int BaseRuntime::ApplyCompilationOptions(ICompilation *co)
   483 {
   484 	if (co == NULL)
   485 	{
   486 		return SP_ERROR_NONE;
   487 	}
   488 
   489 	m_pCo = g_Jit.ApplyOptions(m_pCo, co);
   490 	m_pPlugin->prof_flags = ((CompData *)m_pCo)->profile;
   491 
   492 	return SP_ERROR_NONE;
   493 }
   494 
   495 JitFunction *BaseRuntime::GetJittedFunction(uint32_t idx)
   496 {
   497 	assert(idx <= m_NumFuncs);
   498 
   499 	if (idx == 0 || idx > m_NumFuncs)
   500 	{
   501 		return NULL;
   502 	}
   503 
   504 	return m_FuncCache[idx - 1];
   505 }
   506 
   507 uint32_t BaseRuntime::AddJittedFunction(JitFunction *fn)
   508 {
   509 	if (m_NumFuncs + 1 > m_MaxFuncs)
   510 	{
   511 		if (m_MaxFuncs == 0)
   512 		{
   513 			m_MaxFuncs = 8;
   514 		}
   515 		else
   516 		{
   517 			m_MaxFuncs *= 2;
   518 		}
   519 
   520 		m_FuncCache = (JitFunction **)realloc(
   521 			m_FuncCache,
   522 			sizeof(JitFunction *) * m_MaxFuncs);
   523 	}
   524 
   525 	m_FuncCache[m_NumFuncs++] = fn;
   526 
   527 	return m_NumFuncs;
   528 }