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