dvander@2193: #include dvander@2193: #include dvander@2193: #include dvander@2226: #include dvander@2193: #include "BaseRuntime.h" dvander@2193: #include "sp_vm_engine.h" dvander@2193: #include "x86/jit_x86.h" dvander@2193: #include "sp_vm_basecontext.h" dvander@2193: #include "engine2.h" dvander@2193: dvander@2193: using namespace SourcePawn; dvander@2193: dvander@2226: BaseRuntime::BaseRuntime() : m_Debug(&m_plugin), m_pPlugin(&m_plugin), m_pCtx(NULL), dvander@2226: m_PubFuncs(NULL), m_PubJitFuncs(NULL), m_pCo(NULL), m_CompSerial(0) dvander@2193: { dvander@2226: memset(&m_plugin, 0, sizeof(m_plugin)); dvander@2193: dvander@2226: m_FuncCache = NULL; dvander@2226: m_MaxFuncs = 0; dvander@2226: m_NumFuncs = 0; dvander@2193: } dvander@2193: dvander@2193: BaseRuntime::~BaseRuntime() dvander@2193: { dvander@2226: for (uint32_t i = 0; i < m_pPlugin->num_publics; i++) dvander@2193: { dvander@2193: delete m_PubFuncs[i]; dvander@2193: m_PubFuncs[i] = NULL; dvander@2193: } dvander@2193: delete [] m_PubFuncs; dvander@2226: delete [] m_PubJitFuncs; dvander@2193: dvander@2226: for (unsigned int i = 0; i < m_NumFuncs; i++) dvander@2226: { dvander@2226: delete m_FuncCache[i]; dvander@2226: } dvander@2226: free(m_FuncCache); dvander@2226: dvander@2226: delete m_pCtx; dvander@2226: delete m_pCo; dvander@2193: dvander@2193: free(m_pPlugin->base); dvander@2193: delete [] m_pPlugin->memory; dvander@2226: delete [] m_pPlugin->publics; dvander@2226: delete [] m_pPlugin->pubvars; dvander@2195: delete [] m_pPlugin->natives; dvander@2226: free(m_pPlugin->name); dvander@2226: } dvander@2226: dvander@2226: static cell_t InvalidNative(IPluginContext *pCtx, const cell_t *params) dvander@2226: { dvander@2226: return pCtx->ThrowNativeErrorEx(SP_ERROR_INVALID_NATIVE, "Invalid native"); dvander@2193: } dvander@2193: dvander@2226: int BaseRuntime::CreateFromMemory(sp_file_hdr_t *hdr, uint8_t *base) dvander@2193: { dvander@2226: int set_err; dvander@2226: char *nameptr; dvander@2226: uint8_t sectnum = 0; dvander@2226: sp_plugin_t *plugin = m_pPlugin; dvander@2226: sp_file_section_t *secptr = (sp_file_section_t *)(base + sizeof(sp_file_hdr_t)); dvander@2226: dvander@2226: memset(plugin, 0, sizeof(sp_plugin_t)); dvander@2226: dvander@2226: plugin->base = base; dvander@2226: plugin->base_size = hdr->imagesize; dvander@2226: set_err = SP_ERROR_NONE; dvander@2226: dvander@2226: /* We have to read the name section first */ dvander@2226: for (sectnum = 0; sectnum < hdr->sections; sectnum++) dvander@2226: { dvander@2226: nameptr = (char *)(base + hdr->stringtab + secptr[sectnum].nameoffs); dvander@2226: if (strcmp(nameptr, ".names") == 0) dvander@2226: { dvander@2226: plugin->stringbase = (const char *)(base + secptr[sectnum].dataoffs); dvander@2226: break; dvander@2226: } dvander@2226: } dvander@2226: dvander@2226: sectnum = 0; dvander@2226: dvander@2226: /* Now read the rest of the sections */ dvander@2226: while (sectnum < hdr->sections) dvander@2226: { dvander@2226: nameptr = (char *)(base + hdr->stringtab + secptr->nameoffs); dvander@2226: dvander@2226: if (!(plugin->pcode) && !strcmp(nameptr, ".code")) dvander@2226: { dvander@2226: sp_file_code_t *cod = (sp_file_code_t *)(base + secptr->dataoffs); dvander@2226: dvander@2226: if (cod->codeversion < SP_CODEVERS_JIT1) dvander@2226: { dvander@2226: return SP_ERROR_CODE_TOO_OLD; dvander@2226: } dvander@2226: else if (cod->codeversion > SP_CODEVERS_JIT2) dvander@2226: { dvander@2226: return SP_ERROR_CODE_TOO_NEW; dvander@2226: } dvander@2226: dvander@2226: plugin->pcode = base + secptr->dataoffs + cod->code; dvander@2226: plugin->pcode_size = cod->codesize; dvander@2226: plugin->flags = cod->flags; dvander@2226: plugin->pcode_version = cod->codeversion; dvander@2226: } dvander@2226: else if (!(plugin->data) && !strcmp(nameptr, ".data")) dvander@2226: { dvander@2226: sp_file_data_t *dat = (sp_file_data_t *)(base + secptr->dataoffs); dvander@2226: plugin->data = base + secptr->dataoffs + dat->data; dvander@2226: plugin->data_size = dat->datasize; dvander@2226: plugin->mem_size = dat->memsize; dvander@2226: plugin->memory = new uint8_t[plugin->mem_size]; dvander@2226: memcpy(plugin->memory, plugin->data, plugin->data_size); dvander@2226: } dvander@2226: else if ((plugin->publics == NULL) && !strcmp(nameptr, ".publics")) dvander@2226: { dvander@2226: sp_file_publics_t *publics; dvander@2226: dvander@2226: publics = (sp_file_publics_t *)(base + secptr->dataoffs); dvander@2226: plugin->num_publics = secptr->size / sizeof(sp_file_publics_t); dvander@2226: dvander@2226: if (plugin->num_publics > 0) dvander@2226: { dvander@2226: plugin->publics = new sp_public_t[plugin->num_publics]; dvander@2226: dvander@2226: for (uint32_t i = 0; i < plugin->num_publics; i++) dvander@2226: { dvander@2226: plugin->publics[i].code_offs = publics[i].address; dvander@2226: plugin->publics[i].funcid = (i << 1) | 1; dvander@2226: plugin->publics[i].name = plugin->stringbase + publics[i].name; dvander@2226: } dvander@2226: } dvander@2226: } dvander@2226: else if ((plugin->pubvars == NULL) && !strcmp(nameptr, ".pubvars")) dvander@2226: { dvander@2226: sp_file_pubvars_t *pubvars; dvander@2226: dvander@2226: pubvars = (sp_file_pubvars_t *)(base + secptr->dataoffs); dvander@2226: plugin->num_pubvars = secptr->size / sizeof(sp_file_pubvars_t); dvander@2226: dvander@2226: if (plugin->num_pubvars > 0) dvander@2226: { dvander@2226: plugin->pubvars = new sp_pubvar_t[plugin->num_pubvars]; dvander@2226: dvander@2226: for (uint32_t i = 0; i < plugin->num_pubvars; i++) dvander@2226: { dvander@2226: plugin->pubvars[i].name = plugin->stringbase + pubvars[i].name; dvander@2226: plugin->pubvars[i].offs = (cell_t *)(plugin->memory + pubvars[i].address); dvander@2226: } dvander@2226: } dvander@2226: } dvander@2226: else if ((plugin->natives == NULL) && !strcmp(nameptr, ".natives")) dvander@2226: { dvander@2226: sp_file_natives_t *natives; dvander@2226: dvander@2226: natives = (sp_file_natives_t *)(base + secptr->dataoffs); dvander@2226: plugin->num_natives = secptr->size / sizeof(sp_file_natives_t); dvander@2226: dvander@2226: if (plugin->num_natives > 0) dvander@2226: { dvander@2226: plugin->natives = new sp_native_t[plugin->num_natives]; dvander@2226: dvander@2226: for (uint32_t i = 0; i < plugin->num_natives; i++) dvander@2226: { dvander@2226: plugin->natives[i].flags = 0; dvander@2226: plugin->natives[i].pfn = InvalidNative; dvander@2226: plugin->natives[i].status = SP_NATIVE_UNBOUND; dvander@2226: plugin->natives[i].user = NULL; dvander@2226: plugin->natives[i].name = plugin->stringbase + natives[i].name; dvander@2226: } dvander@2226: } dvander@2226: } dvander@2226: else if (!(plugin->debug.files) && !strcmp(nameptr, ".dbg.files")) dvander@2226: { dvander@2226: plugin->debug.files = (sp_fdbg_file_t *)(base + secptr->dataoffs); dvander@2226: } dvander@2226: else if (!(plugin->debug.lines) && !strcmp(nameptr, ".dbg.lines")) dvander@2226: { dvander@2226: plugin->debug.lines = (sp_fdbg_line_t *)(base + secptr->dataoffs); dvander@2226: } dvander@2226: else if (!(plugin->debug.symbols) && !strcmp(nameptr, ".dbg.symbols")) dvander@2226: { dvander@2226: plugin->debug.symbols = (sp_fdbg_symbol_t *)(base + secptr->dataoffs); dvander@2226: } dvander@2226: else if (!(plugin->debug.lines_num) && !strcmp(nameptr, ".dbg.info")) dvander@2226: { dvander@2226: sp_fdbg_info_t *inf = (sp_fdbg_info_t *)(base + secptr->dataoffs); dvander@2226: plugin->debug.files_num = inf->num_files; dvander@2226: plugin->debug.lines_num = inf->num_lines; dvander@2226: plugin->debug.syms_num = inf->num_syms; dvander@2226: } dvander@2226: else if (!(plugin->debug.stringbase) && !strcmp(nameptr, ".dbg.strings")) dvander@2226: { dvander@2226: plugin->debug.stringbase = (const char *)(base + secptr->dataoffs); dvander@2226: } dvander@2226: dvander@2226: secptr++; dvander@2226: sectnum++; dvander@2226: } dvander@2226: dvander@2226: if (plugin->pcode == NULL || plugin->data == NULL) dvander@2226: { dvander@2226: return SP_ERROR_FILE_FORMAT; dvander@2226: } dvander@2226: dvander@2226: if ((plugin->flags & SP_FLAG_DEBUG) && (!(plugin->debug.files) || !(plugin->debug.lines) || !(plugin->debug.symbols))) dvander@2226: { dvander@2226: return SP_ERROR_FILE_FORMAT; dvander@2226: } dvander@2226: dvander@2226: if (m_pPlugin->num_publics > 0) dvander@2226: { dvander@2226: m_PubFuncs = new CFunction *[m_pPlugin->num_publics]; dvander@2226: memset(m_PubFuncs, 0, sizeof(CFunction *) * m_pPlugin->num_publics); dvander@2226: m_PubJitFuncs = new JitFunction *[m_pPlugin->num_publics]; dvander@2226: memset(m_PubJitFuncs, 0, sizeof(JitFunction *) * m_pPlugin->num_publics); dvander@2226: } dvander@2226: dvander@2226: m_pPlugin->profiler = g_engine2.GetProfiler(); dvander@2226: m_pCtx = new BaseContext(this); dvander@2226: m_pCo = g_Jit.StartCompilation(this); dvander@2226: dvander@2226: return SP_ERROR_NONE; dvander@2193: } dvander@2193: dvander@2193: int BaseRuntime::FindNativeByName(const char *name, uint32_t *index) dvander@2193: { dvander@2193: int high; dvander@2193: dvander@2226: high = m_pPlugin->num_natives - 1; dvander@2193: dvander@2226: for (uint32_t i=0; inum_natives; i++) dvander@2193: { dvander@2193: if (strcmp(m_pPlugin->natives[i].name, name) == 0) dvander@2193: { dvander@2193: if (index) dvander@2193: { dvander@2193: *index = i; dvander@2193: } dvander@2193: return SP_ERROR_NONE; dvander@2193: } dvander@2193: } dvander@2193: dvander@2193: return SP_ERROR_NOT_FOUND; dvander@2193: } dvander@2193: dvander@2193: int BaseRuntime::GetNativeByIndex(uint32_t index, sp_native_t **native) dvander@2193: { dvander@2226: if (index >= m_pPlugin->num_natives) dvander@2193: { dvander@2193: return SP_ERROR_INDEX; dvander@2193: } dvander@2193: dvander@2193: if (native) dvander@2193: { dvander@2193: *native = &(m_pPlugin->natives[index]); dvander@2193: } dvander@2193: dvander@2193: return SP_ERROR_NONE; dvander@2193: } dvander@2193: dvander@2193: dvander@2193: uint32_t BaseRuntime::GetNativesNum() dvander@2193: { dvander@2226: return m_pPlugin->num_natives; dvander@2193: } dvander@2193: dvander@2193: int BaseRuntime::FindPublicByName(const char *name, uint32_t *index) dvander@2193: { dvander@2193: int diff, high, low; dvander@2193: uint32_t mid; dvander@2193: dvander@2226: high = m_pPlugin->num_publics - 1; dvander@2193: low = 0; dvander@2193: dvander@2193: while (low <= high) dvander@2193: { dvander@2193: mid = (low + high) / 2; dvander@2193: diff = strcmp(m_pPlugin->publics[mid].name, name); dvander@2193: if (diff == 0) dvander@2193: { dvander@2193: if (index) dvander@2193: { dvander@2193: *index = mid; dvander@2193: } dvander@2193: return SP_ERROR_NONE; dvander@2193: } else if (diff < 0) { dvander@2193: low = mid + 1; dvander@2193: } else { dvander@2193: high = mid - 1; dvander@2193: } dvander@2193: } dvander@2193: dvander@2193: return SP_ERROR_NOT_FOUND; dvander@2193: } dvander@2193: dvander@2193: int BaseRuntime::GetPublicByIndex(uint32_t index, sp_public_t **pblic) dvander@2193: { dvander@2226: if (index >= m_pPlugin->num_publics) dvander@2193: { dvander@2193: return SP_ERROR_INDEX; dvander@2193: } dvander@2193: dvander@2193: if (pblic) dvander@2193: { dvander@2193: *pblic = &(m_pPlugin->publics[index]); dvander@2193: } dvander@2193: dvander@2193: return SP_ERROR_NONE; dvander@2193: } dvander@2193: dvander@2193: uint32_t BaseRuntime::GetPublicsNum() dvander@2193: { dvander@2226: return m_pPlugin->num_publics; dvander@2193: } dvander@2193: dvander@2193: int BaseRuntime::GetPubvarByIndex(uint32_t index, sp_pubvar_t **pubvar) dvander@2193: { dvander@2226: if (index >= m_pPlugin->num_pubvars) dvander@2193: { dvander@2193: return SP_ERROR_INDEX; dvander@2193: } dvander@2193: dvander@2193: if (pubvar) dvander@2193: { dvander@2193: *pubvar = &(m_pPlugin->pubvars[index]); dvander@2193: } dvander@2193: dvander@2193: return SP_ERROR_NONE; dvander@2193: } dvander@2193: dvander@2193: int BaseRuntime::FindPubvarByName(const char *name, uint32_t *index) dvander@2193: { dvander@2193: int diff, high, low; dvander@2193: uint32_t mid; dvander@2193: dvander@2226: high = m_pPlugin->num_pubvars - 1; dvander@2193: low = 0; dvander@2193: dvander@2193: while (low <= high) dvander@2193: { dvander@2193: mid = (low + high) / 2; dvander@2193: diff = strcmp(m_pPlugin->pubvars[mid].name, name); dvander@2193: if (diff == 0) dvander@2193: { dvander@2193: if (index) dvander@2193: { dvander@2193: *index = mid; dvander@2193: } dvander@2193: return SP_ERROR_NONE; dvander@2226: } dvander@2226: else if (diff < 0) dvander@2226: { dvander@2193: low = mid + 1; dvander@2226: } dvander@2226: else dvander@2226: { dvander@2193: high = mid - 1; dvander@2193: } dvander@2193: } dvander@2193: dvander@2193: return SP_ERROR_NOT_FOUND; dvander@2193: } dvander@2193: dvander@2193: int BaseRuntime::GetPubvarAddrs(uint32_t index, cell_t *local_addr, cell_t **phys_addr) dvander@2193: { dvander@2226: if (index >= m_pPlugin->num_pubvars) dvander@2193: { dvander@2193: return SP_ERROR_INDEX; dvander@2193: } dvander@2193: dvander@2226: *local_addr = (uint8_t *)m_pPlugin->pubvars[index].offs - m_pPlugin->memory; dvander@2193: *phys_addr = m_pPlugin->pubvars[index].offs; dvander@2193: dvander@2193: return SP_ERROR_NONE; dvander@2193: } dvander@2193: dvander@2193: uint32_t BaseRuntime::GetPubVarsNum() dvander@2193: { dvander@2226: return m_pPlugin->num_pubvars; dvander@2193: } dvander@2193: dvander@2193: IPluginContext *BaseRuntime::GetDefaultContext() dvander@2193: { dvander@2193: return m_pCtx; dvander@2193: } dvander@2193: dvander@2193: IPluginDebugInfo *BaseRuntime::GetDebugInfo() dvander@2193: { dvander@2193: return &m_Debug; dvander@2193: } dvander@2193: dvander@2193: IPluginFunction *BaseRuntime::GetFunctionById(funcid_t func_id) dvander@2193: { dvander@2193: CFunction *pFunc = NULL; dvander@2193: dvander@2193: if (func_id & 1) dvander@2193: { dvander@2193: func_id >>= 1; dvander@2226: if (func_id >= m_pPlugin->num_publics) dvander@2193: { dvander@2193: return NULL; dvander@2193: } dvander@2193: pFunc = m_PubFuncs[func_id]; dvander@2193: if (!pFunc) dvander@2193: { dvander@2226: m_PubFuncs[func_id] = new CFunction(this, dvander@2193: (func_id << 1) | 1, dvander@2193: func_id); dvander@2193: pFunc = m_PubFuncs[func_id]; dvander@2193: } dvander@2193: } dvander@2193: dvander@2193: return pFunc; dvander@2193: } dvander@2193: dvander@2193: IPluginFunction *BaseRuntime::GetFunctionByName(const char *public_name) dvander@2193: { dvander@2193: uint32_t index; dvander@2193: dvander@2193: if (FindPublicByName(public_name, &index) != SP_ERROR_NONE) dvander@2193: { dvander@2193: return NULL; dvander@2193: } dvander@2193: dvander@2193: CFunction *pFunc = m_PubFuncs[index]; dvander@2193: if (!pFunc) dvander@2193: { dvander@2193: sp_public_t *pub = NULL; dvander@2193: GetPublicByIndex(index, &pub); dvander@2193: if (pub) dvander@2193: { dvander@2226: m_PubFuncs[index] = new CFunction(this, (index << 1) | 1, index); dvander@2193: } dvander@2193: pFunc = m_PubFuncs[index]; dvander@2193: } dvander@2193: dvander@2193: return pFunc; dvander@2193: } dvander@2193: dvander@2193: bool BaseRuntime::IsDebugging() dvander@2193: { dvander@2226: return true; dvander@2193: } dvander@2193: dvander@2193: void BaseRuntime::SetPauseState(bool paused) dvander@2193: { dvander@2193: if (paused) dvander@2193: { dvander@2193: m_pPlugin->run_flags |= SPFLAG_PLUGIN_PAUSED; dvander@2193: } dvander@2193: else dvander@2193: { dvander@2193: m_pPlugin->run_flags &= ~SPFLAG_PLUGIN_PAUSED; dvander@2193: } dvander@2193: } dvander@2193: dvander@2193: bool BaseRuntime::IsPaused() dvander@2193: { dvander@2193: return ((m_pPlugin->run_flags & SPFLAG_PLUGIN_PAUSED) == SPFLAG_PLUGIN_PAUSED); dvander@2193: } dvander@2193: dvander@2193: size_t BaseRuntime::GetMemUsage() dvander@2193: { dvander@2193: size_t mem = 0; dvander@2193: dvander@2193: mem += sizeof(this); dvander@2193: mem += sizeof(sp_plugin_t); dvander@2193: mem += sizeof(BaseContext); dvander@2193: mem += m_pPlugin->base_size; dvander@2193: dvander@2193: return mem; dvander@2193: } dvander@2193: dvander@2193: BaseContext *BaseRuntime::GetBaseContext() dvander@2193: { dvander@2193: return m_pCtx; dvander@2193: } dvander@2193: dvander@2226: int BaseRuntime::ApplyCompilationOptions(ICompilation *co) dvander@2226: { dvander@2226: if (co == NULL) dvander@2226: { dvander@2226: return SP_ERROR_NONE; dvander@2226: } dvander@2226: dvander@2226: m_pCo = g_Jit.ApplyOptions(m_pCo, co); dvander@2226: dvander@2226: return SP_ERROR_NONE; dvander@2226: } dvander@2226: dvander@2226: JitFunction *BaseRuntime::GetJittedFunction(uint32_t idx) dvander@2226: { dvander@2226: assert(idx <= m_NumFuncs); dvander@2226: dvander@2226: if (idx == 0 || idx > m_NumFuncs) dvander@2226: { dvander@2226: return NULL; dvander@2226: } dvander@2226: dvander@2226: return m_FuncCache[idx - 1]; dvander@2226: } dvander@2226: dvander@2226: uint32_t BaseRuntime::AddJittedFunction(JitFunction *fn) dvander@2226: { dvander@2226: if (m_NumFuncs + 1 > m_MaxFuncs) dvander@2226: { dvander@2226: if (m_MaxFuncs == 0) dvander@2226: { dvander@2226: m_MaxFuncs = 8; dvander@2226: } dvander@2226: else dvander@2226: { dvander@2226: m_MaxFuncs *= 2; dvander@2226: } dvander@2226: dvander@2226: m_FuncCache = (JitFunction **)realloc( dvander@2226: m_FuncCache, dvander@2226: sizeof(JitFunction *) * m_MaxFuncs); dvander@2226: } dvander@2226: dvander@2226: m_FuncCache[m_NumFuncs++] = fn; dvander@2226: dvander@2226: return m_NumFuncs; dvander@2226: }