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