commit
9a37b94f4d
@ -18,7 +18,10 @@ def setup(binary):
|
|||||||
compiler = binary.compiler
|
compiler = binary.compiler
|
||||||
compiler.includes += Includes
|
compiler.includes += Includes
|
||||||
if compiler.vendor == 'gcc' or compiler.vendor == 'clang':
|
if compiler.vendor == 'gcc' or compiler.vendor == 'clang':
|
||||||
compiler.cxxflags += ['-fno-rtti']
|
compiler.cxxflags += [
|
||||||
|
'-fno-rtti',
|
||||||
|
'-Wno-invalid-offsetof',
|
||||||
|
]
|
||||||
elif binary.compiler.vendor == 'msvc':
|
elif binary.compiler.vendor == 'msvc':
|
||||||
compiler.cxxflags += ['/GR-']
|
compiler.cxxflags += ['/GR-']
|
||||||
|
|
||||||
|
@ -16,13 +16,13 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <sp_vm_api.h>
|
#include <sp_vm_api.h>
|
||||||
|
|
||||||
typedef struct sp_context_s sp_context_t;
|
class PluginContext;
|
||||||
|
|
||||||
namespace sp {
|
namespace sp {
|
||||||
|
|
||||||
class Environment;
|
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
|
class CodeStubs
|
||||||
{
|
{
|
||||||
|
@ -20,12 +20,12 @@ using namespace SourcePawn;
|
|||||||
|
|
||||||
CContextTrace::CContextTrace(PluginRuntime *pRuntime, int err, const char *errstr, cell_t start_rp)
|
CContextTrace::CContextTrace(PluginRuntime *pRuntime, int err, const char *errstr, cell_t start_rp)
|
||||||
: m_pRuntime(pRuntime),
|
: m_pRuntime(pRuntime),
|
||||||
|
context_(pRuntime->GetBaseContext()),
|
||||||
m_Error(err),
|
m_Error(err),
|
||||||
m_pMsg(errstr),
|
m_pMsg(errstr),
|
||||||
m_StartRp(start_rp),
|
m_StartRp(start_rp),
|
||||||
m_Level(0)
|
m_Level(0)
|
||||||
{
|
{
|
||||||
m_ctx = pRuntime->m_pCtx->GetCtx();
|
|
||||||
m_pDebug = m_pRuntime->GetDebugInfo();
|
m_pDebug = m_pRuntime->GetDebugInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,21 +65,19 @@ CContextTrace::GetTraceInfo(CallStackInfo *trace)
|
|||||||
cell_t cip;
|
cell_t cip;
|
||||||
|
|
||||||
if (m_Level == 0) {
|
if (m_Level == 0) {
|
||||||
cip = m_ctx->cip;
|
cip = context_->cip();
|
||||||
} else if (m_ctx->rp > 0) {
|
} else if (context_->rp() > 0) {
|
||||||
/* Entries go from ctx.rp - 1 to m_StartRp */
|
/* Entries go from ctx.rp - 1 to m_StartRp */
|
||||||
cell_t offs, start, end;
|
cell_t offs, start, end;
|
||||||
|
|
||||||
offs = m_Level - 1;
|
offs = m_Level - 1;
|
||||||
start = m_ctx->rp - 1;
|
start = context_->rp() - 1;
|
||||||
end = m_StartRp;
|
end = m_StartRp;
|
||||||
|
|
||||||
if (start - offs < end)
|
if (start - offs < end)
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
cip = m_ctx->rstk_cips[start - offs];
|
cip = context_->getReturnStackCip(start - offs);
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -106,15 +104,19 @@ CContextTrace::GetTraceInfo(CallStackInfo *trace)
|
|||||||
const char *
|
const char *
|
||||||
CContextTrace::GetLastNative(uint32_t *index)
|
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;
|
return NULL;
|
||||||
|
|
||||||
sp_native_t *native;
|
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;
|
return NULL;
|
||||||
|
|
||||||
if (index)
|
if (index)
|
||||||
*index = m_ctx->n_idx;
|
*index = lastNative;
|
||||||
|
|
||||||
return native->name;
|
return native->name;
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
#include <sp_vm_api.h>
|
#include <sp_vm_api.h>
|
||||||
|
|
||||||
class PluginRuntime;
|
class PluginRuntime;
|
||||||
|
class PluginContext;
|
||||||
|
|
||||||
namespace sp {
|
namespace sp {
|
||||||
|
|
||||||
@ -37,7 +38,7 @@ class CContextTrace : public IContextTrace
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
PluginRuntime *m_pRuntime;
|
PluginRuntime *m_pRuntime;
|
||||||
sp_context_t *m_ctx;
|
PluginContext *context_;
|
||||||
int m_Error;
|
int m_Error;
|
||||||
const char *m_pMsg;
|
const char *m_pMsg;
|
||||||
cell_t m_StartRp;
|
cell_t m_StartRp;
|
||||||
|
@ -238,17 +238,16 @@ Environment::UnpatchAllJumpsFromTimeout()
|
|||||||
int
|
int
|
||||||
Environment::Invoke(PluginRuntime *runtime, CompiledFunction *fn, cell_t *result)
|
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().
|
// Note that cip, hp, sp are saved and restored by Execute2().
|
||||||
ctx->cip = fn->GetCodeOffset();
|
*cx->addressOfCip() = fn->GetCodeOffset();
|
||||||
|
|
||||||
InvokeStubFn invoke = code_stubs_->InvokeStub();
|
InvokeStubFn invoke = code_stubs_->InvokeStub();
|
||||||
|
|
||||||
EnterInvoke();
|
EnterInvoke();
|
||||||
int err = invoke(ctx, runtime->plugin()->memory, fn->GetEntryAddress());
|
int err = invoke(cx, fn->GetEntryAddress(), result);
|
||||||
LeaveInvoke();
|
LeaveInvoke();
|
||||||
|
|
||||||
*result = ctx->rval;
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
@ -45,187 +45,34 @@ Write(const sp_plugin_t *plugin, cell_t offset, cell_t value)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline cell_t *
|
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) {
|
if (!IsValidOffset(target) || uint32_t(target) >= plugin->pcode_size)
|
||||||
ctx->err = SP_ERROR_INVALID_INSTRUCTION;
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
|
||||||
|
|
||||||
return reinterpret_cast<cell_t *>(plugin->pcode + target);
|
return reinterpret_cast<cell_t *>(plugin->pcode + target);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline cell_t *
|
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)
|
if (!cond)
|
||||||
return cip + 1;
|
return cip + 1;
|
||||||
|
|
||||||
cell_t target = *cip;
|
cell_t target = *cip;
|
||||||
if (!IsValidOffset(target) || uint32_t(target) >= plugin->pcode_size) {
|
if (!IsValidOffset(target) || uint32_t(target) >= plugin->pcode_size) {
|
||||||
ctx->err = SP_ERROR_INVALID_INSTRUCTION;
|
*errp = SP_ERROR_INVALID_INSTRUCTION;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
cell_t *next = reinterpret_cast<cell_t *>(plugin->pcode + target);
|
cell_t *next = reinterpret_cast<cell_t *>(plugin->pcode + target);
|
||||||
if (next < cip && !Environment::get()->watchdog()->HandleInterrupt()) {
|
if (next < cip && !Environment::get()->watchdog()->HandleInterrupt()) {
|
||||||
ctx->err = SP_ERROR_TIMEOUT;
|
*errp = SP_ERROR_TIMEOUT;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return next;
|
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
|
int
|
||||||
Interpret(PluginRuntime *rt, uint32_t aCodeStart, cell_t *rval)
|
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)
|
if (!IsValidOffset(aCodeStart) || aCodeStart > plugin->pcode_size)
|
||||||
return SP_ERROR_INVALID_INSTRUCTION;
|
return SP_ERROR_INVALID_INSTRUCTION;
|
||||||
|
|
||||||
sp_context_t *ctx = rt->GetBaseContext()->GetCtx();
|
PluginContext *cx = rt->GetBaseContext();
|
||||||
ctx->err = SP_ERROR_NONE;
|
|
||||||
|
int err = SP_ERROR_NONE;
|
||||||
|
|
||||||
// Save the original frm. BaseContext won't, and if we error, we won't hit
|
// Save the original frm. BaseContext won't, and if we error, we won't hit
|
||||||
// the stack unwinding code.
|
// 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 pri = 0;
|
||||||
cell_t alt = 0;
|
cell_t alt = 0;
|
||||||
cell_t *cip = code + (aCodeStart / 4);
|
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 (;;) {
|
for (;;) {
|
||||||
if (cip >= codeend) {
|
if (cip >= codeend) {
|
||||||
ctx->err = SP_ERROR_INVALID_INSTRUCTION;
|
err = SP_ERROR_INVALID_INSTRUCTION;
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -281,7 +132,7 @@ Interpret(PluginRuntime *rt, uint32_t aCodeStart, cell_t *rval)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case OP_ZERO_S:
|
case OP_ZERO_S:
|
||||||
Write(plugin, ctx->frm + *cip++, 0);
|
Write(plugin, frm + *cip++, 0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OP_PUSH_PRI:
|
case OP_PUSH_PRI:
|
||||||
@ -321,7 +172,7 @@ Interpret(PluginRuntime *rt, uint32_t aCodeStart, cell_t *rval)
|
|||||||
int i = 1;
|
int i = 1;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
cell_t addr = ctx->frm + *cip++;
|
cell_t addr = frm + *cip++;
|
||||||
*--stk = addr;
|
*--stk = addr;
|
||||||
} while (i++ < n);
|
} while (i++ < n);
|
||||||
break;
|
break;
|
||||||
@ -339,7 +190,7 @@ Interpret(PluginRuntime *rt, uint32_t aCodeStart, cell_t *rval)
|
|||||||
|
|
||||||
int i = 1;
|
int i = 1;
|
||||||
do {
|
do {
|
||||||
cell_t value = Read(plugin, ctx->frm + *cip++);
|
cell_t value = Read(plugin, frm + *cip++);
|
||||||
*--stk = value;
|
*--stk = value;
|
||||||
} while (i++ < n);
|
} while (i++ < n);
|
||||||
break;
|
break;
|
||||||
@ -384,9 +235,9 @@ Interpret(PluginRuntime *rt, uint32_t aCodeStart, cell_t *rval)
|
|||||||
|
|
||||||
case OP_PROC:
|
case OP_PROC:
|
||||||
{
|
{
|
||||||
*--stk = ctx->frm;
|
*--stk = frm;
|
||||||
*--stk = 0;
|
*--stk = 0;
|
||||||
ctx->frm = uintptr_t(stk) - uintptr_t(plugin->memory);
|
frm = uintptr_t(stk) - uintptr_t(plugin->memory);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -505,14 +356,16 @@ Interpret(PluginRuntime *rt, uint32_t aCodeStart, cell_t *rval)
|
|||||||
case OP_INC_S:
|
case OP_INC_S:
|
||||||
{
|
{
|
||||||
cell_t offset = *cip++;
|
cell_t offset = *cip++;
|
||||||
cell_t value = Read(plugin, ctx->frm + offset);
|
cell_t value = Read(plugin, frm + offset);
|
||||||
Write(plugin, ctx->frm + offset, value + 1);
|
Write(plugin, frm + offset, value + 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case OP_INC_I:
|
case OP_INC_I:
|
||||||
if (!CheckAddress(plugin, ctx, stk, pri))
|
if (!cx->checkAddress(stk, pri)) {
|
||||||
|
err = SP_ERROR_MEMACCESS;
|
||||||
goto error;
|
goto error;
|
||||||
|
}
|
||||||
Write(plugin, pri, Read(plugin, pri) + 1);
|
Write(plugin, pri, Read(plugin, pri) + 1);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -533,14 +386,16 @@ Interpret(PluginRuntime *rt, uint32_t aCodeStart, cell_t *rval)
|
|||||||
case OP_DEC_S:
|
case OP_DEC_S:
|
||||||
{
|
{
|
||||||
cell_t offset = *cip++;
|
cell_t offset = *cip++;
|
||||||
cell_t value = Read(plugin, ctx->frm + offset);
|
cell_t value = Read(plugin, frm + offset);
|
||||||
Write(plugin, ctx->frm + offset, value - 1);
|
Write(plugin, frm + offset, value - 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case OP_DEC_I:
|
case OP_DEC_I:
|
||||||
if (!CheckAddress(plugin, ctx, stk, pri))
|
if (!cx->checkAddress(stk, pri)) {
|
||||||
|
err = SP_ERROR_MEMACCESS;
|
||||||
goto error;
|
goto error;
|
||||||
|
}
|
||||||
Write(plugin, pri, Read(plugin, pri) - 1);
|
Write(plugin, pri, Read(plugin, pri) - 1);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -552,27 +407,27 @@ Interpret(PluginRuntime *rt, uint32_t aCodeStart, cell_t *rval)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case OP_LOAD_S_PRI:
|
case OP_LOAD_S_PRI:
|
||||||
pri = Read(plugin, ctx->frm + *cip++);
|
pri = Read(plugin, frm + *cip++);
|
||||||
break;
|
break;
|
||||||
case OP_LOAD_S_ALT:
|
case OP_LOAD_S_ALT:
|
||||||
alt = Read(plugin, ctx->frm + *cip++);
|
alt = Read(plugin, frm + *cip++);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OP_LOAD_S_BOTH:
|
case OP_LOAD_S_BOTH:
|
||||||
pri = Read(plugin, ctx->frm + *cip++);
|
pri = Read(plugin, frm + *cip++);
|
||||||
alt = Read(plugin, ctx->frm + *cip++);
|
alt = Read(plugin, frm + *cip++);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OP_LREF_S_PRI:
|
case OP_LREF_S_PRI:
|
||||||
{
|
{
|
||||||
pri = Read(plugin, ctx->frm + *cip++);
|
pri = Read(plugin, frm + *cip++);
|
||||||
pri = Read(plugin, pri);
|
pri = Read(plugin, pri);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case OP_LREF_S_ALT:
|
case OP_LREF_S_ALT:
|
||||||
{
|
{
|
||||||
alt = Read(plugin, ctx->frm + *cip++);
|
alt = Read(plugin, frm + *cip++);
|
||||||
alt = Read(plugin, alt);
|
alt = Read(plugin, alt);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -585,10 +440,10 @@ Interpret(PluginRuntime *rt, uint32_t aCodeStart, cell_t *rval)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case OP_ADDR_PRI:
|
case OP_ADDR_PRI:
|
||||||
pri = ctx->frm + *cip++;
|
pri = frm + *cip++;
|
||||||
break;
|
break;
|
||||||
case OP_ADDR_ALT:
|
case OP_ADDR_ALT:
|
||||||
alt = ctx->frm + *cip++;
|
alt = frm + *cip++;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OP_STOR_PRI:
|
case OP_STOR_PRI:
|
||||||
@ -599,10 +454,10 @@ Interpret(PluginRuntime *rt, uint32_t aCodeStart, cell_t *rval)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case OP_STOR_S_PRI:
|
case OP_STOR_S_PRI:
|
||||||
Write(plugin, ctx->frm + *cip++, pri);
|
Write(plugin, frm + *cip++, pri);
|
||||||
break;
|
break;
|
||||||
case OP_STOR_S_ALT:
|
case OP_STOR_S_ALT:
|
||||||
Write(plugin, ctx->frm +*cip++, alt);
|
Write(plugin, frm +*cip++, alt);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OP_IDXADDR:
|
case OP_IDXADDR:
|
||||||
@ -612,7 +467,7 @@ Interpret(PluginRuntime *rt, uint32_t aCodeStart, cell_t *rval)
|
|||||||
case OP_SREF_S_PRI:
|
case OP_SREF_S_PRI:
|
||||||
{
|
{
|
||||||
cell_t offset = *cip++;
|
cell_t offset = *cip++;
|
||||||
cell_t addr = Read(plugin, ctx->frm + offset);
|
cell_t addr = Read(plugin, frm + offset);
|
||||||
Write(plugin, addr, pri);
|
Write(plugin, addr, pri);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -620,7 +475,7 @@ Interpret(PluginRuntime *rt, uint32_t aCodeStart, cell_t *rval)
|
|||||||
case OP_SREF_S_ALT:
|
case OP_SREF_S_ALT:
|
||||||
{
|
{
|
||||||
cell_t offset = *cip++;
|
cell_t offset = *cip++;
|
||||||
cell_t addr = Read(plugin, ctx->frm + offset);
|
cell_t addr = Read(plugin, frm + offset);
|
||||||
Write(plugin, addr, alt);
|
Write(plugin, addr, alt);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -644,8 +499,10 @@ Interpret(PluginRuntime *rt, uint32_t aCodeStart, cell_t *rval)
|
|||||||
|
|
||||||
case OP_LIDX:
|
case OP_LIDX:
|
||||||
pri = alt + pri * 4;
|
pri = alt + pri * 4;
|
||||||
if (!CheckAddress(plugin, ctx, stk, pri))
|
if (!cx->checkAddress(stk, pri)) {
|
||||||
|
err = SP_ERROR_MEMACCESS;
|
||||||
goto error;
|
goto error;
|
||||||
|
}
|
||||||
pri = Read(plugin, pri);
|
pri = Read(plugin, pri);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -653,8 +510,10 @@ Interpret(PluginRuntime *rt, uint32_t aCodeStart, cell_t *rval)
|
|||||||
{
|
{
|
||||||
cell_t val = *cip++;
|
cell_t val = *cip++;
|
||||||
pri = alt + (pri << val);
|
pri = alt + (pri << val);
|
||||||
if (!CheckAddress(plugin, ctx, stk, pri))
|
if (!cx->checkAddress(stk, pri)) {
|
||||||
|
err = SP_ERROR_MEMACCESS;
|
||||||
goto error;
|
goto error;
|
||||||
|
}
|
||||||
pri = Read(plugin, pri);
|
pri = Read(plugin, pri);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -671,19 +530,23 @@ Interpret(PluginRuntime *rt, uint32_t aCodeStart, cell_t *rval)
|
|||||||
{
|
{
|
||||||
cell_t offset = *cip++;
|
cell_t offset = *cip++;
|
||||||
cell_t value = *cip++;
|
cell_t value = *cip++;
|
||||||
Write(plugin, ctx->frm + offset, value);
|
Write(plugin, frm + offset, value);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case OP_LOAD_I:
|
case OP_LOAD_I:
|
||||||
if (!CheckAddress(plugin, ctx, stk, pri))
|
if (!cx->checkAddress(stk, pri)) {
|
||||||
|
err = SP_ERROR_MEMACCESS;
|
||||||
goto error;
|
goto error;
|
||||||
|
}
|
||||||
pri = Read(plugin, pri);
|
pri = Read(plugin, pri);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OP_STOR_I:
|
case OP_STOR_I:
|
||||||
if (!CheckAddress(plugin, ctx, stk, alt))
|
if (!cx->checkAddress(stk, alt)) {
|
||||||
|
err = SP_ERROR_MEMACCESS;
|
||||||
goto error;
|
goto error;
|
||||||
|
}
|
||||||
Write(plugin, alt, pri);
|
Write(plugin, alt, pri);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -693,11 +556,11 @@ Interpret(PluginRuntime *rt, uint32_t aCodeStart, cell_t *rval)
|
|||||||
cell_t dividend = (op == OP_SDIV) ? pri : alt;
|
cell_t dividend = (op == OP_SDIV) ? pri : alt;
|
||||||
cell_t divisor = (op == OP_SDIV) ? alt : pri;
|
cell_t divisor = (op == OP_SDIV) ? alt : pri;
|
||||||
if (divisor == 0) {
|
if (divisor == 0) {
|
||||||
ctx->err = SP_ERROR_DIVIDE_BY_ZERO;
|
err = SP_ERROR_DIVIDE_BY_ZERO;
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
if (dividend == INT_MIN && divisor == -1) {
|
if (dividend == INT_MIN && divisor == -1) {
|
||||||
ctx->err = SP_ERROR_INTEGER_OVERFLOW;
|
err = SP_ERROR_INTEGER_OVERFLOW;
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
pri = dividend / divisor;
|
pri = dividend / divisor;
|
||||||
@ -708,8 +571,10 @@ Interpret(PluginRuntime *rt, uint32_t aCodeStart, cell_t *rval)
|
|||||||
case OP_LODB_I:
|
case OP_LODB_I:
|
||||||
{
|
{
|
||||||
cell_t val = *cip++;
|
cell_t val = *cip++;
|
||||||
if (!CheckAddress(plugin, ctx, stk, pri))
|
if (!cx->checkAddress(stk, pri)) {
|
||||||
|
err = SP_ERROR_MEMACCESS;
|
||||||
goto error;
|
goto error;
|
||||||
|
}
|
||||||
pri = Read(plugin, pri);
|
pri = Read(plugin, pri);
|
||||||
if (val == 1)
|
if (val == 1)
|
||||||
pri &= 0xff;
|
pri &= 0xff;
|
||||||
@ -721,8 +586,10 @@ Interpret(PluginRuntime *rt, uint32_t aCodeStart, cell_t *rval)
|
|||||||
case OP_STRB_I:
|
case OP_STRB_I:
|
||||||
{
|
{
|
||||||
cell_t val = *cip++;
|
cell_t val = *cip++;
|
||||||
if (!CheckAddress(plugin, ctx, stk, alt))
|
if (!cx->checkAddress(stk, alt)) {
|
||||||
|
err = SP_ERROR_MEMACCESS;
|
||||||
goto error;
|
goto error;
|
||||||
|
}
|
||||||
if (val == 1)
|
if (val == 1)
|
||||||
*reinterpret_cast<int8_t *>(plugin->memory + alt) = pri;
|
*reinterpret_cast<int8_t *>(plugin->memory + alt) = pri;
|
||||||
else if (val == 2)
|
else if (val == 2)
|
||||||
@ -735,10 +602,10 @@ Interpret(PluginRuntime *rt, uint32_t aCodeStart, cell_t *rval)
|
|||||||
case OP_RETN:
|
case OP_RETN:
|
||||||
{
|
{
|
||||||
stk++;
|
stk++;
|
||||||
ctx->frm = *stk++;
|
frm = *stk++;
|
||||||
stk += *stk + 1;
|
stk += *stk + 1;
|
||||||
*rval = pri;
|
*rval = pri;
|
||||||
ctx->err = SP_ERROR_NONE;
|
err = SP_ERROR_NONE;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -766,19 +633,19 @@ Interpret(PluginRuntime *rt, uint32_t aCodeStart, cell_t *rval)
|
|||||||
{
|
{
|
||||||
cell_t amount = *cip++;
|
cell_t amount = *cip++;
|
||||||
if (!IsValidOffset(amount)) {
|
if (!IsValidOffset(amount)) {
|
||||||
ctx->err = SP_ERROR_INVALID_INSTRUCTION;
|
err = SP_ERROR_INVALID_INSTRUCTION;
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
stk += amount / 4;
|
stk += amount / 4;
|
||||||
if (amount > 0) {
|
if (amount > 0) {
|
||||||
if (uintptr_t(stk) >= uintptr_t(plugin->memory + plugin->mem_size)) {
|
if (uintptr_t(stk) >= uintptr_t(plugin->memory + plugin->mem_size)) {
|
||||||
ctx->err = SP_ERROR_STACKMIN;
|
err = SP_ERROR_STACKMIN;
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (uintptr_t(stk) < uintptr_t(plugin->memory + ctx->hp + STACK_MARGIN)) {
|
if (uintptr_t(stk) < uintptr_t(plugin->memory + cx->hp() + STACK_MARGIN)) {
|
||||||
ctx->err = SP_ERROR_STACKLOW;
|
err = SP_ERROR_STACKLOW;
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -789,17 +656,17 @@ Interpret(PluginRuntime *rt, uint32_t aCodeStart, cell_t *rval)
|
|||||||
{
|
{
|
||||||
cell_t amount = *cip++;
|
cell_t amount = *cip++;
|
||||||
|
|
||||||
alt = ctx->hp;
|
alt = cx->hp();
|
||||||
ctx->hp += amount;
|
*cx->addressOfHp() += amount;
|
||||||
|
|
||||||
if (amount > 0) {
|
if (amount > 0) {
|
||||||
if (uintptr_t(plugin->memory + ctx->hp) > uintptr_t(stk)) {
|
if (uintptr_t(plugin->memory + cx->hp()) > uintptr_t(stk)) {
|
||||||
ctx->err = SP_ERROR_HEAPLOW;
|
err = SP_ERROR_HEAPLOW;
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (uint32_t(ctx->hp) < plugin->data_size) {
|
if (uint32_t(cx->hp()) < plugin->data_size) {
|
||||||
ctx->err = SP_ERROR_HEAPMIN;
|
err = SP_ERROR_HEAPMIN;
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -807,50 +674,50 @@ Interpret(PluginRuntime *rt, uint32_t aCodeStart, cell_t *rval)
|
|||||||
}
|
}
|
||||||
|
|
||||||
case OP_JUMP:
|
case OP_JUMP:
|
||||||
if ((cip = JumpTarget(plugin, ctx, cip, true)) == NULL)
|
if ((cip = JumpTarget(plugin, cip, true, &err)) == NULL)
|
||||||
goto error;
|
goto error;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OP_JZER:
|
case OP_JZER:
|
||||||
if ((cip = JumpTarget(plugin, ctx, cip, pri == 0)) == NULL)
|
if ((cip = JumpTarget(plugin, cip, pri == 0, &err)) == NULL)
|
||||||
goto error;
|
goto error;
|
||||||
break;
|
break;
|
||||||
case OP_JNZ:
|
case OP_JNZ:
|
||||||
if ((cip = JumpTarget(plugin, ctx, cip, pri != 0)) == NULL)
|
if ((cip = JumpTarget(plugin, cip, pri != 0, &err)) == NULL)
|
||||||
goto error;
|
goto error;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OP_JEQ:
|
case OP_JEQ:
|
||||||
if ((cip = JumpTarget(plugin, ctx, cip, pri == alt)) == NULL)
|
if ((cip = JumpTarget(plugin, cip, pri == alt, &err)) == NULL)
|
||||||
goto error;
|
goto error;
|
||||||
break;
|
break;
|
||||||
case OP_JNEQ:
|
case OP_JNEQ:
|
||||||
if ((cip = JumpTarget(plugin, ctx, cip, pri != alt)) == NULL)
|
if ((cip = JumpTarget(plugin, cip, pri != alt, &err)) == NULL)
|
||||||
goto error;
|
goto error;
|
||||||
break;
|
break;
|
||||||
case OP_JSLESS:
|
case OP_JSLESS:
|
||||||
if ((cip = JumpTarget(plugin, ctx, cip, pri < alt)) == NULL)
|
if ((cip = JumpTarget(plugin, cip, pri < alt, &err)) == NULL)
|
||||||
goto error;
|
goto error;
|
||||||
break;
|
break;
|
||||||
case OP_JSLEQ:
|
case OP_JSLEQ:
|
||||||
if ((cip = JumpTarget(plugin, ctx, cip, pri <= alt)) == NULL)
|
if ((cip = JumpTarget(plugin, cip, pri <= alt, &err)) == NULL)
|
||||||
goto error;
|
goto error;
|
||||||
break;
|
break;
|
||||||
case OP_JSGRTR:
|
case OP_JSGRTR:
|
||||||
if ((cip = JumpTarget(plugin, ctx, cip, pri > alt)) == NULL)
|
if ((cip = JumpTarget(plugin, cip, pri > alt, &err)) == NULL)
|
||||||
goto error;
|
goto error;
|
||||||
break;
|
break;
|
||||||
case OP_JSGEQ:
|
case OP_JSGEQ:
|
||||||
if ((cip = JumpTarget(plugin, ctx, cip, pri >= alt)) == NULL)
|
if ((cip = JumpTarget(plugin, cip, pri >= alt, &err)) == NULL)
|
||||||
goto error;
|
goto error;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OP_TRACKER_PUSH_C:
|
case OP_TRACKER_PUSH_C:
|
||||||
{
|
{
|
||||||
cell_t amount = *cip++;
|
cell_t amount = *cip++;
|
||||||
int error = PushTracker(ctx, amount * 4);
|
int error = cx->pushTracker(amount * 4);
|
||||||
if (error != SP_ERROR_NONE) {
|
if (error != SP_ERROR_NONE) {
|
||||||
ctx->err = error;
|
err = error;
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -858,23 +725,23 @@ Interpret(PluginRuntime *rt, uint32_t aCodeStart, cell_t *rval)
|
|||||||
|
|
||||||
case OP_TRACKER_POP_SETHEAP:
|
case OP_TRACKER_POP_SETHEAP:
|
||||||
{
|
{
|
||||||
int error = PopTrackerAndSetHeap(rt);
|
int error = cx->popTrackerAndSetHeap();
|
||||||
if (error != SP_ERROR_NONE) {
|
if (error != SP_ERROR_NONE) {
|
||||||
ctx->err = error;
|
err = error;
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case OP_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;
|
break;
|
||||||
|
|
||||||
case OP_BOUNDS:
|
case OP_BOUNDS:
|
||||||
{
|
{
|
||||||
cell_t value = *cip++;
|
cell_t value = *cip++;
|
||||||
if (uint32_t(pri) > uint32_t(value)) {
|
if (uint32_t(pri) > uint32_t(value)) {
|
||||||
ctx->err = SP_ERROR_ARRAY_BOUNDS;
|
err = SP_ERROR_ARRAY_BOUNDS;
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -885,26 +752,24 @@ Interpret(PluginRuntime *rt, uint32_t aCodeStart, cell_t *rval)
|
|||||||
cell_t offset = *cip++;
|
cell_t offset = *cip++;
|
||||||
|
|
||||||
if (!IsValidOffset(offset) || uint32_t(offset) >= plugin->pcode_size) {
|
if (!IsValidOffset(offset) || uint32_t(offset) >= plugin->pcode_size) {
|
||||||
ctx->err = SP_ERROR_INSTRUCTION_PARAM;
|
err = SP_ERROR_INSTRUCTION_PARAM;
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ctx->rp >= SP_MAX_RETURN_STACK) {
|
|
||||||
ctx->err = SP_ERROR_STACKLOW;
|
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
// For debugging.
|
// For debugging.
|
||||||
uintptr_t rcip = uintptr_t(cip - 2) - uintptr_t(plugin->pcode);
|
uintptr_t rcip = uintptr_t(cip - 2) - uintptr_t(plugin->pcode);
|
||||||
ctx->rstk_cips[ctx->rp++] = rcip;
|
if (!cx->pushReturnCip(rcip)) {
|
||||||
ctx->cip = offset;
|
err = SP_ERROR_STACKLOW;
|
||||||
ctx->sp = uintptr_t(stk) - uintptr_t(plugin->memory);
|
goto error;
|
||||||
|
}
|
||||||
|
*cx->addressOfCip() = offset;
|
||||||
|
sp = uintptr_t(stk) - uintptr_t(plugin->memory);
|
||||||
|
|
||||||
int err = Interpret(rt, offset, &pri);
|
int err = Interpret(rt, offset, &pri);
|
||||||
|
|
||||||
stk = reinterpret_cast<cell_t *>(plugin->memory + ctx->sp);
|
stk = reinterpret_cast<cell_t *>(plugin->memory + sp);
|
||||||
ctx->cip = rcip;
|
*cx->addressOfCip() = rcip;
|
||||||
ctx->rp--;
|
cx->popReturnCip();
|
||||||
|
|
||||||
if (err != SP_ERROR_NONE)
|
if (err != SP_ERROR_NONE)
|
||||||
goto error;
|
goto error;
|
||||||
@ -915,7 +780,7 @@ Interpret(PluginRuntime *rt, uint32_t aCodeStart, cell_t *rval)
|
|||||||
case OP_GENARRAY_Z:
|
case OP_GENARRAY_Z:
|
||||||
{
|
{
|
||||||
cell_t val = *cip++;
|
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;
|
goto error;
|
||||||
|
|
||||||
stk += (val - 1) * 4;
|
stk += (val - 1) * 4;
|
||||||
@ -928,7 +793,7 @@ Interpret(PluginRuntime *rt, uint32_t aCodeStart, cell_t *rval)
|
|||||||
uint32_t native_index = *cip++;
|
uint32_t native_index = *cip++;
|
||||||
|
|
||||||
if (native_index >= plugin->num_natives) {
|
if (native_index >= plugin->num_natives) {
|
||||||
ctx->err = SP_ERROR_INSTRUCTION_PARAM;
|
err = SP_ERROR_INSTRUCTION_PARAM;
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -938,10 +803,10 @@ Interpret(PluginRuntime *rt, uint32_t aCodeStart, cell_t *rval)
|
|||||||
*--stk = num_params;
|
*--stk = num_params;
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx->sp = uintptr_t(stk) - uintptr_t(plugin->memory);
|
sp = uintptr_t(stk) - uintptr_t(plugin->memory);
|
||||||
pri = NativeCallback(ctx, native_index, stk);
|
pri = cx->invokeNative(native_index, stk);
|
||||||
if (ctx->n_err != SP_ERROR_NONE) {
|
if (cx->GetLastNativeError() != SP_ERROR_NONE) {
|
||||||
ctx->err = ctx->n_err;
|
err = cx->GetLastNativeError();
|
||||||
goto error;
|
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;
|
goto error;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
ctx->err = SP_ERROR_INVALID_INSTRUCTION;
|
err = SP_ERROR_INVALID_INSTRUCTION;
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
} // switch
|
} // switch
|
||||||
}
|
}
|
||||||
|
|
||||||
done:
|
done:
|
||||||
assert(orig_frm == ctx->frm);
|
assert(orig_frm == frm);
|
||||||
ctx->sp = uintptr_t(stk) - uintptr_t(plugin->memory);
|
sp = uintptr_t(stk) - uintptr_t(plugin->memory);
|
||||||
return ctx->err;
|
return err;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
ctx->frm = orig_frm;
|
frm = orig_frm;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,19 +22,6 @@
|
|||||||
#include "plugin-runtime.h"
|
#include "plugin-runtime.h"
|
||||||
#include "plugin-context.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 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_
|
#endif // _include_sourcepawn_interpreter_h_
|
||||||
|
@ -68,27 +68,8 @@ namespace SourcePawn
|
|||||||
} sp_plugin_t;
|
} sp_plugin_t;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct tracker_t;
|
|
||||||
class PluginContext;
|
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_DEBUG (1<<0)
|
||||||
#define SPFLAG_PLUGIN_PAUSED (1<<1)
|
#define SPFLAG_PLUGIN_PAUSED (1<<1)
|
||||||
|
|
||||||
|
@ -51,25 +51,21 @@ PluginContext::PluginContext(PluginRuntime *pRuntime)
|
|||||||
m_pNullString = NULL;
|
m_pNullString = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_ctx.hp = m_pRuntime->plugin()->data_size;
|
hp_ = m_pRuntime->plugin()->data_size;
|
||||||
m_ctx.sp = m_pRuntime->plugin()->mem_size - sizeof(cell_t);
|
sp_ = m_pRuntime->plugin()->mem_size - sizeof(cell_t);
|
||||||
m_ctx.frm = m_ctx.sp;
|
frm_ = sp_;
|
||||||
m_ctx.n_err = SP_ERROR_NONE;
|
rp_ = 0;
|
||||||
m_ctx.n_idx = SP_ERROR_NONE;
|
last_native_ = -1;
|
||||||
m_ctx.rp = 0;
|
native_error_ = SP_ERROR_NONE;
|
||||||
|
|
||||||
m_ctx.tracker = new tracker_t;
|
tracker_.pBase = (ucell_t *)malloc(1024);
|
||||||
m_ctx.tracker->pBase = (ucell_t *)malloc(1024);
|
tracker_.pCur = tracker_.pBase;
|
||||||
m_ctx.tracker->pCur = m_ctx.tracker->pBase;
|
tracker_.size = 1024 / sizeof(cell_t);
|
||||||
m_ctx.tracker->size = 1024 / sizeof(cell_t);
|
|
||||||
m_ctx.basecx = this;
|
|
||||||
m_ctx.plugin = const_cast<sp_plugin_t *>(pRuntime->plugin());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PluginContext::~PluginContext()
|
PluginContext::~PluginContext()
|
||||||
{
|
{
|
||||||
free(m_ctx.tracker->pBase);
|
free(tracker_.pBase);
|
||||||
delete m_ctx.tracker;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
IVirtualMachine *
|
IVirtualMachine *
|
||||||
@ -84,12 +80,6 @@ PluginContext::GetContext()
|
|||||||
return reinterpret_cast<sp_context_t *>((IPluginContext * )this);
|
return reinterpret_cast<sp_context_t *>((IPluginContext * )this);
|
||||||
}
|
}
|
||||||
|
|
||||||
sp_context_t *
|
|
||||||
PluginContext::GetCtx()
|
|
||||||
{
|
|
||||||
return &m_ctx;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
PluginContext::IsDebugging()
|
PluginContext::IsDebugging()
|
||||||
{
|
{
|
||||||
@ -137,7 +127,7 @@ PluginContext::ThrowNativeErrorEx(int error, const char *msg, ...)
|
|||||||
if (!m_InExec)
|
if (!m_InExec)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
m_ctx.n_err = error;
|
native_error_ = error;
|
||||||
|
|
||||||
if (msg) {
|
if (msg) {
|
||||||
va_list ap;
|
va_list ap;
|
||||||
@ -155,7 +145,7 @@ PluginContext::ThrowNativeError(const char *msg, ...)
|
|||||||
if (!m_InExec)
|
if (!m_InExec)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
m_ctx.n_err = SP_ERROR_NATIVE;
|
native_error_ = SP_ERROR_NATIVE;
|
||||||
|
|
||||||
if (msg) {
|
if (msg) {
|
||||||
va_list ap;
|
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.
|
* 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;
|
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 */
|
/* store size of allocation in cells */
|
||||||
*addr = (cell_t)cells;
|
*addr = (cell_t)cells;
|
||||||
addr++;
|
addr++;
|
||||||
m_ctx.hp += sizeof(cell_t);
|
hp_ += sizeof(cell_t);
|
||||||
|
|
||||||
*local_addr = m_ctx.hp;
|
*local_addr = hp_;
|
||||||
|
|
||||||
if (phys_addr)
|
if (phys_addr)
|
||||||
*phys_addr = addr;
|
*phys_addr = addr;
|
||||||
|
|
||||||
m_ctx.hp += realmem;
|
hp_ += realmem;
|
||||||
|
|
||||||
return SP_ERROR_NONE;
|
return SP_ERROR_NONE;
|
||||||
}
|
}
|
||||||
@ -214,16 +204,16 @@ PluginContext::HeapPop(cell_t local_addr)
|
|||||||
|
|
||||||
/* check the bounds of this address */
|
/* check the bounds of this address */
|
||||||
local_addr -= sizeof(cell_t);
|
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;
|
return SP_ERROR_INVALID_ADDRESS;
|
||||||
|
|
||||||
addr = (cell_t *)(m_pRuntime->plugin()->memory + local_addr);
|
addr = (cell_t *)(m_pRuntime->plugin()->memory + local_addr);
|
||||||
cellcount = (*addr) * sizeof(cell_t);
|
cellcount = (*addr) * sizeof(cell_t);
|
||||||
/* check if this memory count looks valid */
|
/* 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;
|
return SP_ERROR_INVALID_ADDRESS;
|
||||||
|
|
||||||
m_ctx.hp = local_addr;
|
hp_ = local_addr;
|
||||||
|
|
||||||
return SP_ERROR_NONE;
|
return SP_ERROR_NONE;
|
||||||
}
|
}
|
||||||
@ -235,7 +225,7 @@ PluginContext::HeapRelease(cell_t local_addr)
|
|||||||
if (local_addr < (cell_t)m_pRuntime->plugin()->data_size)
|
if (local_addr < (cell_t)m_pRuntime->plugin()->data_size)
|
||||||
return SP_ERROR_INVALID_ADDRESS;
|
return SP_ERROR_INVALID_ADDRESS;
|
||||||
|
|
||||||
m_ctx.hp = local_addr - sizeof(cell_t);
|
hp_ = local_addr - sizeof(cell_t);
|
||||||
|
|
||||||
return SP_ERROR_NONE;
|
return SP_ERROR_NONE;
|
||||||
}
|
}
|
||||||
@ -327,7 +317,7 @@ PluginContext::BindNativeToAny(SPVM_NATIVE_FUNC native)
|
|||||||
int
|
int
|
||||||
PluginContext::LocalToPhysAddr(cell_t local_addr, cell_t **phys_addr)
|
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))
|
(local_addr < 0) || ((ucell_t)local_addr >= m_pRuntime->plugin()->mem_size))
|
||||||
{
|
{
|
||||||
return SP_ERROR_INVALID_ADDRESS;
|
return SP_ERROR_INVALID_ADDRESS;
|
||||||
@ -360,7 +350,7 @@ PluginContext::PushCellArray(cell_t *local_addr, cell_t **phys_addr, cell_t arra
|
|||||||
int
|
int
|
||||||
PluginContext::LocalToString(cell_t local_addr, char **addr)
|
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))
|
(local_addr < 0) || ((ucell_t)local_addr >= m_pRuntime->plugin()->mem_size))
|
||||||
{
|
{
|
||||||
return SP_ERROR_INVALID_ADDRESS;
|
return SP_ERROR_INVALID_ADDRESS;
|
||||||
@ -382,7 +372,7 @@ PluginContext::StringToLocal(cell_t local_addr, size_t bytes, const char *source
|
|||||||
char *dest;
|
char *dest;
|
||||||
size_t len;
|
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))
|
(local_addr < 0) || ((ucell_t)local_addr >= m_pRuntime->plugin()->mem_size))
|
||||||
{
|
{
|
||||||
return SP_ERROR_INVALID_ADDRESS;
|
return SP_ERROR_INVALID_ADDRESS;
|
||||||
@ -445,7 +435,7 @@ PluginContext::StringToLocalUTF8(cell_t local_addr, size_t maxbytes, const char
|
|||||||
size_t len;
|
size_t len;
|
||||||
bool needtocheck = false;
|
bool needtocheck = false;
|
||||||
|
|
||||||
if (((local_addr >= m_ctx.hp) && (local_addr < m_ctx.sp)) ||
|
if (((local_addr >= hp_) && (local_addr < sp_)) ||
|
||||||
(local_addr < 0) ||
|
(local_addr < 0) ||
|
||||||
((ucell_t)local_addr >= m_pRuntime->plugin()->mem_size))
|
((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())
|
if (m_pRuntime->IsPaused())
|
||||||
return SP_ERROR_NOT_RUNNABLE;
|
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;
|
return SP_ERROR_STACKLOW;
|
||||||
|
|
||||||
if (result == NULL)
|
if (result == NULL)
|
||||||
@ -580,25 +570,25 @@ PluginContext::Execute2(IPluginFunction *function, const cell_t *params, unsigne
|
|||||||
uint32_t save_n_idx;
|
uint32_t save_n_idx;
|
||||||
cell_t save_sp, save_hp, save_rp, save_cip;
|
cell_t save_sp, save_hp, save_rp, save_cip;
|
||||||
|
|
||||||
save_sp = m_ctx.sp;
|
save_sp = sp_;
|
||||||
save_hp = m_ctx.hp;
|
save_hp = hp_;
|
||||||
save_exec = m_InExec;
|
save_exec = m_InExec;
|
||||||
save_n_idx = m_ctx.n_idx;
|
save_n_idx = last_native_;
|
||||||
save_rp = m_ctx.rp;
|
save_rp = rp_;
|
||||||
save_cip = m_ctx.cip;
|
save_cip = cip_;
|
||||||
|
|
||||||
/* Push parameters */
|
/* Push parameters */
|
||||||
|
|
||||||
m_ctx.sp -= sizeof(cell_t) * (num_params + 1);
|
sp_ -= sizeof(cell_t) * (num_params + 1);
|
||||||
sp = (cell_t *)(m_pRuntime->plugin()->memory + m_ctx.sp);
|
sp = (cell_t *)(m_pRuntime->plugin()->memory + sp_);
|
||||||
|
|
||||||
sp[0] = num_params;
|
sp[0] = num_params;
|
||||||
for (unsigned int i = 0; i < num_params; i++)
|
for (unsigned int i = 0; i < num_params; i++)
|
||||||
sp[i + 1] = params[i];
|
sp[i + 1] = params[i];
|
||||||
|
|
||||||
/* Clear internal state */
|
/* Clear internal state */
|
||||||
m_ctx.n_err = SP_ERROR_NONE;
|
native_error_ = SP_ERROR_NONE;
|
||||||
m_ctx.n_idx = 0;
|
last_native_ = -1;
|
||||||
m_MsgCache[0] = '\0';
|
m_MsgCache[0] = '\0';
|
||||||
m_CustomMsg = false;
|
m_CustomMsg = false;
|
||||||
m_InExec = true;
|
m_InExec = true;
|
||||||
@ -615,23 +605,23 @@ PluginContext::Execute2(IPluginFunction *function, const cell_t *params, unsigne
|
|||||||
m_InExec = save_exec;
|
m_InExec = save_exec;
|
||||||
|
|
||||||
if (ir == SP_ERROR_NONE) {
|
if (ir == SP_ERROR_NONE) {
|
||||||
m_ctx.n_err = SP_ERROR_NONE;
|
native_error_ = SP_ERROR_NONE;
|
||||||
if (m_ctx.sp != save_sp) {
|
if (sp_ != save_sp) {
|
||||||
ir = SP_ERROR_STACKLEAK;
|
ir = SP_ERROR_STACKLEAK;
|
||||||
_SetErrorMessage("Stack leak detected: sp:%d should be %d!",
|
_SetErrorMessage("Stack leak detected: sp:%d should be %d!",
|
||||||
m_ctx.sp,
|
sp_,
|
||||||
save_sp);
|
save_sp);
|
||||||
}
|
}
|
||||||
if (m_ctx.hp != save_hp) {
|
if (hp_ != save_hp) {
|
||||||
ir = SP_ERROR_HEAPLEAK;
|
ir = SP_ERROR_HEAPLEAK;
|
||||||
_SetErrorMessage("Heap leak detected: hp:%d should be %d!",
|
_SetErrorMessage("Heap leak detected: hp:%d should be %d!",
|
||||||
m_ctx.hp,
|
hp_,
|
||||||
save_hp);
|
save_hp);
|
||||||
}
|
}
|
||||||
if (m_ctx.rp != save_rp) {
|
if (rp_ != save_rp) {
|
||||||
ir = SP_ERROR_STACKLEAK;
|
ir = SP_ERROR_STACKLEAK;
|
||||||
_SetErrorMessage("Return stack leak detected: rp:%d should be %d!",
|
_SetErrorMessage("Return stack leak detected: rp:%d should be %d!",
|
||||||
m_ctx.rp,
|
rp_,
|
||||||
save_rp);
|
save_rp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -642,13 +632,13 @@ PluginContext::Execute2(IPluginFunction *function, const cell_t *params, unsigne
|
|||||||
if (ir != SP_ERROR_NONE)
|
if (ir != SP_ERROR_NONE)
|
||||||
Environment::get()->ReportError(m_pRuntime, ir, m_MsgCache, save_rp);
|
Environment::get()->ReportError(m_pRuntime, ir, m_MsgCache, save_rp);
|
||||||
|
|
||||||
m_ctx.sp = save_sp;
|
sp_ = save_sp;
|
||||||
m_ctx.hp = save_hp;
|
hp_ = save_hp;
|
||||||
m_ctx.rp = save_rp;
|
rp_ = save_rp;
|
||||||
|
|
||||||
m_ctx.cip = save_cip;
|
cip_ = save_cip;
|
||||||
m_ctx.n_idx = save_n_idx;
|
last_native_ = save_n_idx;
|
||||||
m_ctx.n_err = SP_ERROR_NONE;
|
native_error_ = SP_ERROR_NONE;
|
||||||
m_MsgCache[0] = '\0';
|
m_MsgCache[0] = '\0';
|
||||||
m_CustomMsg = false;
|
m_CustomMsg = false;
|
||||||
|
|
||||||
@ -780,13 +770,13 @@ DebugInfo::LookupLine(ucell_t addr, uint32_t *line)
|
|||||||
int
|
int
|
||||||
PluginContext::GetLastNativeError()
|
PluginContext::GetLastNativeError()
|
||||||
{
|
{
|
||||||
return m_ctx.n_err;
|
return native_error_;
|
||||||
}
|
}
|
||||||
|
|
||||||
cell_t *
|
cell_t *
|
||||||
PluginContext::GetLocalParams()
|
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
|
void
|
||||||
@ -812,5 +802,250 @@ PluginContext::GetKey(int k, void **value)
|
|||||||
void
|
void
|
||||||
PluginContext::ClearLastNativeError()
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -18,6 +18,18 @@
|
|||||||
#include "plugin-runtime.h"
|
#include "plugin-runtime.h"
|
||||||
#include "jit_shared.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
|
class PluginContext : public IPluginContext
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -27,7 +39,6 @@ class PluginContext : public IPluginContext
|
|||||||
public: //IPluginContext
|
public: //IPluginContext
|
||||||
IVirtualMachine *GetVirtualMachine();
|
IVirtualMachine *GetVirtualMachine();
|
||||||
sp_context_t *GetContext();
|
sp_context_t *GetContext();
|
||||||
sp_context_t *GetCtx();
|
|
||||||
bool IsDebugging();
|
bool IsDebugging();
|
||||||
int SetDebugBreak(void *newpfn, void *oldpfn);
|
int SetDebugBreak(void *newpfn, void *oldpfn);
|
||||||
IPluginDebugInfo *GetDebugInfo();
|
IPluginDebugInfo *GetDebugInfo();
|
||||||
@ -76,6 +87,94 @@ class PluginContext : public IPluginContext
|
|||||||
public:
|
public:
|
||||||
bool IsInExec();
|
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:
|
private:
|
||||||
void SetErrorMessage(const char *msg, va_list ap);
|
void SetErrorMessage(const char *msg, va_list ap);
|
||||||
void _SetErrorMessage(const char *msg, ...);
|
void _SetErrorMessage(const char *msg, ...);
|
||||||
@ -87,9 +186,27 @@ class PluginContext : public IPluginContext
|
|||||||
bool m_CustomMsg;
|
bool m_CustomMsg;
|
||||||
bool m_InExec;
|
bool m_InExec;
|
||||||
PluginRuntime *m_pRuntime;
|
PluginRuntime *m_pRuntime;
|
||||||
sp_context_t m_ctx;
|
|
||||||
void *m_keys[4];
|
void *m_keys[4];
|
||||||
bool m_keys_set[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_
|
#endif //_INCLUDE_SOURCEPAWN_BASECONTEXT_H_
|
||||||
|
@ -96,6 +96,10 @@ class PluginRuntime
|
|||||||
return m_JitFunctions[i];
|
return m_JitFunctions[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline size_t offsetToPlugin() {
|
||||||
|
return offsetof(PluginRuntime, m_plugin);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void SetupFloatNativeRemapping();
|
void SetupFloatNativeRemapping();
|
||||||
|
|
||||||
|
@ -47,12 +47,19 @@ CodeStubs::CompileInvokeStub()
|
|||||||
__ push(ebx); // ebp - 12
|
__ push(ebx); // ebp - 12
|
||||||
__ push(esp); // ebp - 16
|
__ push(esp); // ebp - 16
|
||||||
|
|
||||||
|
// ebx = cx
|
||||||
__ movl(ebx, Operand(ebp, 8 + 4 * 0));
|
__ 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.
|
// Set up run-time registers.
|
||||||
__ movl(edi, Operand(ebx, offsetof(sp_context_t, sp)));
|
__ movl(edi, Operand(ebx, PluginContext::offsetOfSp()));
|
||||||
__ addl(edi, eax);
|
__ addl(edi, eax);
|
||||||
__ movl(esi, eax);
|
__ movl(esi, eax);
|
||||||
__ movl(ebx, edi);
|
__ movl(ebx, edi);
|
||||||
@ -64,8 +71,8 @@ CodeStubs::CompileInvokeStub()
|
|||||||
__ call(ecx);
|
__ call(ecx);
|
||||||
|
|
||||||
// Get input context, store rval.
|
// Get input context, store rval.
|
||||||
__ movl(ecx, Operand(ebp, 8 + 4 * 0));
|
__ movl(ecx, Operand(ebp, 8 + 4 * 2));
|
||||||
__ movl(Operand(ecx, offsetof(sp_context_t, rval)), pri);
|
__ movl(Operand(ecx, 0), pri);
|
||||||
|
|
||||||
// Set no error.
|
// Set no error.
|
||||||
__ movl(eax, SP_ERROR_NONE);
|
__ movl(eax, SP_ERROR_NONE);
|
||||||
@ -75,7 +82,8 @@ CodeStubs::CompileInvokeStub()
|
|||||||
Label ret;
|
Label ret;
|
||||||
__ bind(&ret);
|
__ bind(&ret);
|
||||||
__ subl(stk, dat);
|
__ 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.
|
// Restore stack.
|
||||||
__ movl(esp, Operand(ebp, -16));
|
__ movl(esp, Operand(ebp, -16));
|
||||||
|
@ -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
|
#if !defined NDEBUG
|
||||||
static const char *
|
static const char *
|
||||||
GetFunctionName(const sp_plugin_t *plugin, uint32_t offs)
|
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)
|
Compiler::Compiler(PluginRuntime *rt, cell_t pcode_offs)
|
||||||
: env_(Environment::get()),
|
: env_(Environment::get()),
|
||||||
rt_(rt),
|
rt_(rt),
|
||||||
|
context_(rt->GetBaseContext()),
|
||||||
plugin_(rt->plugin()),
|
plugin_(rt->plugin()),
|
||||||
error_(SP_ERROR_NONE),
|
error_(SP_ERROR_NONE),
|
||||||
pcode_start_(pcode_offs),
|
pcode_start_(pcode_offs),
|
||||||
@ -384,6 +263,37 @@ Compiler::emit(int *errp)
|
|||||||
return new CompiledFunction(code, pcode_start_, edges.take());
|
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
|
bool
|
||||||
Compiler::emitOp(OPCODE op)
|
Compiler::emitOp(OPCODE op)
|
||||||
{
|
{
|
||||||
@ -1258,8 +1168,8 @@ Compiler::emitOp(OPCODE op)
|
|||||||
__ push(alt);
|
__ push(alt);
|
||||||
|
|
||||||
__ push(amount * 4);
|
__ push(amount * 4);
|
||||||
__ push(intptr_t(rt_->GetBaseContext()->GetCtx()));
|
__ push(intptr_t(rt_->GetBaseContext()));
|
||||||
__ call(ExternalAddress((void *)PushTracker));
|
__ call(ExternalAddress((void *)InvokePushTracker));
|
||||||
__ addl(esp, 8);
|
__ addl(esp, 8);
|
||||||
__ testl(eax, eax);
|
__ testl(eax, eax);
|
||||||
__ j(not_zero, &extern_error_);
|
__ j(not_zero, &extern_error_);
|
||||||
@ -1276,8 +1186,8 @@ Compiler::emitOp(OPCODE op)
|
|||||||
__ push(alt);
|
__ push(alt);
|
||||||
|
|
||||||
// Get the context pointer and call the sanity checker.
|
// Get the context pointer and call the sanity checker.
|
||||||
__ push(intptr_t(rt_));
|
__ push(intptr_t(rt_->GetBaseContext()));
|
||||||
__ call(ExternalAddress((void *)PopTrackerAndSetHeap));
|
__ call(ExternalAddress((void *)InvokePopTrackerAndSetHeap));
|
||||||
__ addl(esp, 4);
|
__ addl(esp, 4);
|
||||||
__ testl(eax, eax);
|
__ testl(eax, eax);
|
||||||
__ j(not_zero, &extern_error_);
|
__ j(not_zero, &extern_error_);
|
||||||
@ -1296,8 +1206,6 @@ Compiler::emitOp(OPCODE op)
|
|||||||
|
|
||||||
case OP_HALT:
|
case OP_HALT:
|
||||||
__ align(16);
|
__ align(16);
|
||||||
__ movl(tmp, intptr_t(rt_->GetBaseContext()->GetCtx()));
|
|
||||||
__ movl(Operand(tmp, offsetof(sp_context_t, rval)), pri);
|
|
||||||
__ movl(pri, readCell());
|
__ movl(pri, readCell());
|
||||||
__ jmp(&extern_error_);
|
__ jmp(&extern_error_);
|
||||||
break;
|
break;
|
||||||
@ -1405,8 +1313,8 @@ Compiler::emitGenArray(bool autozero)
|
|||||||
|
|
||||||
__ shll(tmp, 2);
|
__ shll(tmp, 2);
|
||||||
__ push(tmp);
|
__ push(tmp);
|
||||||
__ push(intptr_t(rt_->GetBaseContext()->GetCtx()));
|
__ push(intptr_t(rt_->GetBaseContext()));
|
||||||
__ call(ExternalAddress((void *)PushTracker));
|
__ call(ExternalAddress((void *)InvokePushTracker));
|
||||||
__ addl(esp, 4);
|
__ addl(esp, 4);
|
||||||
__ pop(tmp);
|
__ pop(tmp);
|
||||||
__ shrl(tmp, 2);
|
__ shrl(tmp, 2);
|
||||||
@ -1432,8 +1340,8 @@ Compiler::emitGenArray(bool autozero)
|
|||||||
__ push(autozero ? 1 : 0);
|
__ push(autozero ? 1 : 0);
|
||||||
__ push(stk);
|
__ push(stk);
|
||||||
__ push(val);
|
__ push(val);
|
||||||
__ push(intptr_t(rt_));
|
__ push(intptr_t(context_));
|
||||||
__ call(ExternalAddress((void *)GenerateFullArray));
|
__ call(ExternalAddress((void *)InvokeGenerateFullArray));
|
||||||
__ addl(esp, 4 * sizeof(void *));
|
__ addl(esp, 4 * sizeof(void *));
|
||||||
|
|
||||||
// restore pri to tmp
|
// restore pri to tmp
|
||||||
@ -1462,8 +1370,8 @@ Compiler::emitCall()
|
|||||||
|
|
||||||
// eax = context
|
// eax = context
|
||||||
// ecx = rp
|
// ecx = rp
|
||||||
__ movl(eax, intptr_t(rt_->GetBaseContext()->GetCtx()));
|
__ movl(eax, intptr_t(rt_->GetBaseContext()));
|
||||||
__ movl(ecx, Operand(eax, offsetof(sp_context_t, rp)));
|
__ movl(ecx, Operand(eax, PluginContext::offsetOfRp()));
|
||||||
|
|
||||||
// Check if the return stack is used up.
|
// Check if the return stack is used up.
|
||||||
__ cmpl(ecx, SP_MAX_RETURN_STACK);
|
__ cmpl(ecx, SP_MAX_RETURN_STACK);
|
||||||
@ -1471,10 +1379,10 @@ Compiler::emitCall()
|
|||||||
|
|
||||||
// Add to the return stack.
|
// Add to the return stack.
|
||||||
uintptr_t cip = uintptr_t(cip_ - 2) - uintptr_t(plugin_->pcode);
|
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.
|
// 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.
|
// Store the CIP of the function we're about to call.
|
||||||
__ movl(Operand(cipAddr()), offset);
|
__ movl(Operand(cipAddr()), offset);
|
||||||
@ -1495,8 +1403,8 @@ Compiler::emitCall()
|
|||||||
__ movl(Operand(cipAddr()), cip);
|
__ movl(Operand(cipAddr()), cip);
|
||||||
|
|
||||||
// Mark us as leaving the last frame.
|
// Mark us as leaving the last frame.
|
||||||
__ movl(tmp, intptr_t(rt_->GetBaseContext()->GetCtx()));
|
__ movl(tmp, intptr_t(rt_->GetBaseContext()));
|
||||||
__ subl(Operand(tmp, offsetof(sp_context_t, rp)), 1);
|
__ subl(Operand(tmp, PluginContext::offsetOfRp()), 1);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1581,13 +1489,13 @@ Compiler::emitNativeCall(OPCODE op)
|
|||||||
// Push the last parameter for the C++ function.
|
// Push the last parameter for the C++ function.
|
||||||
__ push(stk);
|
__ 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
|
// Relocate our absolute stk to be dat-relative, and update the context's
|
||||||
// view.
|
// view.
|
||||||
__ movl(eax, intptr_t(rt_->GetBaseContext()->GetCtx()));
|
|
||||||
__ subl(stk, dat);
|
__ subl(stk, dat);
|
||||||
__ movl(Operand(eax, offsetof(sp_context_t, sp)), stk);
|
__ movl(Operand(eax, PluginContext::offsetOfSp()), stk);
|
||||||
|
|
||||||
__ movl(Operand(eax, offsetof(sp_context_t, n_idx)), native_index);
|
|
||||||
|
|
||||||
sp_native_t *native = rt_->GetNativeByIndex(native_index);
|
sp_native_t *native = rt_->GetNativeByIndex(native_index);
|
||||||
if ((native->status != SP_NATIVE_BOUND) ||
|
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
|
// The native is either unbound, or it could become unbound in the
|
||||||
// future. Invoke the slower native callback.
|
// future. Invoke the slower native callback.
|
||||||
__ push(native_index);
|
__ push(native_index);
|
||||||
__ push(eax);
|
__ push(intptr_t(rt_->GetBaseContext()));
|
||||||
__ call(ExternalAddress((void *)NativeCallback));
|
__ call(ExternalAddress((void *)InvokeNativeHelper));
|
||||||
} else {
|
} else {
|
||||||
// The native is bound so we have a few more guarantees.
|
// The native is bound so we have a few more guarantees.
|
||||||
__ push(intptr_t(native->pfn));
|
__ push(intptr_t(native->pfn));
|
||||||
__ push(eax);
|
__ push(intptr_t(rt_->GetBaseContext()));
|
||||||
__ call(ExternalAddress((void *)BoundNativeCallback));
|
__ call(ExternalAddress((void *)InvokeBoundNativeHelper));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for errors.
|
// Check for errors.
|
||||||
__ movl(ecx, intptr_t(rt_->GetBaseContext()->GetCtx()));
|
__ movl(ecx, intptr_t(rt_->GetBaseContext()));
|
||||||
__ movl(ecx, Operand(ecx, offsetof(sp_context_t, n_err)));
|
__ movl(ecx, Operand(ecx, PluginContext::offsetOfNativeError()));
|
||||||
__ testl(ecx, ecx);
|
__ testl(ecx, ecx);
|
||||||
__ j(not_zero, &extern_error_);
|
__ j(not_zero, &extern_error_);
|
||||||
|
|
||||||
@ -1798,8 +1706,8 @@ Compiler::emitErrorPaths()
|
|||||||
|
|
||||||
if (extern_error_.used()) {
|
if (extern_error_.used()) {
|
||||||
__ bind(&extern_error_);
|
__ bind(&extern_error_);
|
||||||
__ movl(eax, intptr_t(rt_->GetBaseContext()->GetCtx()));
|
__ movl(eax, intptr_t(rt_->GetBaseContext()));
|
||||||
__ movl(eax, Operand(eax, offsetof(sp_context_t, n_err)));
|
__ movl(eax, Operand(eax, PluginContext::offsetOfNativeError()));
|
||||||
__ jmp(ExternalAddress(env_->stubs()->ReturnStub()));
|
__ jmp(ExternalAddress(env_->stubs()->ReturnStub()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -91,22 +91,20 @@ class Compiler
|
|||||||
void emitFloatCmp(ConditionCode cc);
|
void emitFloatCmp(ConditionCode cc);
|
||||||
|
|
||||||
ExternalAddress cipAddr() {
|
ExternalAddress cipAddr() {
|
||||||
sp_context_t *ctx = rt_->GetBaseContext()->GetCtx();
|
return ExternalAddress(context_->addressOfCip());
|
||||||
return ExternalAddress(&ctx->cip);
|
|
||||||
}
|
}
|
||||||
ExternalAddress hpAddr() {
|
ExternalAddress hpAddr() {
|
||||||
sp_context_t *ctx = rt_->GetBaseContext()->GetCtx();
|
return ExternalAddress(context_->addressOfHp());
|
||||||
return ExternalAddress(&ctx->hp);
|
|
||||||
}
|
}
|
||||||
ExternalAddress frmAddr() {
|
ExternalAddress frmAddr() {
|
||||||
sp_context_t *ctx = rt_->GetBaseContext()->GetCtx();
|
return ExternalAddress(context_->addressOfFrm());
|
||||||
return ExternalAddress(&ctx->frm);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
AssemblerX86 masm;
|
AssemblerX86 masm;
|
||||||
sp::Environment *env_;
|
sp::Environment *env_;
|
||||||
PluginRuntime *rt_;
|
PluginRuntime *rt_;
|
||||||
|
PluginContext *context_;
|
||||||
const sp_plugin_t *plugin_;
|
const sp_plugin_t *plugin_;
|
||||||
int error_;
|
int error_;
|
||||||
uint32_t pcode_start_;
|
uint32_t pcode_start_;
|
||||||
|
Loading…
Reference in New Issue
Block a user