From 438ccf39a03a019e60f9e0bd7343f1d5ffcd4565 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 11 Nov 2006 05:47:00 +0000 Subject: [PATCH] added new API for function address lookups. this gives us O(1) code_addr -> sequential index --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40180 --- sourcepawn/compiler/sc1.c | 2 + sourcepawn/include/sp_vm_api.h | 45 +++++++++++++++++----- sourcepawn/include/sp_vm_types.h | 2 +- sourcepawn/jit/x86/jit_x86.cpp | 64 ++++++++++++++++++++++++++++++-- sourcepawn/jit/x86/jit_x86.h | 22 ++++++++++- 5 files changed, 118 insertions(+), 17 deletions(-) diff --git a/sourcepawn/compiler/sc1.c b/sourcepawn/compiler/sc1.c index 7d621142..0f678fa1 100644 --- a/sourcepawn/compiler/sc1.c +++ b/sourcepawn/compiler/sc1.c @@ -505,6 +505,8 @@ cleanup: delete_pathtable(); delete_sourcefiletable(); delete_dbgstringtable(); + funcenums_free(); + pstructs_free(); #if !defined NO_DEFINE delete_substtable(); #endif diff --git a/sourcepawn/include/sp_vm_api.h b/sourcepawn/include/sp_vm_api.h index 1859324d..61cbecfc 100644 --- a/sourcepawn/include/sp_vm_api.h +++ b/sourcepawn/include/sp_vm_api.h @@ -4,6 +4,8 @@ #include #include "sp_vm_types.h" +#define SOURCEPAWN_VM_API_VERSION 1 + namespace SourcePawn { class IVirtualMachine; @@ -393,12 +395,17 @@ namespace SourcePawn { public: /** - * Returns the string name of a VM implementation. + * @brief Returns the current API version. + */ + virtual unsigned int GetAPIVersion() =0; + + /** + * @brief Returns the string name of a VM implementation. */ virtual const char *GetVMName() =0; /** - * Begins a new compilation + * @brief Begins a new compilation * * @param plugin Pointer to a plugin structure. * @return New compilation pointer. @@ -406,7 +413,7 @@ namespace SourcePawn virtual ICompilation *StartCompilation(sp_plugin_t *plugin) =0; /** - * Sets a compilation option. + * @brief Sets a compilation option. * * @param co Pointer to a compilation. * @param key Option key name. @@ -416,7 +423,7 @@ namespace SourcePawn virtual bool SetCompilationOption(ICompilation *co, const char *key, const char *val) =0; /** - * Finalizes a compilation into a new sp_context_t. + * @brief Finalizes a compilation into a new sp_context_t. * Note: This will free the ICompilation pointer. * * @param co Compilation pointer. @@ -426,28 +433,46 @@ namespace SourcePawn virtual sp_context_t *CompileToContext(ICompilation *co, int *err) =0; /** - * Aborts a compilation and frees the ICompilation pointer. + * @brief Aborts a compilation and frees the ICompilation pointer. * * @param co Compilation pointer. */ virtual void AbortCompilation(ICompilation *co) =0; /** - * Frees any internal variable usage on a context. + * @brief Frees any internal variable usage on a context. * * @param ctx Context structure pointer. */ virtual void FreeContext(sp_context_t *ctx) =0; /** - * Calls the "execute" function on a context. + * @brief Calls the "execute" function on a context. * * @param ctx Executes a function in a context. - * @param code_idx Index into the code section. - * @param result Pointer to store result in. + * @param code_addr Index into the code section. + * @param result Pointer to store result into. * @return Error code (if any). */ - virtual int ContextExecute(sp_context_t *ctx, uint32_t code_idx, cell_t *result) =0; + virtual int ContextExecute(sp_context_t *ctx, uint32_t code_addr, cell_t *result) =0; + + /** + * @brief Given a context and a code address, returns the index of the function. + * + * @param ctx Context to search. + * @param code_addr Index into the code section. + * @param result Pointer to store result into. + * @return True if code index is valid, false otherwise. + */ + virtual bool FunctionLookup(const sp_context_t *ctx, uint32_t code_addr, unsigned int *result) =0; + + /** + * @brief Returns the number of functions defined in the context. + * + * @param ctx Context to search. + * @return Number of functions. + */ + virtual unsigned int FunctionCount(const sp_context_t *ctx) =0; }; }; diff --git a/sourcepawn/include/sp_vm_types.h b/sourcepawn/include/sp_vm_types.h index 2c7bea84..91117b13 100644 --- a/sourcepawn/include/sp_vm_types.h +++ b/sourcepawn/include/sp_vm_types.h @@ -104,7 +104,7 @@ namespace SourcePawn struct sp_context_s; -typedef cell_t (*SPVM_NATIVE_FUNC)(struct sp_context_s *, cell_t *); +typedef cell_t (*SPVM_NATIVE_FUNC)(struct sp_context_s *, const cell_t *); /********************************************** *** The following structures are bound to the VM/JIT. diff --git a/sourcepawn/jit/x86/jit_x86.cpp b/sourcepawn/jit/x86/jit_x86.cpp index 1dfe2d97..aedd936a 100644 --- a/sourcepawn/jit/x86/jit_x86.cpp +++ b/sourcepawn/jit/x86/jit_x86.cpp @@ -233,6 +233,7 @@ inline void WriteOp_Proc(JitWriter *jit) * Just in case, we guard this memory with INT3 to break into the debugger. */ jitoffs_t cur_offs = jit->get_outputpos(); + CompData *co = (CompData *)jit->data; if (cur_offs % 4) { cur_offs = 4 - (cur_offs % 4); @@ -240,11 +241,25 @@ inline void WriteOp_Proc(JitWriter *jit) { jit->write_ubyte(IA32_INT3); } - /* add this amt to the offset we relocated */ + } + + /* Write the info struct about this function */ + jit->write_uint32(JIT_FUNCMAGIC); + jit->write_uint32(co->func_idx); + + /* Now we have to backpatch our reloction offset! */ + { jitoffs_t offs = jit->get_inputpos() - sizeof(cell_t); jitcode_t rebase = ((CompData *)jit->data)->rebase; *(jitoffs_t *)((unsigned char *)rebase + offs) = jit->get_outputpos(); } + + /* Lastly, if we're writing, keep track of the function count */ + if (jit->outbase) + { + co->func_idx++; + } + //push old frame on stack: //mov ecx, [esi+frm] //mov [edi-4], ecx @@ -1756,7 +1771,7 @@ cell_t NativeCallback(sp_context_t *ctx, ucell_t native_idx, cell_t *params) return native->pfn(ctx, params); } -cell_t InvalidNative(sp_context_t *ctx, cell_t *params) +cell_t InvalidNative(sp_context_t *ctx, const cell_t *params) { ctx->err = SP_ERROR_INVALID_NATIVE; @@ -1877,6 +1892,7 @@ sp_context_t *JITX86::CompileToContext(ICompilation *co, int *err) JitWriter writer; JitWriter *jit = &writer; cell_t *endptr = (cell_t *)(end_cip); + uint32_t codemem = 0; /* Initial code is written "blank," * so we can check the exact memory usage. @@ -1957,8 +1973,8 @@ jit_rewind: WriteErrorRoutines(data, jit); /* the total codesize is now known! */ - uint32_t mem = writer.get_outputpos(); - writer.outbase = (jitcode_t)engine->ExecAlloc(mem); + codemem = writer.get_outputpos(); + writer.outbase = (jitcode_t)engine->ExecAlloc(codemem); writer.outptr = writer.outbase; /* go back for third pass */ goto jit_rewind; @@ -2100,6 +2116,11 @@ jit_rewind: trk->pCur = trk->pBase; trk->size = 1024 / sizeof(cell_t); + functracker_t *fnc = new functracker_t; + ctx->vm[JITVARS_FUNCINFO] = fnc; + fnc->code_size = codemem; + fnc->num_functions = data->func_idx; + /* clean up relocation+compilation memory */ AbortCompilation(co); @@ -2172,3 +2193,38 @@ bool JITX86::SetCompilationOption(ICompilation *co, const char *key, const char return false; } + +unsigned int JITX86::GetAPIVersion() +{ + return SOURCEPAWN_VM_API_VERSION; +} + +bool JITX86::FunctionLookup(const sp_context_t *ctx, uint32_t code_addr, unsigned int *result) +{ + functracker_t *fnc = (functracker_t *)ctx->vm[JITVARS_FUNCINFO]; + + if (code_addr >= fnc->code_size) + { + return false; + } + + funcinfo_t *f = (funcinfo_t *)((char *)ctx->codebase + code_addr - sizeof(funcinfo_t)); + if (f->magic != JIT_FUNCMAGIC || f->index >= fnc->num_functions) + { + return false; + } + + if (result) + { + *result = f->index; + } + + return true; +} + +unsigned int JITX86::FunctionCount(const sp_context_t *ctx) +{ + functracker_t *fnc = (functracker_t *)ctx->vm[JITVARS_FUNCINFO]; + + return fnc->num_functions; +} diff --git a/sourcepawn/jit/x86/jit_x86.h b/sourcepawn/jit/x86/jit_x86.h index f4f40f4c..5f8eae60 100644 --- a/sourcepawn/jit/x86/jit_x86.h +++ b/sourcepawn/jit/x86/jit_x86.h @@ -9,9 +9,11 @@ using namespace SourcePawn; #define JIT_INLINE_ERRORCHECKS (1<<0) #define JIT_INLINE_NATIVES (1<<1) -#define STACK_MARGIN 64 //8 parameters of safety, I guess +#define STACK_MARGIN 64 //8 parameters of safety, I guess +#define JIT_FUNCMAGIC 0x214D4148 //magic function offset #define JITVARS_TRACKER 0 //important: don't change this to avoid trouble +#define JITVARS_FUNCINFO 1 //important: don't change this aWOAWOGJQG I LIKE HAM typedef struct tracker_s { @@ -20,12 +22,24 @@ typedef struct tracker_s ucell_t *pCur; } tracker_t; +typedef struct funcinfo_s +{ + unsigned int magic; + unsigned int index; +} funcinfo_t; + +typedef struct functracker_s +{ + unsigned int num_functions; + unsigned int code_size; +} functracker_t; + class CompData : public ICompilation { public: CompData() : plugin(NULL), debug(false), inline_level(0), rebase(NULL), - error_set(SP_ERROR_NONE) + error_set(SP_ERROR_NONE), func_idx(0) { }; public: @@ -49,6 +63,7 @@ public: jitoffs_t jit_extern_error; /* returning generic error */ jitoffs_t jit_sysreq_c; /* old version! */ uint32_t codesize; /* total codesize */ + unsigned int func_idx; /* current function index */ int inline_level; /* inline optimization level */ int error_set; /* error code to halt process */ bool debug; /* whether to compile debug mode */ @@ -64,6 +79,9 @@ public: void AbortCompilation(ICompilation *co); void FreeContext(sp_context_t *ctx); int ContextExecute(sp_context_t *ctx, uint32_t code_idx, cell_t *result); + unsigned int GetAPIVersion(); + bool FunctionLookup(const sp_context_t *ctx, uint32_t code_addr, unsigned int *result); + unsigned int FunctionCount(const sp_context_t *ctx); }; cell_t NativeCallback(sp_context_t *ctx, ucell_t native_idx, cell_t *params);