Merge pull request #280 from alliedmodders/rm-ctx

Remove sp_context_t.
This commit is contained in:
David Anderson 2015-02-26 15:46:32 -08:00
commit 9a37b94f4d
14 changed files with 631 additions and 521 deletions

View File

@ -18,7 +18,10 @@ def setup(binary):
compiler = binary.compiler
compiler.includes += Includes
if compiler.vendor == 'gcc' or compiler.vendor == 'clang':
compiler.cxxflags += ['-fno-rtti']
compiler.cxxflags += [
'-fno-rtti',
'-Wno-invalid-offsetof',
]
elif binary.compiler.vendor == 'msvc':
compiler.cxxflags += ['/GR-']

View File

@ -16,13 +16,13 @@
#include <stdint.h>
#include <sp_vm_api.h>
typedef struct sp_context_s sp_context_t;
class PluginContext;
namespace sp {
class Environment;
typedef int (*InvokeStubFn)(sp_context_t *ctx, uint8_t *memory, void *code);
typedef int (*InvokeStubFn)(PluginContext *cx, void *code, cell_t *rval);
class CodeStubs
{

View File

@ -20,12 +20,12 @@ using namespace SourcePawn;
CContextTrace::CContextTrace(PluginRuntime *pRuntime, int err, const char *errstr, cell_t start_rp)
: m_pRuntime(pRuntime),
context_(pRuntime->GetBaseContext()),
m_Error(err),
m_pMsg(errstr),
m_StartRp(start_rp),
m_Level(0)
{
m_ctx = pRuntime->m_pCtx->GetCtx();
m_pDebug = m_pRuntime->GetDebugInfo();
}
@ -65,21 +65,19 @@ CContextTrace::GetTraceInfo(CallStackInfo *trace)
cell_t cip;
if (m_Level == 0) {
cip = m_ctx->cip;
} else if (m_ctx->rp > 0) {
cip = context_->cip();
} else if (context_->rp() > 0) {
/* Entries go from ctx.rp - 1 to m_StartRp */
cell_t offs, start, end;
offs = m_Level - 1;
start = m_ctx->rp - 1;
start = context_->rp() - 1;
end = m_StartRp;
if (start - offs < end)
{
return false;
}
cip = m_ctx->rstk_cips[start - offs];
cip = context_->getReturnStackCip(start - offs);
} else {
return false;
}
@ -106,15 +104,19 @@ CContextTrace::GetTraceInfo(CallStackInfo *trace)
const char *
CContextTrace::GetLastNative(uint32_t *index)
{
if (m_ctx->n_err == SP_ERROR_NONE)
if (context_->GetLastNativeError() == SP_ERROR_NONE)
return NULL;
int lastNative = context_->lastNative();
if (lastNative < 0)
return NULL;
sp_native_t *native;
if (m_pRuntime->GetNativeByIndex(m_ctx->n_idx, &native) != SP_ERROR_NONE)
if (m_pRuntime->GetNativeByIndex(lastNative, &native) != SP_ERROR_NONE)
return NULL;
if (index)
*index = m_ctx->n_idx;
*index = lastNative;
return native->name;
}

View File

@ -16,6 +16,7 @@
#include <sp_vm_api.h>
class PluginRuntime;
class PluginContext;
namespace sp {
@ -37,7 +38,7 @@ class CContextTrace : public IContextTrace
private:
PluginRuntime *m_pRuntime;
sp_context_t *m_ctx;
PluginContext *context_;
int m_Error;
const char *m_pMsg;
cell_t m_StartRp;

View File

@ -238,17 +238,16 @@ Environment::UnpatchAllJumpsFromTimeout()
int
Environment::Invoke(PluginRuntime *runtime, CompiledFunction *fn, cell_t *result)
{
sp_context_t *ctx = runtime->GetBaseContext()->GetCtx();
PluginContext *cx = runtime->GetBaseContext();
// Note that cip, hp, sp are saved and restored by Execute2().
ctx->cip = fn->GetCodeOffset();
*cx->addressOfCip() = fn->GetCodeOffset();
InvokeStubFn invoke = code_stubs_->InvokeStub();
EnterInvoke();
int err = invoke(ctx, runtime->plugin()->memory, fn->GetEntryAddress());
int err = invoke(cx, fn->GetEntryAddress(), result);
LeaveInvoke();
*result = ctx->rval;
return err;
}

View File

@ -45,187 +45,34 @@ Write(const sp_plugin_t *plugin, cell_t offset, cell_t value)
}
static inline cell_t *
Jump(const sp_plugin_t *plugin, sp_context_t *ctx, cell_t target)
Jump(const sp_plugin_t *plugin, cell_t target)
{
if (!IsValidOffset(target) || uint32_t(target) >= plugin->pcode_size) {
ctx->err = SP_ERROR_INVALID_INSTRUCTION;
if (!IsValidOffset(target) || uint32_t(target) >= plugin->pcode_size)
return NULL;
}
return reinterpret_cast<cell_t *>(plugin->pcode + target);
}
static inline cell_t *
JumpTarget(const sp_plugin_t *plugin, sp_context_t *ctx, cell_t *cip, bool cond)
JumpTarget(const sp_plugin_t *plugin, cell_t *cip, bool cond, int *errp)
{
if (!cond)
return cip + 1;
cell_t target = *cip;
if (!IsValidOffset(target) || uint32_t(target) >= plugin->pcode_size) {
ctx->err = SP_ERROR_INVALID_INSTRUCTION;
*errp = SP_ERROR_INVALID_INSTRUCTION;
return NULL;
}
cell_t *next = reinterpret_cast<cell_t *>(plugin->pcode + target);
if (next < cip && !Environment::get()->watchdog()->HandleInterrupt()) {
ctx->err = SP_ERROR_TIMEOUT;
*errp = SP_ERROR_TIMEOUT;
return NULL;
}
return next;
}
static inline bool
CheckAddress(const sp_plugin_t *plugin, sp_context_t *ctx, cell_t *stk, cell_t addr)
{
if (uint32_t(addr) >= plugin->mem_size) {
ctx->err = SP_ERROR_MEMACCESS;
return false;
}
if (addr < ctx->hp)
return true;
if (reinterpret_cast<cell_t *>(plugin->memory + addr) < stk) {
ctx->err = SP_ERROR_MEMACCESS;
return false;
}
return true;
}
int
PopTrackerAndSetHeap(PluginRuntime *rt)
{
sp_context_t *ctx = rt->GetBaseContext()->GetCtx();
tracker_t *trk = ctx->tracker;
assert(trk->pCur > trk->pBase);
trk->pCur--;
if (trk->pCur < trk->pBase)
return SP_ERROR_TRACKER_BOUNDS;
ucell_t amt = *trk->pCur;
if (amt > (ctx->hp - rt->plugin()->data_size))
return SP_ERROR_HEAPMIN;
ctx->hp -= amt;
return SP_ERROR_NONE;
}
int
PushTracker(sp_context_t *ctx, size_t amount)
{
tracker_t *trk = ctx->tracker;
if ((size_t)(trk->pCur - trk->pBase) >= trk->size)
return SP_ERROR_TRACKER_BOUNDS;
if (trk->pCur + 1 - (trk->pBase + trk->size) == 0) {
size_t disp = trk->size - 1;
trk->size *= 2;
trk->pBase = (ucell_t *)realloc(trk->pBase, trk->size * sizeof(cell_t));
if (!trk->pBase)
return SP_ERROR_TRACKER_BOUNDS;
trk->pCur = trk->pBase + disp;
}
*trk->pCur++ = amount;
return SP_ERROR_NONE;
}
cell_t
NativeCallback(sp_context_t *ctx, ucell_t native_idx, cell_t *params)
{
cell_t save_sp = ctx->sp;
cell_t save_hp = ctx->hp;
ctx->n_idx = native_idx;
sp_native_t *native = &ctx->plugin->natives[native_idx];
if (native->status == SP_NATIVE_UNBOUND) {
ctx->n_err = SP_ERROR_INVALID_NATIVE;
return 0;
}
cell_t result = native->pfn(ctx->basecx, params);
if (ctx->n_err != SP_ERROR_NONE)
return result;
if (save_sp != ctx->sp) {
ctx->n_err = SP_ERROR_STACKLEAK;
return result;
}
if (save_hp != ctx->hp) {
ctx->n_err = SP_ERROR_HEAPLEAK;
return result;
}
return result;
}
cell_t
BoundNativeCallback(sp_context_t *ctx, SPVM_NATIVE_FUNC pfn, cell_t *params)
{
cell_t save_sp = ctx->sp;
cell_t save_hp = ctx->hp;
cell_t result = pfn(ctx->basecx, params);
if (ctx->n_err != SP_ERROR_NONE)
return result;
if (save_sp != ctx->sp) {
ctx->n_err = SP_ERROR_STACKLEAK;
return result;
}
if (save_hp != ctx->hp) {
ctx->n_err = SP_ERROR_HEAPLEAK;
return result;
}
return result;
}
static inline bool
GenerateArray(PluginRuntime *rt, sp_context_t *ctx, cell_t dims, cell_t *stk, bool autozero)
{
if (dims == 1) {
uint32_t size = *stk;
if (size == 0 || !ke::IsUint32MultiplySafe(size, 4)) {
ctx->err = SP_ERROR_ARRAY_TOO_BIG;
return false;
}
*stk = ctx->hp;
uint32_t bytes = size * 4;
ctx->hp += bytes;
if (uintptr_t(ctx->plugin->memory + ctx->hp) >= uintptr_t(stk)) {
ctx->err = SP_ERROR_HEAPLOW;
return false;
}
if ((ctx->err = PushTracker(ctx, bytes)) != SP_ERROR_NONE)
return false;
if (autozero)
memset(ctx->plugin->memory + ctx->hp, 0, bytes);
return true;
}
if ((ctx->err = GenerateFullArray(rt, dims, stk, autozero)) != SP_ERROR_NONE)
return false;
return true;
}
int
Interpret(PluginRuntime *rt, uint32_t aCodeStart, cell_t *rval)
{
@ -236,21 +83,25 @@ Interpret(PluginRuntime *rt, uint32_t aCodeStart, cell_t *rval)
if (!IsValidOffset(aCodeStart) || aCodeStart > plugin->pcode_size)
return SP_ERROR_INVALID_INSTRUCTION;
sp_context_t *ctx = rt->GetBaseContext()->GetCtx();
ctx->err = SP_ERROR_NONE;
PluginContext *cx = rt->GetBaseContext();
int err = SP_ERROR_NONE;
// Save the original frm. BaseContext won't, and if we error, we won't hit
// the stack unwinding code.
cell_t orig_frm = ctx->frm;
cell_t orig_frm = cx->frm();
cell_t &frm = *cx->addressOfFrm();
cell_t &sp = *cx->addressOfSp();
cell_t pri = 0;
cell_t alt = 0;
cell_t *cip = code + (aCodeStart / 4);
cell_t *stk = reinterpret_cast<cell_t *>(plugin->memory + ctx->sp);
cell_t *stk = reinterpret_cast<cell_t *>(plugin->memory + sp);
for (;;) {
if (cip >= codeend) {
ctx->err = SP_ERROR_INVALID_INSTRUCTION;
err = SP_ERROR_INVALID_INSTRUCTION;
goto error;
}
@ -281,7 +132,7 @@ Interpret(PluginRuntime *rt, uint32_t aCodeStart, cell_t *rval)
break;
case OP_ZERO_S:
Write(plugin, ctx->frm + *cip++, 0);
Write(plugin, frm + *cip++, 0);
break;
case OP_PUSH_PRI:
@ -321,7 +172,7 @@ Interpret(PluginRuntime *rt, uint32_t aCodeStart, cell_t *rval)
int i = 1;
do {
cell_t addr = ctx->frm + *cip++;
cell_t addr = frm + *cip++;
*--stk = addr;
} while (i++ < n);
break;
@ -339,7 +190,7 @@ Interpret(PluginRuntime *rt, uint32_t aCodeStart, cell_t *rval)
int i = 1;
do {
cell_t value = Read(plugin, ctx->frm + *cip++);
cell_t value = Read(plugin, frm + *cip++);
*--stk = value;
} while (i++ < n);
break;
@ -384,9 +235,9 @@ Interpret(PluginRuntime *rt, uint32_t aCodeStart, cell_t *rval)
case OP_PROC:
{
*--stk = ctx->frm;
*--stk = frm;
*--stk = 0;
ctx->frm = uintptr_t(stk) - uintptr_t(plugin->memory);
frm = uintptr_t(stk) - uintptr_t(plugin->memory);
break;
}
@ -505,14 +356,16 @@ Interpret(PluginRuntime *rt, uint32_t aCodeStart, cell_t *rval)
case OP_INC_S:
{
cell_t offset = *cip++;
cell_t value = Read(plugin, ctx->frm + offset);
Write(plugin, ctx->frm + offset, value + 1);
cell_t value = Read(plugin, frm + offset);
Write(plugin, frm + offset, value + 1);
break;
}
case OP_INC_I:
if (!CheckAddress(plugin, ctx, stk, pri))
if (!cx->checkAddress(stk, pri)) {
err = SP_ERROR_MEMACCESS;
goto error;
}
Write(plugin, pri, Read(plugin, pri) + 1);
break;
@ -533,14 +386,16 @@ Interpret(PluginRuntime *rt, uint32_t aCodeStart, cell_t *rval)
case OP_DEC_S:
{
cell_t offset = *cip++;
cell_t value = Read(plugin, ctx->frm + offset);
Write(plugin, ctx->frm + offset, value - 1);
cell_t value = Read(plugin, frm + offset);
Write(plugin, frm + offset, value - 1);
break;
}
case OP_DEC_I:
if (!CheckAddress(plugin, ctx, stk, pri))
if (!cx->checkAddress(stk, pri)) {
err = SP_ERROR_MEMACCESS;
goto error;
}
Write(plugin, pri, Read(plugin, pri) - 1);
break;
@ -552,27 +407,27 @@ Interpret(PluginRuntime *rt, uint32_t aCodeStart, cell_t *rval)
break;
case OP_LOAD_S_PRI:
pri = Read(plugin, ctx->frm + *cip++);
pri = Read(plugin, frm + *cip++);
break;
case OP_LOAD_S_ALT:
alt = Read(plugin, ctx->frm + *cip++);
alt = Read(plugin, frm + *cip++);
break;
case OP_LOAD_S_BOTH:
pri = Read(plugin, ctx->frm + *cip++);
alt = Read(plugin, ctx->frm + *cip++);
pri = Read(plugin, frm + *cip++);
alt = Read(plugin, frm + *cip++);
break;
case OP_LREF_S_PRI:
{
pri = Read(plugin, ctx->frm + *cip++);
pri = Read(plugin, frm + *cip++);
pri = Read(plugin, pri);
break;
}
case OP_LREF_S_ALT:
{
alt = Read(plugin, ctx->frm + *cip++);
alt = Read(plugin, frm + *cip++);
alt = Read(plugin, alt);
break;
}
@ -585,10 +440,10 @@ Interpret(PluginRuntime *rt, uint32_t aCodeStart, cell_t *rval)
break;
case OP_ADDR_PRI:
pri = ctx->frm + *cip++;
pri = frm + *cip++;
break;
case OP_ADDR_ALT:
alt = ctx->frm + *cip++;
alt = frm + *cip++;
break;
case OP_STOR_PRI:
@ -599,10 +454,10 @@ Interpret(PluginRuntime *rt, uint32_t aCodeStart, cell_t *rval)
break;
case OP_STOR_S_PRI:
Write(plugin, ctx->frm + *cip++, pri);
Write(plugin, frm + *cip++, pri);
break;
case OP_STOR_S_ALT:
Write(plugin, ctx->frm +*cip++, alt);
Write(plugin, frm +*cip++, alt);
break;
case OP_IDXADDR:
@ -612,7 +467,7 @@ Interpret(PluginRuntime *rt, uint32_t aCodeStart, cell_t *rval)
case OP_SREF_S_PRI:
{
cell_t offset = *cip++;
cell_t addr = Read(plugin, ctx->frm + offset);
cell_t addr = Read(plugin, frm + offset);
Write(plugin, addr, pri);
break;
}
@ -620,7 +475,7 @@ Interpret(PluginRuntime *rt, uint32_t aCodeStart, cell_t *rval)
case OP_SREF_S_ALT:
{
cell_t offset = *cip++;
cell_t addr = Read(plugin, ctx->frm + offset);
cell_t addr = Read(plugin, frm + offset);
Write(plugin, addr, alt);
break;
}
@ -644,8 +499,10 @@ Interpret(PluginRuntime *rt, uint32_t aCodeStart, cell_t *rval)
case OP_LIDX:
pri = alt + pri * 4;
if (!CheckAddress(plugin, ctx, stk, pri))
if (!cx->checkAddress(stk, pri)) {
err = SP_ERROR_MEMACCESS;
goto error;
}
pri = Read(plugin, pri);
break;
@ -653,8 +510,10 @@ Interpret(PluginRuntime *rt, uint32_t aCodeStart, cell_t *rval)
{
cell_t val = *cip++;
pri = alt + (pri << val);
if (!CheckAddress(plugin, ctx, stk, pri))
if (!cx->checkAddress(stk, pri)) {
err = SP_ERROR_MEMACCESS;
goto error;
}
pri = Read(plugin, pri);
break;
}
@ -671,19 +530,23 @@ Interpret(PluginRuntime *rt, uint32_t aCodeStart, cell_t *rval)
{
cell_t offset = *cip++;
cell_t value = *cip++;
Write(plugin, ctx->frm + offset, value);
Write(plugin, frm + offset, value);
break;
}
case OP_LOAD_I:
if (!CheckAddress(plugin, ctx, stk, pri))
if (!cx->checkAddress(stk, pri)) {
err = SP_ERROR_MEMACCESS;
goto error;
}
pri = Read(plugin, pri);
break;
case OP_STOR_I:
if (!CheckAddress(plugin, ctx, stk, alt))
if (!cx->checkAddress(stk, alt)) {
err = SP_ERROR_MEMACCESS;
goto error;
}
Write(plugin, alt, pri);
break;
@ -693,11 +556,11 @@ Interpret(PluginRuntime *rt, uint32_t aCodeStart, cell_t *rval)
cell_t dividend = (op == OP_SDIV) ? pri : alt;
cell_t divisor = (op == OP_SDIV) ? alt : pri;
if (divisor == 0) {
ctx->err = SP_ERROR_DIVIDE_BY_ZERO;
err = SP_ERROR_DIVIDE_BY_ZERO;
goto error;
}
if (dividend == INT_MIN && divisor == -1) {
ctx->err = SP_ERROR_INTEGER_OVERFLOW;
err = SP_ERROR_INTEGER_OVERFLOW;
goto error;
}
pri = dividend / divisor;
@ -708,8 +571,10 @@ Interpret(PluginRuntime *rt, uint32_t aCodeStart, cell_t *rval)
case OP_LODB_I:
{
cell_t val = *cip++;
if (!CheckAddress(plugin, ctx, stk, pri))
if (!cx->checkAddress(stk, pri)) {
err = SP_ERROR_MEMACCESS;
goto error;
}
pri = Read(plugin, pri);
if (val == 1)
pri &= 0xff;
@ -721,8 +586,10 @@ Interpret(PluginRuntime *rt, uint32_t aCodeStart, cell_t *rval)
case OP_STRB_I:
{
cell_t val = *cip++;
if (!CheckAddress(plugin, ctx, stk, alt))
if (!cx->checkAddress(stk, alt)) {
err = SP_ERROR_MEMACCESS;
goto error;
}
if (val == 1)
*reinterpret_cast<int8_t *>(plugin->memory + alt) = pri;
else if (val == 2)
@ -735,10 +602,10 @@ Interpret(PluginRuntime *rt, uint32_t aCodeStart, cell_t *rval)
case OP_RETN:
{
stk++;
ctx->frm = *stk++;
frm = *stk++;
stk += *stk + 1;
*rval = pri;
ctx->err = SP_ERROR_NONE;
err = SP_ERROR_NONE;
goto done;
}
@ -766,19 +633,19 @@ Interpret(PluginRuntime *rt, uint32_t aCodeStart, cell_t *rval)
{
cell_t amount = *cip++;
if (!IsValidOffset(amount)) {
ctx->err = SP_ERROR_INVALID_INSTRUCTION;
err = SP_ERROR_INVALID_INSTRUCTION;
goto error;
}
stk += amount / 4;
if (amount > 0) {
if (uintptr_t(stk) >= uintptr_t(plugin->memory + plugin->mem_size)) {
ctx->err = SP_ERROR_STACKMIN;
err = SP_ERROR_STACKMIN;
goto error;
}
} else {
if (uintptr_t(stk) < uintptr_t(plugin->memory + ctx->hp + STACK_MARGIN)) {
ctx->err = SP_ERROR_STACKLOW;
if (uintptr_t(stk) < uintptr_t(plugin->memory + cx->hp() + STACK_MARGIN)) {
err = SP_ERROR_STACKLOW;
goto error;
}
}
@ -789,17 +656,17 @@ Interpret(PluginRuntime *rt, uint32_t aCodeStart, cell_t *rval)
{
cell_t amount = *cip++;
alt = ctx->hp;
ctx->hp += amount;
alt = cx->hp();
*cx->addressOfHp() += amount;
if (amount > 0) {
if (uintptr_t(plugin->memory + ctx->hp) > uintptr_t(stk)) {
ctx->err = SP_ERROR_HEAPLOW;
if (uintptr_t(plugin->memory + cx->hp()) > uintptr_t(stk)) {
err = SP_ERROR_HEAPLOW;
goto error;
}
} else {
if (uint32_t(ctx->hp) < plugin->data_size) {
ctx->err = SP_ERROR_HEAPMIN;
if (uint32_t(cx->hp()) < plugin->data_size) {
err = SP_ERROR_HEAPMIN;
goto error;
}
}
@ -807,50 +674,50 @@ Interpret(PluginRuntime *rt, uint32_t aCodeStart, cell_t *rval)
}
case OP_JUMP:
if ((cip = JumpTarget(plugin, ctx, cip, true)) == NULL)
if ((cip = JumpTarget(plugin, cip, true, &err)) == NULL)
goto error;
break;
case OP_JZER:
if ((cip = JumpTarget(plugin, ctx, cip, pri == 0)) == NULL)
if ((cip = JumpTarget(plugin, cip, pri == 0, &err)) == NULL)
goto error;
break;
case OP_JNZ:
if ((cip = JumpTarget(plugin, ctx, cip, pri != 0)) == NULL)
if ((cip = JumpTarget(plugin, cip, pri != 0, &err)) == NULL)
goto error;
break;
case OP_JEQ:
if ((cip = JumpTarget(plugin, ctx, cip, pri == alt)) == NULL)
if ((cip = JumpTarget(plugin, cip, pri == alt, &err)) == NULL)
goto error;
break;
case OP_JNEQ:
if ((cip = JumpTarget(plugin, ctx, cip, pri != alt)) == NULL)
if ((cip = JumpTarget(plugin, cip, pri != alt, &err)) == NULL)
goto error;
break;
case OP_JSLESS:
if ((cip = JumpTarget(plugin, ctx, cip, pri < alt)) == NULL)
if ((cip = JumpTarget(plugin, cip, pri < alt, &err)) == NULL)
goto error;
break;
case OP_JSLEQ:
if ((cip = JumpTarget(plugin, ctx, cip, pri <= alt)) == NULL)
if ((cip = JumpTarget(plugin, cip, pri <= alt, &err)) == NULL)
goto error;
break;
case OP_JSGRTR:
if ((cip = JumpTarget(plugin, ctx, cip, pri > alt)) == NULL)
if ((cip = JumpTarget(plugin, cip, pri > alt, &err)) == NULL)
goto error;
break;
case OP_JSGEQ:
if ((cip = JumpTarget(plugin, ctx, cip, pri >= alt)) == NULL)
if ((cip = JumpTarget(plugin, cip, pri >= alt, &err)) == NULL)
goto error;
break;
case OP_TRACKER_PUSH_C:
{
cell_t amount = *cip++;
int error = PushTracker(ctx, amount * 4);
int error = cx->pushTracker(amount * 4);
if (error != SP_ERROR_NONE) {
ctx->err = error;
err = error;
goto error;
}
break;
@ -858,23 +725,23 @@ Interpret(PluginRuntime *rt, uint32_t aCodeStart, cell_t *rval)
case OP_TRACKER_POP_SETHEAP:
{
int error = PopTrackerAndSetHeap(rt);
int error = cx->popTrackerAndSetHeap();
if (error != SP_ERROR_NONE) {
ctx->err = error;
err = error;
goto error;
}
break;
}
case OP_BREAK:
ctx->cip = uintptr_t(cip - 1) - uintptr_t(plugin->pcode);
*cx->addressOfCip() = uintptr_t(cip - 1) - uintptr_t(plugin->pcode);
break;
case OP_BOUNDS:
{
cell_t value = *cip++;
if (uint32_t(pri) > uint32_t(value)) {
ctx->err = SP_ERROR_ARRAY_BOUNDS;
err = SP_ERROR_ARRAY_BOUNDS;
goto error;
}
break;
@ -885,26 +752,24 @@ Interpret(PluginRuntime *rt, uint32_t aCodeStart, cell_t *rval)
cell_t offset = *cip++;
if (!IsValidOffset(offset) || uint32_t(offset) >= plugin->pcode_size) {
ctx->err = SP_ERROR_INSTRUCTION_PARAM;
goto error;
}
if (ctx->rp >= SP_MAX_RETURN_STACK) {
ctx->err = SP_ERROR_STACKLOW;
err = SP_ERROR_INSTRUCTION_PARAM;
goto error;
}
// For debugging.
uintptr_t rcip = uintptr_t(cip - 2) - uintptr_t(plugin->pcode);
ctx->rstk_cips[ctx->rp++] = rcip;
ctx->cip = offset;
ctx->sp = uintptr_t(stk) - uintptr_t(plugin->memory);
if (!cx->pushReturnCip(rcip)) {
err = SP_ERROR_STACKLOW;
goto error;
}
*cx->addressOfCip() = offset;
sp = uintptr_t(stk) - uintptr_t(plugin->memory);
int err = Interpret(rt, offset, &pri);
stk = reinterpret_cast<cell_t *>(plugin->memory + ctx->sp);
ctx->cip = rcip;
ctx->rp--;
stk = reinterpret_cast<cell_t *>(plugin->memory + sp);
*cx->addressOfCip() = rcip;
cx->popReturnCip();
if (err != SP_ERROR_NONE)
goto error;
@ -915,7 +780,7 @@ Interpret(PluginRuntime *rt, uint32_t aCodeStart, cell_t *rval)
case OP_GENARRAY_Z:
{
cell_t val = *cip++;
if (!GenerateArray(rt, ctx, val, stk, op == OP_GENARRAY_Z))
if ((err = cx->generateArray(val, stk, op == OP_GENARRAY_Z)) != SP_ERROR_NONE)
goto error;
stk += (val - 1) * 4;
@ -928,7 +793,7 @@ Interpret(PluginRuntime *rt, uint32_t aCodeStart, cell_t *rval)
uint32_t native_index = *cip++;
if (native_index >= plugin->num_natives) {
ctx->err = SP_ERROR_INSTRUCTION_PARAM;
err = SP_ERROR_INSTRUCTION_PARAM;
goto error;
}
@ -938,10 +803,10 @@ Interpret(PluginRuntime *rt, uint32_t aCodeStart, cell_t *rval)
*--stk = num_params;
}
ctx->sp = uintptr_t(stk) - uintptr_t(plugin->memory);
pri = NativeCallback(ctx, native_index, stk);
if (ctx->n_err != SP_ERROR_NONE) {
ctx->err = ctx->n_err;
sp = uintptr_t(stk) - uintptr_t(plugin->memory);
pri = cx->invokeNative(native_index, stk);
if (cx->GetLastNativeError() != SP_ERROR_NONE) {
err = cx->GetLastNativeError();
goto error;
}
@ -965,26 +830,28 @@ Interpret(PluginRuntime *rt, uint32_t aCodeStart, cell_t *rval)
}
}
if ((cip = Jump(plugin, ctx, target)) == NULL)
if ((cip = Jump(plugin, target)) == NULL) {
err = SP_ERROR_INVALID_INSTRUCTION;
goto error;
}
break;
}
default:
{
ctx->err = SP_ERROR_INVALID_INSTRUCTION;
err = SP_ERROR_INVALID_INSTRUCTION;
goto error;
}
} // switch
}
done:
assert(orig_frm == ctx->frm);
ctx->sp = uintptr_t(stk) - uintptr_t(plugin->memory);
return ctx->err;
assert(orig_frm == frm);
sp = uintptr_t(stk) - uintptr_t(plugin->memory);
return err;
error:
ctx->frm = orig_frm;
frm = orig_frm;
goto done;
}

View File

@ -22,19 +22,6 @@
#include "plugin-runtime.h"
#include "plugin-context.h"
struct tracker_t
{
size_t size;
ucell_t *pBase;
ucell_t *pCur;
};
int Interpret(PluginRuntime *rt, uint32_t aCodeStart, cell_t *rval);
int GenerateFullArray(PluginRuntime *rt, uint32_t argc, cell_t *argv, int autozero);
cell_t NativeCallback(sp_context_t *ctx, ucell_t native_idx, cell_t *params);
cell_t BoundNativeCallback(sp_context_t *ctx, SPVM_NATIVE_FUNC pfn, cell_t *params);
int PopTrackerAndSetHeap(PluginRuntime *rt);
int PushTracker(sp_context_t *ctx, size_t amount);
#endif // _include_sourcepawn_interpreter_h_

View File

@ -68,27 +68,8 @@ namespace SourcePawn
} sp_plugin_t;
}
struct tracker_t;
class PluginContext;
typedef struct sp_context_s
{
cell_t hp; /**< Heap pointer */
cell_t sp; /**< Stack pointer */
cell_t frm; /**< Frame pointer */
cell_t rval; /**< Return value from InvokeFunction() */
int32_t cip; /**< Code pointer last error occurred in */
int32_t err; /**< Error last set by interpreter */
int32_t n_err; /**< Error code set by a native */
uint32_t n_idx; /**< Current native index being executed */
tracker_t *tracker;
sp_plugin_t *plugin;
PluginContext *basecx;
void * vm[8]; /**< VM-specific pointers */
cell_t rp; /**< Return stack pointer */
cell_t rstk_cips[SP_MAX_RETURN_STACK];
} sp_context_t;
//#define SPFLAG_PLUGIN_DEBUG (1<<0)
#define SPFLAG_PLUGIN_PAUSED (1<<1)

View File

@ -51,25 +51,21 @@ PluginContext::PluginContext(PluginRuntime *pRuntime)
m_pNullString = NULL;
}
m_ctx.hp = m_pRuntime->plugin()->data_size;
m_ctx.sp = m_pRuntime->plugin()->mem_size - sizeof(cell_t);
m_ctx.frm = m_ctx.sp;
m_ctx.n_err = SP_ERROR_NONE;
m_ctx.n_idx = SP_ERROR_NONE;
m_ctx.rp = 0;
hp_ = m_pRuntime->plugin()->data_size;
sp_ = m_pRuntime->plugin()->mem_size - sizeof(cell_t);
frm_ = sp_;
rp_ = 0;
last_native_ = -1;
native_error_ = SP_ERROR_NONE;
m_ctx.tracker = new tracker_t;
m_ctx.tracker->pBase = (ucell_t *)malloc(1024);
m_ctx.tracker->pCur = m_ctx.tracker->pBase;
m_ctx.tracker->size = 1024 / sizeof(cell_t);
m_ctx.basecx = this;
m_ctx.plugin = const_cast<sp_plugin_t *>(pRuntime->plugin());
tracker_.pBase = (ucell_t *)malloc(1024);
tracker_.pCur = tracker_.pBase;
tracker_.size = 1024 / sizeof(cell_t);
}
PluginContext::~PluginContext()
{
free(m_ctx.tracker->pBase);
delete m_ctx.tracker;
free(tracker_.pBase);
}
IVirtualMachine *
@ -84,12 +80,6 @@ PluginContext::GetContext()
return reinterpret_cast<sp_context_t *>((IPluginContext * )this);
}
sp_context_t *
PluginContext::GetCtx()
{
return &m_ctx;
}
bool
PluginContext::IsDebugging()
{
@ -137,7 +127,7 @@ PluginContext::ThrowNativeErrorEx(int error, const char *msg, ...)
if (!m_InExec)
return 0;
m_ctx.n_err = error;
native_error_ = error;
if (msg) {
va_list ap;
@ -155,7 +145,7 @@ PluginContext::ThrowNativeError(const char *msg, ...)
if (!m_InExec)
return 0;
m_ctx.n_err = SP_ERROR_NATIVE;
native_error_ = SP_ERROR_NATIVE;
if (msg) {
va_list ap;
@ -187,21 +177,21 @@ PluginContext::HeapAlloc(unsigned int cells, cell_t *local_addr, cell_t **phys_a
/**
* Check if the space between the heap and stack is sufficient.
*/
if ((cell_t)(m_ctx.sp - m_ctx.hp - realmem) < STACKMARGIN)
if ((cell_t)(sp_ - hp_ - realmem) < STACKMARGIN)
return SP_ERROR_HEAPLOW;
addr = (cell_t *)(m_pRuntime->plugin()->memory + m_ctx.hp);
addr = (cell_t *)(m_pRuntime->plugin()->memory + hp_);
/* store size of allocation in cells */
*addr = (cell_t)cells;
addr++;
m_ctx.hp += sizeof(cell_t);
hp_ += sizeof(cell_t);
*local_addr = m_ctx.hp;
*local_addr = hp_;
if (phys_addr)
*phys_addr = addr;
m_ctx.hp += realmem;
hp_ += realmem;
return SP_ERROR_NONE;
}
@ -214,16 +204,16 @@ PluginContext::HeapPop(cell_t local_addr)
/* check the bounds of this address */
local_addr -= sizeof(cell_t);
if (local_addr < (cell_t)m_pRuntime->plugin()->data_size || local_addr >= m_ctx.sp)
if (local_addr < (cell_t)m_pRuntime->plugin()->data_size || local_addr >= sp_)
return SP_ERROR_INVALID_ADDRESS;
addr = (cell_t *)(m_pRuntime->plugin()->memory + local_addr);
cellcount = (*addr) * sizeof(cell_t);
/* check if this memory count looks valid */
if ((signed)(m_ctx.hp - cellcount - sizeof(cell_t)) != local_addr)
if ((signed)(hp_ - cellcount - sizeof(cell_t)) != local_addr)
return SP_ERROR_INVALID_ADDRESS;
m_ctx.hp = local_addr;
hp_ = local_addr;
return SP_ERROR_NONE;
}
@ -235,7 +225,7 @@ PluginContext::HeapRelease(cell_t local_addr)
if (local_addr < (cell_t)m_pRuntime->plugin()->data_size)
return SP_ERROR_INVALID_ADDRESS;
m_ctx.hp = local_addr - sizeof(cell_t);
hp_ = local_addr - sizeof(cell_t);
return SP_ERROR_NONE;
}
@ -327,7 +317,7 @@ PluginContext::BindNativeToAny(SPVM_NATIVE_FUNC native)
int
PluginContext::LocalToPhysAddr(cell_t local_addr, cell_t **phys_addr)
{
if (((local_addr >= m_ctx.hp) && (local_addr < m_ctx.sp)) ||
if (((local_addr >= hp_) && (local_addr < sp_)) ||
(local_addr < 0) || ((ucell_t)local_addr >= m_pRuntime->plugin()->mem_size))
{
return SP_ERROR_INVALID_ADDRESS;
@ -360,7 +350,7 @@ PluginContext::PushCellArray(cell_t *local_addr, cell_t **phys_addr, cell_t arra
int
PluginContext::LocalToString(cell_t local_addr, char **addr)
{
if (((local_addr >= m_ctx.hp) && (local_addr < m_ctx.sp)) ||
if (((local_addr >= hp_) && (local_addr < sp_)) ||
(local_addr < 0) || ((ucell_t)local_addr >= m_pRuntime->plugin()->mem_size))
{
return SP_ERROR_INVALID_ADDRESS;
@ -382,7 +372,7 @@ PluginContext::StringToLocal(cell_t local_addr, size_t bytes, const char *source
char *dest;
size_t len;
if (((local_addr >= m_ctx.hp) && (local_addr < m_ctx.sp)) ||
if (((local_addr >= hp_) && (local_addr < sp_)) ||
(local_addr < 0) || ((ucell_t)local_addr >= m_pRuntime->plugin()->mem_size))
{
return SP_ERROR_INVALID_ADDRESS;
@ -445,7 +435,7 @@ PluginContext::StringToLocalUTF8(cell_t local_addr, size_t maxbytes, const char
size_t len;
bool needtocheck = false;
if (((local_addr >= m_ctx.hp) && (local_addr < m_ctx.sp)) ||
if (((local_addr >= hp_) && (local_addr < sp_)) ||
(local_addr < 0) ||
((ucell_t)local_addr >= m_pRuntime->plugin()->mem_size))
{
@ -550,7 +540,7 @@ PluginContext::Execute2(IPluginFunction *function, const cell_t *params, unsigne
if (m_pRuntime->IsPaused())
return SP_ERROR_NOT_RUNNABLE;
if ((cell_t)(m_ctx.hp + 16*sizeof(cell_t)) > (cell_t)(m_ctx.sp - (sizeof(cell_t) * (num_params + 1))))
if ((cell_t)(hp_ + 16*sizeof(cell_t)) > (cell_t)(sp_ - (sizeof(cell_t) * (num_params + 1))))
return SP_ERROR_STACKLOW;
if (result == NULL)
@ -580,25 +570,25 @@ PluginContext::Execute2(IPluginFunction *function, const cell_t *params, unsigne
uint32_t save_n_idx;
cell_t save_sp, save_hp, save_rp, save_cip;
save_sp = m_ctx.sp;
save_hp = m_ctx.hp;
save_sp = sp_;
save_hp = hp_;
save_exec = m_InExec;
save_n_idx = m_ctx.n_idx;
save_rp = m_ctx.rp;
save_cip = m_ctx.cip;
save_n_idx = last_native_;
save_rp = rp_;
save_cip = cip_;
/* Push parameters */
m_ctx.sp -= sizeof(cell_t) * (num_params + 1);
sp = (cell_t *)(m_pRuntime->plugin()->memory + m_ctx.sp);
sp_ -= sizeof(cell_t) * (num_params + 1);
sp = (cell_t *)(m_pRuntime->plugin()->memory + sp_);
sp[0] = num_params;
for (unsigned int i = 0; i < num_params; i++)
sp[i + 1] = params[i];
/* Clear internal state */
m_ctx.n_err = SP_ERROR_NONE;
m_ctx.n_idx = 0;
native_error_ = SP_ERROR_NONE;
last_native_ = -1;
m_MsgCache[0] = '\0';
m_CustomMsg = false;
m_InExec = true;
@ -615,23 +605,23 @@ PluginContext::Execute2(IPluginFunction *function, const cell_t *params, unsigne
m_InExec = save_exec;
if (ir == SP_ERROR_NONE) {
m_ctx.n_err = SP_ERROR_NONE;
if (m_ctx.sp != save_sp) {
native_error_ = SP_ERROR_NONE;
if (sp_ != save_sp) {
ir = SP_ERROR_STACKLEAK;
_SetErrorMessage("Stack leak detected: sp:%d should be %d!",
m_ctx.sp,
sp_,
save_sp);
}
if (m_ctx.hp != save_hp) {
if (hp_ != save_hp) {
ir = SP_ERROR_HEAPLEAK;
_SetErrorMessage("Heap leak detected: hp:%d should be %d!",
m_ctx.hp,
hp_,
save_hp);
}
if (m_ctx.rp != save_rp) {
if (rp_ != save_rp) {
ir = SP_ERROR_STACKLEAK;
_SetErrorMessage("Return stack leak detected: rp:%d should be %d!",
m_ctx.rp,
rp_,
save_rp);
}
}
@ -642,13 +632,13 @@ PluginContext::Execute2(IPluginFunction *function, const cell_t *params, unsigne
if (ir != SP_ERROR_NONE)
Environment::get()->ReportError(m_pRuntime, ir, m_MsgCache, save_rp);
m_ctx.sp = save_sp;
m_ctx.hp = save_hp;
m_ctx.rp = save_rp;
sp_ = save_sp;
hp_ = save_hp;
rp_ = save_rp;
m_ctx.cip = save_cip;
m_ctx.n_idx = save_n_idx;
m_ctx.n_err = SP_ERROR_NONE;
cip_ = save_cip;
last_native_ = save_n_idx;
native_error_ = SP_ERROR_NONE;
m_MsgCache[0] = '\0';
m_CustomMsg = false;
@ -780,13 +770,13 @@ DebugInfo::LookupLine(ucell_t addr, uint32_t *line)
int
PluginContext::GetLastNativeError()
{
return m_ctx.n_err;
return native_error_;
}
cell_t *
PluginContext::GetLocalParams()
{
return (cell_t *)(m_pRuntime->plugin()->memory + m_ctx.frm + (2 * sizeof(cell_t)));
return (cell_t *)(m_pRuntime->plugin()->memory + frm_ + (2 * sizeof(cell_t)));
}
void
@ -812,5 +802,250 @@ PluginContext::GetKey(int k, void **value)
void
PluginContext::ClearLastNativeError()
{
m_ctx.n_err = SP_ERROR_NONE;
native_error_ = SP_ERROR_NONE;
}
int
PluginContext::popTrackerAndSetHeap()
{
assert(tracker_.pCur > tracker_.pBase);
tracker_.pCur--;
if (tracker_.pCur < tracker_.pBase)
return SP_ERROR_TRACKER_BOUNDS;
ucell_t amt = *tracker_.pCur;
if (amt > (hp_ - m_pRuntime->plugin()->data_size))
return SP_ERROR_HEAPMIN;
hp_ -= amt;
return SP_ERROR_NONE;
}
int
PluginContext::pushTracker(uint32_t amount)
{
if ((size_t)(tracker_.pCur - tracker_.pBase) >= tracker_.size)
return SP_ERROR_TRACKER_BOUNDS;
if (tracker_.pCur + 1 - (tracker_.pBase + tracker_.size) == 0) {
size_t disp = tracker_.size - 1;
tracker_.size *= 2;
tracker_.pBase = (ucell_t *)realloc(tracker_.pBase, tracker_.size * sizeof(cell_t));
if (!tracker_.pBase)
return SP_ERROR_TRACKER_BOUNDS;
tracker_.pCur = tracker_.pBase + disp;
}
*tracker_.pCur++ = amount;
return SP_ERROR_NONE;
}
cell_t
PluginContext::invokeNative(ucell_t native_idx, cell_t *params)
{
cell_t save_sp = sp_;
cell_t save_hp = hp_;
// Note: Invoke() saves the last native, so we don't need to here.
last_native_ = native_idx;
sp_native_t *native = &m_pRuntime->plugin()->natives[native_idx];
if (native->status == SP_NATIVE_UNBOUND) {
native_error_ = SP_ERROR_INVALID_NATIVE;
return 0;
}
cell_t result = native->pfn(this, params);
if (native_error_ != SP_ERROR_NONE)
return result;
if (save_sp != sp_) {
native_error_ = SP_ERROR_STACKLEAK;
return result;
}
if (save_hp != hp_) {
native_error_ = SP_ERROR_HEAPLEAK;
return result;
}
return result;
}
cell_t
PluginContext::invokeBoundNative(SPVM_NATIVE_FUNC pfn, cell_t *params)
{
cell_t save_sp = sp_;
cell_t save_hp = hp_;
cell_t result = pfn(this, params);
if (native_error_ != SP_ERROR_NONE)
return result;
if (save_sp != sp_) {
native_error_ = SP_ERROR_STACKLEAK;
return result;
}
if (save_hp != hp_) {
native_error_ = SP_ERROR_HEAPLEAK;
return result;
}
return result;
}
struct array_creation_t
{
const cell_t *dim_list; /* Dimension sizes */
cell_t dim_count; /* Number of dimensions */
cell_t *data_offs; /* Current offset AFTER the indirection vectors (data) */
cell_t *base; /* array base */
};
static cell_t
GenerateInnerArrayIndirectionVectors(array_creation_t *ar, int dim, cell_t cur_offs)
{
cell_t write_offs = cur_offs;
cell_t *data_offs = ar->data_offs;
cur_offs += ar->dim_list[dim];
// Dimension n-x where x > 2 will have sub-vectors.
// Otherwise, we just need to reference the data section.
if (ar->dim_count > 2 && dim < ar->dim_count - 2) {
// For each index at this dimension, write offstes to our sub-vectors.
// After we write one sub-vector, we generate its sub-vectors recursively.
// At the end, we're given the next offset we can use.
for (int i = 0; i < ar->dim_list[dim]; i++) {
ar->base[write_offs] = (cur_offs - write_offs) * sizeof(cell_t);
write_offs++;
cur_offs = GenerateInnerArrayIndirectionVectors(ar, dim + 1, cur_offs);
}
} else {
// In this section, there are no sub-vectors, we need to write offsets
// to the data. This is separate so the data stays in one big chunk.
// The data offset will increment by the size of the last dimension,
// because that is where the data is finally computed as.
for (int i = 0; i < ar->dim_list[dim]; i++) {
ar->base[write_offs] = (*data_offs - write_offs) * sizeof(cell_t);
write_offs++;
*data_offs = *data_offs + ar->dim_list[dim + 1];
}
}
return cur_offs;
}
static cell_t
calc_indirection(const array_creation_t *ar, cell_t dim)
{
cell_t size = ar->dim_list[dim];
if (dim < ar->dim_count - 2)
size += ar->dim_list[dim] * calc_indirection(ar, dim + 1);
return size;
}
static cell_t
GenerateArrayIndirectionVectors(cell_t *arraybase, cell_t dims[], cell_t _dimcount, bool autozero)
{
array_creation_t ar;
cell_t data_offs;
/* Reverse the dimensions */
cell_t dim_list[sDIMEN_MAX];
int cur_dim = 0;
for (int i = _dimcount - 1; i >= 0; i--)
dim_list[cur_dim++] = dims[i];
ar.base = arraybase;
ar.dim_list = dim_list;
ar.dim_count = _dimcount;
ar.data_offs = &data_offs;
data_offs = calc_indirection(&ar, 0);
GenerateInnerArrayIndirectionVectors(&ar, 0, 0);
return data_offs;
}
int
PluginContext::generateFullArray(uint32_t argc, cell_t *argv, int autozero)
{
// Calculate how many cells are needed.
if (argv[0] <= 0)
return SP_ERROR_ARRAY_TOO_BIG;
uint32_t cells = argv[0];
for (uint32_t dim = 1; dim < argc; dim++) {
cell_t dimsize = argv[dim];
if (dimsize <= 0)
return SP_ERROR_ARRAY_TOO_BIG;
if (!ke::IsUint32MultiplySafe(cells, dimsize))
return SP_ERROR_ARRAY_TOO_BIG;
cells *= uint32_t(dimsize);
if (!ke::IsUint32AddSafe(cells, dimsize))
return SP_ERROR_ARRAY_TOO_BIG;
cells += uint32_t(dimsize);
}
if (!ke::IsUint32MultiplySafe(cells, 4))
return SP_ERROR_ARRAY_TOO_BIG;
uint32_t bytes = cells * 4;
if (!ke::IsUint32AddSafe(hp_, bytes))
return SP_ERROR_ARRAY_TOO_BIG;
uint32_t new_hp = hp_ + bytes;
cell_t *dat_hp = reinterpret_cast<cell_t *>(m_pRuntime->plugin()->memory + new_hp);
// argv, coincidentally, is STK.
if (dat_hp >= argv - STACK_MARGIN)
return SP_ERROR_HEAPLOW;
if (int err = pushTracker(bytes))
return err;
cell_t *base = reinterpret_cast<cell_t *>(m_pRuntime->plugin()->memory + hp_);
cell_t offs = GenerateArrayIndirectionVectors(base, argv, argc, !!autozero);
assert(size_t(offs) == cells);
argv[argc - 1] = hp_;
hp_ = new_hp;
return SP_ERROR_NONE;
}
int
PluginContext::generateArray(cell_t dims, cell_t *stk, bool autozero)
{
if (dims == 1) {
uint32_t size = *stk;
if (size == 0 || !ke::IsUint32MultiplySafe(size, 4))
return SP_ERROR_ARRAY_TOO_BIG;
*stk = hp_;
uint32_t bytes = size * 4;
hp_ += bytes;
if (uintptr_t(m_pRuntime->plugin()->memory + hp_) >= uintptr_t(stk))
return SP_ERROR_HEAPLOW;
if (int err = pushTracker(bytes))
return err;
if (autozero)
memset(m_pRuntime->plugin()->memory + hp_, 0, bytes);
return SP_ERROR_NONE;
}
if (int err = generateFullArray(dims, stk, autozero))
return err;
return SP_ERROR_NONE;
}

View File

@ -18,6 +18,18 @@
#include "plugin-runtime.h"
#include "jit_shared.h"
struct HeapTracker
{
HeapTracker()
: size(0),
pBase(nullptr),
pCur(nullptr)
{}
size_t size;
ucell_t *pBase;
ucell_t *pCur;
};
class PluginContext : public IPluginContext
{
public:
@ -27,7 +39,6 @@ class PluginContext : public IPluginContext
public: //IPluginContext
IVirtualMachine *GetVirtualMachine();
sp_context_t *GetContext();
sp_context_t *GetCtx();
bool IsDebugging();
int SetDebugBreak(void *newpfn, void *oldpfn);
IPluginDebugInfo *GetDebugInfo();
@ -76,6 +87,94 @@ class PluginContext : public IPluginContext
public:
bool IsInExec();
static inline size_t offsetOfRp() {
return offsetof(PluginContext, rp_);
}
static inline size_t offsetOfRstkCips() {
return offsetof(PluginContext, rstk_cips_);
}
static inline size_t offsetOfTracker() {
return offsetof(PluginContext, tracker_);
}
static inline size_t offsetOfLastNative() {
return offsetof(PluginContext, last_native_);
}
static inline size_t offsetOfNativeError() {
return offsetof(PluginContext, native_error_);
}
static inline size_t offsetOfSp() {
return offsetof(PluginContext, sp_);
}
static inline size_t offsetOfRuntime() {
return offsetof(PluginContext, m_pRuntime);
}
int32_t *addressOfCip() {
return &cip_;
}
int32_t *addressOfSp() {
return &sp_;
}
cell_t *addressOfFrm() {
return &frm_;
}
cell_t *addressOfHp() {
return &hp_;
}
int32_t cip() const {
return cip_;
}
cell_t frm() const {
return frm_;
}
cell_t hp() const {
return hp_;
}
// Return stack logic.
bool pushReturnCip(cell_t cip) {
if (rp_ >= SP_MAX_RETURN_STACK)
return false;
rstk_cips_[rp_++] = cip;
return true;
}
void popReturnCip() {
assert(rp_ > 0);
rp_--;
}
cell_t rp() const {
return rp_;
}
cell_t getReturnStackCip(int index) {
assert(index >= 0 && index < SP_MAX_RETURN_STACK);
return rstk_cips_[index];
}
int popTrackerAndSetHeap();
int pushTracker(uint32_t amount);
int generateArray(cell_t dims, cell_t *stk, bool autozero);
int generateFullArray(uint32_t argc, cell_t *argv, int autozero);
cell_t invokeNative(ucell_t native_idx, cell_t *params);
cell_t invokeBoundNative(SPVM_NATIVE_FUNC pfn, cell_t *params);
int lastNative() const {
return last_native_;
}
inline bool checkAddress(cell_t *stk, cell_t addr) {
if (uint32_t(addr) >= m_pRuntime->plugin()->mem_size)
return false;
if (addr < hp_)
return true;
if (reinterpret_cast<cell_t *>(m_pRuntime->plugin()->memory + addr) < stk)
return false;
return true;
}
private:
void SetErrorMessage(const char *msg, va_list ap);
void _SetErrorMessage(const char *msg, ...);
@ -87,9 +186,27 @@ class PluginContext : public IPluginContext
bool m_CustomMsg;
bool m_InExec;
PluginRuntime *m_pRuntime;
sp_context_t m_ctx;
void *m_keys[4];
bool m_keys_set[4];
// Tracker for local HEA growth.
HeapTracker tracker_;
// Return stack.
cell_t rp_;
cell_t rstk_cips_[SP_MAX_RETURN_STACK];
// Track the currently executing native index, and any error it throws.
int32_t last_native_;
int native_error_;
// Most recent CIP.
int32_t cip_;
// Stack, heap, and frame pointer.
cell_t sp_;
cell_t hp_;
cell_t frm_;
};
#endif //_INCLUDE_SOURCEPAWN_BASECONTEXT_H_

View File

@ -96,6 +96,10 @@ class PluginRuntime
return m_JitFunctions[i];
}
static inline size_t offsetToPlugin() {
return offsetof(PluginRuntime, m_plugin);
}
private:
void SetupFloatNativeRemapping();

View File

@ -47,12 +47,19 @@ CodeStubs::CompileInvokeStub()
__ push(ebx); // ebp - 12
__ push(esp); // ebp - 16
// ebx = cx
__ movl(ebx, Operand(ebp, 8 + 4 * 0));
__ movl(eax, Operand(ebp, 8 + 4 * 1));
__ movl(ecx, Operand(ebp, 8 + 4 * 2));
// ecx = code
__ movl(ecx, Operand(ebp, 8 + 4 * 1));
// eax = cx->m_pRuntime->m_plugin.memory
__ movl(eax, Operand(ebx, PluginContext::offsetOfRuntime()));
__ addl(eax, PluginRuntime::offsetToPlugin());
__ movl(eax, Operand(eax, offsetof(sp_plugin_t, memory)));
// Set up run-time registers.
__ movl(edi, Operand(ebx, offsetof(sp_context_t, sp)));
__ movl(edi, Operand(ebx, PluginContext::offsetOfSp()));
__ addl(edi, eax);
__ movl(esi, eax);
__ movl(ebx, edi);
@ -64,8 +71,8 @@ CodeStubs::CompileInvokeStub()
__ call(ecx);
// Get input context, store rval.
__ movl(ecx, Operand(ebp, 8 + 4 * 0));
__ movl(Operand(ecx, offsetof(sp_context_t, rval)), pri);
__ movl(ecx, Operand(ebp, 8 + 4 * 2));
__ movl(Operand(ecx, 0), pri);
// Set no error.
__ movl(eax, SP_ERROR_NONE);
@ -75,7 +82,8 @@ CodeStubs::CompileInvokeStub()
Label ret;
__ bind(&ret);
__ subl(stk, dat);
__ movl(Operand(ecx, offsetof(sp_context_t, sp)), stk);
__ movl(ecx, Operand(ebp, 8 + 4 * 0));
__ movl(Operand(ecx, PluginContext::offsetOfSp()), stk);
// Restore stack.
__ movl(esp, Operand(ebp, -16));

View File

@ -77,128 +77,6 @@ OpToCondition(OPCODE op)
}
}
struct array_creation_t
{
const cell_t *dim_list; /* Dimension sizes */
cell_t dim_count; /* Number of dimensions */
cell_t *data_offs; /* Current offset AFTER the indirection vectors (data) */
cell_t *base; /* array base */
};
static cell_t
GenerateInnerArrayIndirectionVectors(array_creation_t *ar, int dim, cell_t cur_offs)
{
cell_t write_offs = cur_offs;
cell_t *data_offs = ar->data_offs;
cur_offs += ar->dim_list[dim];
// Dimension n-x where x > 2 will have sub-vectors.
// Otherwise, we just need to reference the data section.
if (ar->dim_count > 2 && dim < ar->dim_count - 2) {
// For each index at this dimension, write offstes to our sub-vectors.
// After we write one sub-vector, we generate its sub-vectors recursively.
// At the end, we're given the next offset we can use.
for (int i = 0; i < ar->dim_list[dim]; i++) {
ar->base[write_offs] = (cur_offs - write_offs) * sizeof(cell_t);
write_offs++;
cur_offs = GenerateInnerArrayIndirectionVectors(ar, dim + 1, cur_offs);
}
} else {
// In this section, there are no sub-vectors, we need to write offsets
// to the data. This is separate so the data stays in one big chunk.
// The data offset will increment by the size of the last dimension,
// because that is where the data is finally computed as.
for (int i = 0; i < ar->dim_list[dim]; i++) {
ar->base[write_offs] = (*data_offs - write_offs) * sizeof(cell_t);
write_offs++;
*data_offs = *data_offs + ar->dim_list[dim + 1];
}
}
return cur_offs;
}
static cell_t
calc_indirection(const array_creation_t *ar, cell_t dim)
{
cell_t size = ar->dim_list[dim];
if (dim < ar->dim_count - 2)
size += ar->dim_list[dim] * calc_indirection(ar, dim + 1);
return size;
}
static cell_t
GenerateArrayIndirectionVectors(cell_t *arraybase, cell_t dims[], cell_t _dimcount, bool autozero)
{
array_creation_t ar;
cell_t data_offs;
/* Reverse the dimensions */
cell_t dim_list[sDIMEN_MAX];
int cur_dim = 0;
for (int i = _dimcount - 1; i >= 0; i--)
dim_list[cur_dim++] = dims[i];
ar.base = arraybase;
ar.dim_list = dim_list;
ar.dim_count = _dimcount;
ar.data_offs = &data_offs;
data_offs = calc_indirection(&ar, 0);
GenerateInnerArrayIndirectionVectors(&ar, 0, 0);
return data_offs;
}
int
GenerateFullArray(PluginRuntime *rt, uint32_t argc, cell_t *argv, int autozero)
{
sp_context_t *ctx = rt->GetBaseContext()->GetCtx();
// Calculate how many cells are needed.
if (argv[0] <= 0)
return SP_ERROR_ARRAY_TOO_BIG;
uint32_t cells = argv[0];
for (uint32_t dim = 1; dim < argc; dim++) {
cell_t dimsize = argv[dim];
if (dimsize <= 0)
return SP_ERROR_ARRAY_TOO_BIG;
if (!ke::IsUint32MultiplySafe(cells, dimsize))
return SP_ERROR_ARRAY_TOO_BIG;
cells *= uint32_t(dimsize);
if (!ke::IsUint32AddSafe(cells, dimsize))
return SP_ERROR_ARRAY_TOO_BIG;
cells += uint32_t(dimsize);
}
if (!ke::IsUint32MultiplySafe(cells, 4))
return SP_ERROR_ARRAY_TOO_BIG;
uint32_t bytes = cells * 4;
if (!ke::IsUint32AddSafe(ctx->hp, bytes))
return SP_ERROR_ARRAY_TOO_BIG;
uint32_t new_hp = ctx->hp + bytes;
cell_t *dat_hp = reinterpret_cast<cell_t *>(rt->plugin()->memory + new_hp);
// argv, coincidentally, is STK.
if (dat_hp >= argv - STACK_MARGIN)
return SP_ERROR_HEAPLOW;
if (int err = PushTracker(rt->GetBaseContext()->GetCtx(), bytes))
return err;
cell_t *base = reinterpret_cast<cell_t *>(rt->plugin()->memory + ctx->hp);
cell_t offs = GenerateArrayIndirectionVectors(base, argv, argc, !!autozero);
assert(size_t(offs) == cells);
argv[argc - 1] = ctx->hp;
ctx->hp = new_hp;
return SP_ERROR_NONE;
}
#if !defined NDEBUG
static const char *
GetFunctionName(const sp_plugin_t *plugin, uint32_t offs)
@ -303,6 +181,7 @@ CompileFromThunk(PluginRuntime *runtime, cell_t pcode_offs, void **addrp, char *
Compiler::Compiler(PluginRuntime *rt, cell_t pcode_offs)
: env_(Environment::get()),
rt_(rt),
context_(rt->GetBaseContext()),
plugin_(rt->plugin()),
error_(SP_ERROR_NONE),
pcode_start_(pcode_offs),
@ -384,6 +263,37 @@ Compiler::emit(int *errp)
return new CompiledFunction(code, pcode_start_, edges.take());
}
// Helpers for invoking context members.
static int
InvokePushTracker(PluginContext *cx, uint32_t amount)
{
return cx->pushTracker(amount);
}
static int
InvokePopTrackerAndSetHeap(PluginContext *cx)
{
return cx->popTrackerAndSetHeap();
}
static cell_t
InvokeNativeHelper(PluginContext *cx, ucell_t native_idx, cell_t *params)
{
return cx->invokeNative(native_idx, params);
}
static cell_t
InvokeBoundNativeHelper(PluginContext *cx, SPVM_NATIVE_FUNC fn, cell_t *params)
{
return cx->invokeBoundNative(fn, params);
}
static int
InvokeGenerateFullArray(PluginContext *cx, uint32_t argc, cell_t *argv, int autozero)
{
return cx->generateFullArray(argc, argv, autozero);
}
bool
Compiler::emitOp(OPCODE op)
{
@ -1258,8 +1168,8 @@ Compiler::emitOp(OPCODE op)
__ push(alt);
__ push(amount * 4);
__ push(intptr_t(rt_->GetBaseContext()->GetCtx()));
__ call(ExternalAddress((void *)PushTracker));
__ push(intptr_t(rt_->GetBaseContext()));
__ call(ExternalAddress((void *)InvokePushTracker));
__ addl(esp, 8);
__ testl(eax, eax);
__ j(not_zero, &extern_error_);
@ -1276,8 +1186,8 @@ Compiler::emitOp(OPCODE op)
__ push(alt);
// Get the context pointer and call the sanity checker.
__ push(intptr_t(rt_));
__ call(ExternalAddress((void *)PopTrackerAndSetHeap));
__ push(intptr_t(rt_->GetBaseContext()));
__ call(ExternalAddress((void *)InvokePopTrackerAndSetHeap));
__ addl(esp, 4);
__ testl(eax, eax);
__ j(not_zero, &extern_error_);
@ -1296,8 +1206,6 @@ Compiler::emitOp(OPCODE op)
case OP_HALT:
__ align(16);
__ movl(tmp, intptr_t(rt_->GetBaseContext()->GetCtx()));
__ movl(Operand(tmp, offsetof(sp_context_t, rval)), pri);
__ movl(pri, readCell());
__ jmp(&extern_error_);
break;
@ -1405,8 +1313,8 @@ Compiler::emitGenArray(bool autozero)
__ shll(tmp, 2);
__ push(tmp);
__ push(intptr_t(rt_->GetBaseContext()->GetCtx()));
__ call(ExternalAddress((void *)PushTracker));
__ push(intptr_t(rt_->GetBaseContext()));
__ call(ExternalAddress((void *)InvokePushTracker));
__ addl(esp, 4);
__ pop(tmp);
__ shrl(tmp, 2);
@ -1432,8 +1340,8 @@ Compiler::emitGenArray(bool autozero)
__ push(autozero ? 1 : 0);
__ push(stk);
__ push(val);
__ push(intptr_t(rt_));
__ call(ExternalAddress((void *)GenerateFullArray));
__ push(intptr_t(context_));
__ call(ExternalAddress((void *)InvokeGenerateFullArray));
__ addl(esp, 4 * sizeof(void *));
// restore pri to tmp
@ -1462,8 +1370,8 @@ Compiler::emitCall()
// eax = context
// ecx = rp
__ movl(eax, intptr_t(rt_->GetBaseContext()->GetCtx()));
__ movl(ecx, Operand(eax, offsetof(sp_context_t, rp)));
__ movl(eax, intptr_t(rt_->GetBaseContext()));
__ movl(ecx, Operand(eax, PluginContext::offsetOfRp()));
// Check if the return stack is used up.
__ cmpl(ecx, SP_MAX_RETURN_STACK);
@ -1471,10 +1379,10 @@ Compiler::emitCall()
// Add to the return stack.
uintptr_t cip = uintptr_t(cip_ - 2) - uintptr_t(plugin_->pcode);
__ movl(Operand(eax, ecx, ScaleFour, offsetof(sp_context_t, rstk_cips)), cip);
__ movl(Operand(eax, ecx, ScaleFour, PluginContext::offsetOfRstkCips()), cip);
// Increment the return stack pointer.
__ addl(Operand(eax, offsetof(sp_context_t, rp)), 1);
__ addl(Operand(eax, PluginContext::offsetOfRp()), 1);
// Store the CIP of the function we're about to call.
__ movl(Operand(cipAddr()), offset);
@ -1495,8 +1403,8 @@ Compiler::emitCall()
__ movl(Operand(cipAddr()), cip);
// Mark us as leaving the last frame.
__ movl(tmp, intptr_t(rt_->GetBaseContext()->GetCtx()));
__ subl(Operand(tmp, offsetof(sp_context_t, rp)), 1);
__ movl(tmp, intptr_t(rt_->GetBaseContext()));
__ subl(Operand(tmp, PluginContext::offsetOfRp()), 1);
return true;
}
@ -1581,13 +1489,13 @@ Compiler::emitNativeCall(OPCODE op)
// Push the last parameter for the C++ function.
__ push(stk);
__ movl(eax, intptr_t(rt_->GetBaseContext()));
__ movl(Operand(eax, PluginContext::offsetOfLastNative()), native_index);
// Relocate our absolute stk to be dat-relative, and update the context's
// view.
__ movl(eax, intptr_t(rt_->GetBaseContext()->GetCtx()));
__ subl(stk, dat);
__ movl(Operand(eax, offsetof(sp_context_t, sp)), stk);
__ movl(Operand(eax, offsetof(sp_context_t, n_idx)), native_index);
__ movl(Operand(eax, PluginContext::offsetOfSp()), stk);
sp_native_t *native = rt_->GetNativeByIndex(native_index);
if ((native->status != SP_NATIVE_BOUND) ||
@ -1596,18 +1504,18 @@ Compiler::emitNativeCall(OPCODE op)
// The native is either unbound, or it could become unbound in the
// future. Invoke the slower native callback.
__ push(native_index);
__ push(eax);
__ call(ExternalAddress((void *)NativeCallback));
__ push(intptr_t(rt_->GetBaseContext()));
__ call(ExternalAddress((void *)InvokeNativeHelper));
} else {
// The native is bound so we have a few more guarantees.
__ push(intptr_t(native->pfn));
__ push(eax);
__ call(ExternalAddress((void *)BoundNativeCallback));
__ push(intptr_t(rt_->GetBaseContext()));
__ call(ExternalAddress((void *)InvokeBoundNativeHelper));
}
// Check for errors.
__ movl(ecx, intptr_t(rt_->GetBaseContext()->GetCtx()));
__ movl(ecx, Operand(ecx, offsetof(sp_context_t, n_err)));
__ movl(ecx, intptr_t(rt_->GetBaseContext()));
__ movl(ecx, Operand(ecx, PluginContext::offsetOfNativeError()));
__ testl(ecx, ecx);
__ j(not_zero, &extern_error_);
@ -1798,8 +1706,8 @@ Compiler::emitErrorPaths()
if (extern_error_.used()) {
__ bind(&extern_error_);
__ movl(eax, intptr_t(rt_->GetBaseContext()->GetCtx()));
__ movl(eax, Operand(eax, offsetof(sp_context_t, n_err)));
__ movl(eax, intptr_t(rt_->GetBaseContext()));
__ movl(eax, Operand(eax, PluginContext::offsetOfNativeError()));
__ jmp(ExternalAddress(env_->stubs()->ReturnStub()));
}
}

View File

@ -91,22 +91,20 @@ class Compiler
void emitFloatCmp(ConditionCode cc);
ExternalAddress cipAddr() {
sp_context_t *ctx = rt_->GetBaseContext()->GetCtx();
return ExternalAddress(&ctx->cip);
return ExternalAddress(context_->addressOfCip());
}
ExternalAddress hpAddr() {
sp_context_t *ctx = rt_->GetBaseContext()->GetCtx();
return ExternalAddress(&ctx->hp);
return ExternalAddress(context_->addressOfHp());
}
ExternalAddress frmAddr() {
sp_context_t *ctx = rt_->GetBaseContext()->GetCtx();
return ExternalAddress(&ctx->frm);
return ExternalAddress(context_->addressOfFrm());
}
private:
AssemblerX86 masm;
sp::Environment *env_;
PluginRuntime *rt_;
PluginContext *context_;
const sp_plugin_t *plugin_;
int error_;
uint32_t pcode_start_;