sourcemod/sourcepawn/jit/plugin-context.cpp

954 lines
21 KiB
C++
Raw Normal View History

2015-02-23 22:40:01 +01:00
// vim: set sts=2 ts=8 sw=2 tw=99 et:
//
// Copyright (C) 2006-2015 AlliedModders LLC
//
// This file is part of SourcePawn. SourcePawn is free software: you can
// redistribute it and/or modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation, either version 3 of
// the License, or (at your option) any later version.
//
// You should have received a copy of the GNU General Public License along with
// SourcePawn. If not, see http://www.gnu.org/licenses/.
//
#include <string.h>
#include <stdarg.h>
#include <assert.h>
#include <limits.h>
#include <sp_vm_api.h>
#include "plugin-context.h"
#include "watchdog_timer.h"
#include "x86/jit_x86.h"
#include "environment.h"
#include "compiled-function.h"
using namespace sp;
using namespace SourcePawn;
2015-02-23 22:40:01 +01:00
#define CELLBOUNDMAX (INT_MAX/sizeof(cell_t))
#define STACKMARGIN ((cell_t)(16*sizeof(cell_t)))
static const size_t kMinHeapSize = 16384;
2015-02-24 21:50:09 +01:00
PluginContext::PluginContext(PluginRuntime *pRuntime)
Implement a new stack and error handling model for the SourcePawn VM. This has three major changes to SourcePawn. First, the API now supports the concept of "exceptions". The exception state is a global property of an instance of the SourcePawn VM. Exceptions can be caught or suppressed. Many places in SourceMod have been updated to check exceptions instead of errors. The new API obsoletes major parts of the embedder API - all but one method of invoking functions is obsoleted, and the debug interface has been scrapped. Extensions using the native API will not be affected, however, ThrowNativeError has been deprecated in favor of ReportError. Second, the SourcePawn concept of a "stack" has been unified at the API level. A stack frame iterator now iterates over all SourcePawn invocations, rather than the topmost plugin. This makes error handling more consistent and removes another dependency on context-per-plugin. Finally, the implementation of stack frames has been changed dramatically. Rather than maintain a complicated and expensive return pointer stack, we now rely on the implicit one provided by the CPU. The stack frame iterator now walks the JIT stack directly. This removes many unnecessary bookkeeping instructions from the generated code, in particular making the CALL instruction 40% faster. These changes required some fair surgery to the JIT. Its error paths are now slightly more complicated, as they have to throw an exception rather than return an error code. In addition, any path that can throw an exception is now responsible for creating an "exit frame", which exists to tell the stack frame iterator about transitions from the JIT to the VM.
2015-02-27 09:32:44 +01:00
: env_(Environment::get()),
m_pRuntime(pRuntime),
memory_(nullptr),
data_size_(m_pRuntime->data().length),
mem_size_(m_pRuntime->image()->HeapSize()),
m_pNullVec(nullptr),
Implement a new stack and error handling model for the SourcePawn VM. This has three major changes to SourcePawn. First, the API now supports the concept of "exceptions". The exception state is a global property of an instance of the SourcePawn VM. Exceptions can be caught or suppressed. Many places in SourceMod have been updated to check exceptions instead of errors. The new API obsoletes major parts of the embedder API - all but one method of invoking functions is obsoleted, and the debug interface has been scrapped. Extensions using the native API will not be affected, however, ThrowNativeError has been deprecated in favor of ReportError. Second, the SourcePawn concept of a "stack" has been unified at the API level. A stack frame iterator now iterates over all SourcePawn invocations, rather than the topmost plugin. This makes error handling more consistent and removes another dependency on context-per-plugin. Finally, the implementation of stack frames has been changed dramatically. Rather than maintain a complicated and expensive return pointer stack, we now rely on the implicit one provided by the CPU. The stack frame iterator now walks the JIT stack directly. This removes many unnecessary bookkeeping instructions from the generated code, in particular making the CALL instruction 40% faster. These changes required some fair surgery to the JIT. Its error paths are now slightly more complicated, as they have to throw an exception rather than return an error code. In addition, any path that can throw an exception is now responsible for creating an "exit frame", which exists to tell the stack frame iterator about transitions from the JIT to the VM.
2015-02-27 09:32:44 +01:00
m_pNullString(nullptr)
{
// Compute and align a minimum memory amount.
if (mem_size_ < data_size_)
mem_size_ = data_size_;
mem_size_ = ke::Align(mem_size_, sizeof(cell_t));
// Add a minimum heap size if needed.
if (mem_size_ < data_size_ + kMinHeapSize)
mem_size_ = data_size_ + kMinHeapSize;
assert(ke::IsAligned(mem_size_, sizeof(cell_t)));
hp_ = data_size_;
sp_ = mem_size_ - sizeof(cell_t);
frm_ = sp_;
tracker_.pBase = (ucell_t *)malloc(1024);
tracker_.pCur = tracker_.pBase;
tracker_.size = 1024 / sizeof(cell_t);
}
PluginContext::~PluginContext()
{
free(tracker_.pBase);
delete[] memory_;
}
2015-02-23 22:40:01 +01:00
bool
PluginContext::Initialize()
{
memory_ = new uint8_t[mem_size_];
if (!memory_)
return false;
memset(memory_ + data_size_, 0, mem_size_ - data_size_);
memcpy(memory_, m_pRuntime->data().bytes, data_size_);
2015-02-23 22:40:01 +01:00
/* Initialize the null references */
uint32_t index;
if (FindPubvarByName("NULL_VECTOR", &index) == SP_ERROR_NONE) {
sp_pubvar_t *pubvar;
GetPubvarByIndex(index, &pubvar);
m_pNullVec = pubvar->offs;
} else {
m_pNullVec = NULL;
}
if (FindPubvarByName("NULL_STRING", &index) == SP_ERROR_NONE) {
sp_pubvar_t *pubvar;
GetPubvarByIndex(index, &pubvar);
m_pNullString = pubvar->offs;
} else {
m_pNullString = NULL;
}
return true;
}
2015-02-23 22:40:01 +01:00
IVirtualMachine *
2015-02-24 21:50:09 +01:00
PluginContext::GetVirtualMachine()
{
2015-02-23 22:40:01 +01:00
return NULL;
}
2015-02-23 22:40:01 +01:00
sp_context_t *
2015-02-24 21:50:09 +01:00
PluginContext::GetContext()
{
2015-02-23 22:40:01 +01:00
return reinterpret_cast<sp_context_t *>((IPluginContext * )this);
}
2015-02-23 22:40:01 +01:00
bool
2015-02-24 21:50:09 +01:00
PluginContext::IsDebugging()
{
2015-02-23 22:40:01 +01:00
return true;
}
2015-02-23 22:40:01 +01:00
int
2015-02-24 21:50:09 +01:00
PluginContext::SetDebugBreak(void *newpfn, void *oldpfn)
{
2015-02-23 22:40:01 +01:00
return SP_ERROR_ABORTED;
}
2015-02-23 22:40:01 +01:00
IPluginDebugInfo *
2015-02-24 21:50:09 +01:00
PluginContext::GetDebugInfo()
{
2015-02-23 22:40:01 +01:00
return NULL;
}
2015-02-23 22:40:01 +01:00
int
2015-02-24 21:50:09 +01:00
PluginContext::Execute(uint32_t code_addr, cell_t *result)
{
2015-02-23 22:40:01 +01:00
return SP_ERROR_ABORTED;
}
Implement a new stack and error handling model for the SourcePawn VM. This has three major changes to SourcePawn. First, the API now supports the concept of "exceptions". The exception state is a global property of an instance of the SourcePawn VM. Exceptions can be caught or suppressed. Many places in SourceMod have been updated to check exceptions instead of errors. The new API obsoletes major parts of the embedder API - all but one method of invoking functions is obsoleted, and the debug interface has been scrapped. Extensions using the native API will not be affected, however, ThrowNativeError has been deprecated in favor of ReportError. Second, the SourcePawn concept of a "stack" has been unified at the API level. A stack frame iterator now iterates over all SourcePawn invocations, rather than the topmost plugin. This makes error handling more consistent and removes another dependency on context-per-plugin. Finally, the implementation of stack frames has been changed dramatically. Rather than maintain a complicated and expensive return pointer stack, we now rely on the implicit one provided by the CPU. The stack frame iterator now walks the JIT stack directly. This removes many unnecessary bookkeeping instructions from the generated code, in particular making the CALL instruction 40% faster. These changes required some fair surgery to the JIT. Its error paths are now slightly more complicated, as they have to throw an exception rather than return an error code. In addition, any path that can throw an exception is now responsible for creating an "exit frame", which exists to tell the stack frame iterator about transitions from the JIT to the VM.
2015-02-27 09:32:44 +01:00
cell_t
PluginContext::ThrowNativeErrorEx(int error, const char *msg, ...)
{
2015-02-23 22:40:01 +01:00
va_list ap;
va_start(ap, msg);
Implement a new stack and error handling model for the SourcePawn VM. This has three major changes to SourcePawn. First, the API now supports the concept of "exceptions". The exception state is a global property of an instance of the SourcePawn VM. Exceptions can be caught or suppressed. Many places in SourceMod have been updated to check exceptions instead of errors. The new API obsoletes major parts of the embedder API - all but one method of invoking functions is obsoleted, and the debug interface has been scrapped. Extensions using the native API will not be affected, however, ThrowNativeError has been deprecated in favor of ReportError. Second, the SourcePawn concept of a "stack" has been unified at the API level. A stack frame iterator now iterates over all SourcePawn invocations, rather than the topmost plugin. This makes error handling more consistent and removes another dependency on context-per-plugin. Finally, the implementation of stack frames has been changed dramatically. Rather than maintain a complicated and expensive return pointer stack, we now rely on the implicit one provided by the CPU. The stack frame iterator now walks the JIT stack directly. This removes many unnecessary bookkeeping instructions from the generated code, in particular making the CALL instruction 40% faster. These changes required some fair surgery to the JIT. Its error paths are now slightly more complicated, as they have to throw an exception rather than return an error code. In addition, any path that can throw an exception is now responsible for creating an "exit frame", which exists to tell the stack frame iterator about transitions from the JIT to the VM.
2015-02-27 09:32:44 +01:00
env_->ReportErrorVA(error, msg, ap);
2015-02-23 22:40:01 +01:00
va_end(ap);
return 0;
}
2015-02-23 22:40:01 +01:00
cell_t
2015-02-24 21:50:09 +01:00
PluginContext::ThrowNativeError(const char *msg, ...)
{
Implement a new stack and error handling model for the SourcePawn VM. This has three major changes to SourcePawn. First, the API now supports the concept of "exceptions". The exception state is a global property of an instance of the SourcePawn VM. Exceptions can be caught or suppressed. Many places in SourceMod have been updated to check exceptions instead of errors. The new API obsoletes major parts of the embedder API - all but one method of invoking functions is obsoleted, and the debug interface has been scrapped. Extensions using the native API will not be affected, however, ThrowNativeError has been deprecated in favor of ReportError. Second, the SourcePawn concept of a "stack" has been unified at the API level. A stack frame iterator now iterates over all SourcePawn invocations, rather than the topmost plugin. This makes error handling more consistent and removes another dependency on context-per-plugin. Finally, the implementation of stack frames has been changed dramatically. Rather than maintain a complicated and expensive return pointer stack, we now rely on the implicit one provided by the CPU. The stack frame iterator now walks the JIT stack directly. This removes many unnecessary bookkeeping instructions from the generated code, in particular making the CALL instruction 40% faster. These changes required some fair surgery to the JIT. Its error paths are now slightly more complicated, as they have to throw an exception rather than return an error code. In addition, any path that can throw an exception is now responsible for creating an "exit frame", which exists to tell the stack frame iterator about transitions from the JIT to the VM.
2015-02-27 09:32:44 +01:00
va_list ap;
va_start(ap, msg);
env_->ReportErrorVA(SP_ERROR_NATIVE, msg, ap);
va_end(ap);
2015-02-23 22:40:01 +01:00
return 0;
}
2015-02-23 22:40:01 +01:00
int
2015-02-24 21:50:09 +01:00
PluginContext::HeapAlloc(unsigned int cells, cell_t *local_addr, cell_t **phys_addr)
{
2015-02-23 22:40:01 +01:00
cell_t *addr;
ucell_t realmem;
#if 0
2015-02-23 22:40:01 +01:00
if (cells > CELLBOUNDMAX)
{
return SP_ERROR_ARAM;
}
#else
2015-02-23 22:40:01 +01:00
assert(cells < CELLBOUNDMAX);
#endif
2015-02-23 22:40:01 +01:00
realmem = cells * sizeof(cell_t);
2015-02-23 22:40:01 +01:00
/**
* Check if the space between the heap and stack is sufficient.
*/
if ((cell_t)(sp_ - hp_ - realmem) < STACKMARGIN)
2015-02-23 22:40:01 +01:00
return SP_ERROR_HEAPLOW;
addr = (cell_t *)(memory_ + hp_);
2015-02-23 22:40:01 +01:00
/* store size of allocation in cells */
*addr = (cell_t)cells;
addr++;
hp_ += sizeof(cell_t);
*local_addr = hp_;
2015-02-23 22:40:01 +01:00
if (phys_addr)
*phys_addr = addr;
hp_ += realmem;
2015-02-23 22:40:01 +01:00
return SP_ERROR_NONE;
}
2015-02-23 22:40:01 +01:00
int
2015-02-24 21:50:09 +01:00
PluginContext::HeapPop(cell_t local_addr)
{
2015-02-23 22:40:01 +01:00
cell_t cellcount;
cell_t *addr;
2015-02-23 22:40:01 +01:00
/* check the bounds of this address */
local_addr -= sizeof(cell_t);
if (local_addr < (cell_t)data_size_ || local_addr >= sp_)
2015-02-23 22:40:01 +01:00
return SP_ERROR_INVALID_ADDRESS;
addr = (cell_t *)(memory_ + local_addr);
2015-02-23 22:40:01 +01:00
cellcount = (*addr) * sizeof(cell_t);
/* check if this memory count looks valid */
if ((signed)(hp_ - cellcount - sizeof(cell_t)) != local_addr)
2015-02-23 22:40:01 +01:00
return SP_ERROR_INVALID_ADDRESS;
hp_ = local_addr;
2015-02-23 22:40:01 +01:00
return SP_ERROR_NONE;
}
2015-02-23 22:40:01 +01:00
int
2015-02-24 21:50:09 +01:00
PluginContext::HeapRelease(cell_t local_addr)
{
if (local_addr < (cell_t)data_size_)
2015-02-23 22:40:01 +01:00
return SP_ERROR_INVALID_ADDRESS;
hp_ = local_addr - sizeof(cell_t);
2015-02-23 22:40:01 +01:00
return SP_ERROR_NONE;
}
2015-02-23 22:40:01 +01:00
int
2015-02-24 21:50:09 +01:00
PluginContext::FindNativeByName(const char *name, uint32_t *index)
{
2015-02-23 22:40:01 +01:00
return m_pRuntime->FindNativeByName(name, index);
}
2015-02-23 22:40:01 +01:00
int
2015-02-24 21:50:09 +01:00
PluginContext::GetNativeByIndex(uint32_t index, sp_native_t **native)
{
2015-02-23 22:40:01 +01:00
return m_pRuntime->GetNativeByIndex(index, native);
}
2015-02-23 22:40:01 +01:00
uint32_t
2015-02-24 21:50:09 +01:00
PluginContext::GetNativesNum()
{
2015-02-23 22:40:01 +01:00
return m_pRuntime->GetNativesNum();
}
2015-02-23 22:40:01 +01:00
int
2015-02-24 21:50:09 +01:00
PluginContext::FindPublicByName(const char *name, uint32_t *index)
{
2015-02-23 22:40:01 +01:00
return m_pRuntime->FindPublicByName(name, index);
}
2015-02-23 22:40:01 +01:00
int
2015-02-24 21:50:09 +01:00
PluginContext::GetPublicByIndex(uint32_t index, sp_public_t **pblic)
{
2015-02-23 22:40:01 +01:00
return m_pRuntime->GetPublicByIndex(index, pblic);
}
2015-02-23 22:40:01 +01:00
uint32_t
2015-02-24 21:50:09 +01:00
PluginContext::GetPublicsNum()
{
2015-02-23 22:40:01 +01:00
return m_pRuntime->GetPublicsNum();
}
2015-02-23 22:40:01 +01:00
int
2015-02-24 21:50:09 +01:00
PluginContext::GetPubvarByIndex(uint32_t index, sp_pubvar_t **pubvar)
{
2015-02-23 22:40:01 +01:00
return m_pRuntime->GetPubvarByIndex(index, pubvar);
}
2015-02-23 22:40:01 +01:00
int
2015-02-24 21:50:09 +01:00
PluginContext::FindPubvarByName(const char *name, uint32_t *index)
{
2015-02-23 22:40:01 +01:00
return m_pRuntime->FindPubvarByName(name, index);
}
2015-02-23 22:40:01 +01:00
int
2015-02-24 21:50:09 +01:00
PluginContext::GetPubvarAddrs(uint32_t index, cell_t *local_addr, cell_t **phys_addr)
{
2015-02-23 22:40:01 +01:00
return m_pRuntime->GetPubvarAddrs(index, local_addr, phys_addr);
}
2015-02-23 22:40:01 +01:00
uint32_t
2015-02-24 21:50:09 +01:00
PluginContext::GetPubVarsNum()
{
2015-02-23 22:40:01 +01:00
return m_pRuntime->GetPubVarsNum();
}
2015-02-23 22:40:01 +01:00
int
2015-02-24 21:50:09 +01:00
PluginContext::BindNatives(const sp_nativeinfo_t *natives, unsigned int num, int overwrite)
{
2015-02-23 22:40:01 +01:00
return SP_ERROR_ABORTED;
}
2015-02-23 22:40:01 +01:00
int
2015-02-24 21:50:09 +01:00
PluginContext::BindNative(const sp_nativeinfo_t *native)
{
2015-02-23 22:40:01 +01:00
return SP_ERROR_ABORTED;
}
2015-02-23 22:40:01 +01:00
int
2015-02-24 21:50:09 +01:00
PluginContext::BindNativeToIndex(uint32_t index, SPVM_NATIVE_FUNC func)
{
2015-02-23 22:40:01 +01:00
return SP_ERROR_ABORTED;
}
2015-02-23 22:40:01 +01:00
int
2015-02-24 21:50:09 +01:00
PluginContext::BindNativeToAny(SPVM_NATIVE_FUNC native)
{
2015-02-23 22:40:01 +01:00
return SP_ERROR_ABORTED;
}
2015-02-23 22:40:01 +01:00
int
2015-02-24 21:50:09 +01:00
PluginContext::LocalToPhysAddr(cell_t local_addr, cell_t **phys_addr)
{
if (((local_addr >= hp_) && (local_addr < sp_)) ||
(local_addr < 0) || ((ucell_t)local_addr >= mem_size_))
2015-02-23 22:40:01 +01:00
{
return SP_ERROR_INVALID_ADDRESS;
}
2015-02-23 22:40:01 +01:00
if (phys_addr)
*phys_addr = (cell_t *)(memory_ + local_addr);
2015-02-23 22:40:01 +01:00
return SP_ERROR_NONE;
}
2015-02-23 22:40:01 +01:00
int
2015-02-24 21:50:09 +01:00
PluginContext::PushCell(cell_t value)
{
2015-02-23 22:40:01 +01:00
return SP_ERROR_ABORTED;
}
2015-02-23 22:40:01 +01:00
int
2015-02-24 21:50:09 +01:00
PluginContext::PushCellsFromArray(cell_t array[], unsigned int numcells)
{
2015-02-23 22:40:01 +01:00
return SP_ERROR_ABORTED;
}
2015-02-23 22:40:01 +01:00
int
2015-02-24 21:50:09 +01:00
PluginContext::PushCellArray(cell_t *local_addr, cell_t **phys_addr, cell_t array[], unsigned int numcells)
{
2015-02-23 22:40:01 +01:00
return SP_ERROR_ABORTED;
}
2015-02-23 22:40:01 +01:00
int
2015-02-24 21:50:09 +01:00
PluginContext::LocalToString(cell_t local_addr, char **addr)
{
if (((local_addr >= hp_) && (local_addr < sp_)) ||
(local_addr < 0) || ((ucell_t)local_addr >= mem_size_))
2015-02-23 22:40:01 +01:00
{
return SP_ERROR_INVALID_ADDRESS;
}
*addr = (char *)(memory_ + local_addr);
2015-02-23 22:40:01 +01:00
return SP_ERROR_NONE;
}
2015-02-23 22:40:01 +01:00
int
2015-02-24 21:50:09 +01:00
PluginContext::PushString(cell_t *local_addr, char **phys_addr, const char *string)
{
2015-02-23 22:40:01 +01:00
return SP_ERROR_ABORTED;
}
2015-02-23 22:40:01 +01:00
int
2015-02-24 21:50:09 +01:00
PluginContext::StringToLocal(cell_t local_addr, size_t bytes, const char *source)
{
2015-02-23 22:40:01 +01:00
char *dest;
size_t len;
if (((local_addr >= hp_) && (local_addr < sp_)) ||
(local_addr < 0) || ((ucell_t)local_addr >= mem_size_))
2015-02-23 22:40:01 +01:00
{
return SP_ERROR_INVALID_ADDRESS;
}
2015-02-23 22:40:01 +01:00
if (bytes == 0)
return SP_ERROR_NONE;
2015-02-23 22:40:01 +01:00
len = strlen(source);
dest = (char *)(memory_ + local_addr);
2015-02-23 22:40:01 +01:00
if (len >= bytes)
len = bytes - 1;
2015-02-23 22:40:01 +01:00
memmove(dest, source, len);
dest[len] = '\0';
2015-02-23 22:40:01 +01:00
return SP_ERROR_NONE;
}
2015-02-23 22:40:01 +01:00
static inline int
__CheckValidChar(char *c)
{
2015-02-23 22:40:01 +01:00
int count;
int bytecount = 0;
2015-02-23 22:40:01 +01:00
for (count=1; (*c & 0xC0) == 0x80; count++)
c--;
2015-02-23 22:40:01 +01:00
switch (*c & 0xF0)
{
case 0xC0:
case 0xD0:
{
bytecount = 2;
break;
}
case 0xE0:
{
bytecount = 3;
break;
}
case 0xF0:
{
bytecount = 4;
break;
}
}
2015-02-23 22:40:01 +01:00
if (bytecount != count)
return count;
2015-02-23 22:40:01 +01:00
return 0;
}
2015-02-23 22:40:01 +01:00
int
2015-02-24 21:50:09 +01:00
PluginContext::StringToLocalUTF8(cell_t local_addr, size_t maxbytes, const char *source, size_t *wrtnbytes)
{
2015-02-23 22:40:01 +01:00
char *dest;
size_t len;
bool needtocheck = false;
if (((local_addr >= hp_) && (local_addr < sp_)) ||
2015-02-23 22:40:01 +01:00
(local_addr < 0) ||
((ucell_t)local_addr >= mem_size_))
2015-02-23 22:40:01 +01:00
{
return SP_ERROR_INVALID_ADDRESS;
}
if (maxbytes == 0)
return SP_ERROR_NONE;
2015-02-23 22:40:01 +01:00
len = strlen(source);
dest = (char *)(memory_ + local_addr);
2015-02-23 22:40:01 +01:00
if ((size_t)len >= maxbytes) {
len = maxbytes - 1;
needtocheck = true;
}
2015-02-23 22:40:01 +01:00
memmove(dest, source, len);
if ((dest[len-1] & 1<<7) && needtocheck)
len -= __CheckValidChar(dest+len-1);
dest[len] = '\0';
2015-02-23 22:40:01 +01:00
if (wrtnbytes)
*wrtnbytes = len;
2015-02-23 22:40:01 +01:00
return SP_ERROR_NONE;
}
2015-02-23 22:40:01 +01:00
IPluginFunction *
2015-02-24 21:50:09 +01:00
PluginContext::GetFunctionById(funcid_t func_id)
{
2015-02-23 22:40:01 +01:00
return m_pRuntime->GetFunctionById(func_id);
}
2015-02-23 22:40:01 +01:00
IPluginFunction *
2015-02-24 21:50:09 +01:00
PluginContext::GetFunctionByName(const char *public_name)
{
2015-02-23 22:40:01 +01:00
return m_pRuntime->GetFunctionByName(public_name);
}
2015-02-23 22:40:01 +01:00
int
2015-02-24 21:50:09 +01:00
PluginContext::LocalToStringNULL(cell_t local_addr, char **addr)
{
2015-02-23 22:40:01 +01:00
int err;
if ((err = LocalToString(local_addr, addr)) != SP_ERROR_NONE)
return err;
2015-02-23 22:40:01 +01:00
if ((cell_t *)*addr == m_pNullString)
*addr = NULL;
2015-02-23 22:40:01 +01:00
return SP_ERROR_NONE;
}
2015-02-23 22:40:01 +01:00
SourceMod::IdentityToken_t *
2015-02-24 21:50:09 +01:00
PluginContext::GetIdentity()
{
2015-02-23 22:40:01 +01:00
SourceMod::IdentityToken_t *tok;
2015-02-23 22:40:01 +01:00
if (GetKey(1, (void **)&tok))
return tok;
return NULL;
}
2015-02-23 22:40:01 +01:00
cell_t *
2015-02-24 21:50:09 +01:00
PluginContext::GetNullRef(SP_NULL_TYPE type)
{
2015-02-23 22:40:01 +01:00
if (type == SP_NULL_VECTOR)
return m_pNullVec;
2015-02-23 22:40:01 +01:00
return NULL;
}
2015-02-23 22:40:01 +01:00
bool
2015-02-24 21:50:09 +01:00
PluginContext::IsInExec()
{
Implement a new stack and error handling model for the SourcePawn VM. This has three major changes to SourcePawn. First, the API now supports the concept of "exceptions". The exception state is a global property of an instance of the SourcePawn VM. Exceptions can be caught or suppressed. Many places in SourceMod have been updated to check exceptions instead of errors. The new API obsoletes major parts of the embedder API - all but one method of invoking functions is obsoleted, and the debug interface has been scrapped. Extensions using the native API will not be affected, however, ThrowNativeError has been deprecated in favor of ReportError. Second, the SourcePawn concept of a "stack" has been unified at the API level. A stack frame iterator now iterates over all SourcePawn invocations, rather than the topmost plugin. This makes error handling more consistent and removes another dependency on context-per-plugin. Finally, the implementation of stack frames has been changed dramatically. Rather than maintain a complicated and expensive return pointer stack, we now rely on the implicit one provided by the CPU. The stack frame iterator now walks the JIT stack directly. This removes many unnecessary bookkeeping instructions from the generated code, in particular making the CALL instruction 40% faster. These changes required some fair surgery to the JIT. Its error paths are now slightly more complicated, as they have to throw an exception rather than return an error code. In addition, any path that can throw an exception is now responsible for creating an "exit frame", which exists to tell the stack frame iterator about transitions from the JIT to the VM.
2015-02-27 09:32:44 +01:00
for (InvokeFrame *ivk = env_->top(); ivk; ivk = ivk->prev()) {
if (ivk->cx() == this)
return true;
}
return false;
}
2015-02-23 22:40:01 +01:00
int
2015-02-24 21:50:09 +01:00
PluginContext::Execute2(IPluginFunction *function, const cell_t *params, unsigned int num_params, cell_t *result)
{
Implement a new stack and error handling model for the SourcePawn VM. This has three major changes to SourcePawn. First, the API now supports the concept of "exceptions". The exception state is a global property of an instance of the SourcePawn VM. Exceptions can be caught or suppressed. Many places in SourceMod have been updated to check exceptions instead of errors. The new API obsoletes major parts of the embedder API - all but one method of invoking functions is obsoleted, and the debug interface has been scrapped. Extensions using the native API will not be affected, however, ThrowNativeError has been deprecated in favor of ReportError. Second, the SourcePawn concept of a "stack" has been unified at the API level. A stack frame iterator now iterates over all SourcePawn invocations, rather than the topmost plugin. This makes error handling more consistent and removes another dependency on context-per-plugin. Finally, the implementation of stack frames has been changed dramatically. Rather than maintain a complicated and expensive return pointer stack, we now rely on the implicit one provided by the CPU. The stack frame iterator now walks the JIT stack directly. This removes many unnecessary bookkeeping instructions from the generated code, in particular making the CALL instruction 40% faster. These changes required some fair surgery to the JIT. Its error paths are now slightly more complicated, as they have to throw an exception rather than return an error code. In addition, any path that can throw an exception is now responsible for creating an "exit frame", which exists to tell the stack frame iterator about transitions from the JIT to the VM.
2015-02-27 09:32:44 +01:00
ReportErrorNumber(SP_ERROR_ABORTED);
return SP_ERROR_ABORTED;
}
2015-02-23 22:40:01 +01:00
Implement a new stack and error handling model for the SourcePawn VM. This has three major changes to SourcePawn. First, the API now supports the concept of "exceptions". The exception state is a global property of an instance of the SourcePawn VM. Exceptions can be caught or suppressed. Many places in SourceMod have been updated to check exceptions instead of errors. The new API obsoletes major parts of the embedder API - all but one method of invoking functions is obsoleted, and the debug interface has been scrapped. Extensions using the native API will not be affected, however, ThrowNativeError has been deprecated in favor of ReportError. Second, the SourcePawn concept of a "stack" has been unified at the API level. A stack frame iterator now iterates over all SourcePawn invocations, rather than the topmost plugin. This makes error handling more consistent and removes another dependency on context-per-plugin. Finally, the implementation of stack frames has been changed dramatically. Rather than maintain a complicated and expensive return pointer stack, we now rely on the implicit one provided by the CPU. The stack frame iterator now walks the JIT stack directly. This removes many unnecessary bookkeeping instructions from the generated code, in particular making the CALL instruction 40% faster. These changes required some fair surgery to the JIT. Its error paths are now slightly more complicated, as they have to throw an exception rather than return an error code. In addition, any path that can throw an exception is now responsible for creating an "exit frame", which exists to tell the stack frame iterator about transitions from the JIT to the VM.
2015-02-27 09:32:44 +01:00
bool
PluginContext::Invoke(funcid_t fnid, const cell_t *params, unsigned int num_params, cell_t *result)
{
2015-02-23 22:40:01 +01:00
EnterProfileScope profileScope("SourcePawn", "EnterJIT");
Implement a new stack and error handling model for the SourcePawn VM. This has three major changes to SourcePawn. First, the API now supports the concept of "exceptions". The exception state is a global property of an instance of the SourcePawn VM. Exceptions can be caught or suppressed. Many places in SourceMod have been updated to check exceptions instead of errors. The new API obsoletes major parts of the embedder API - all but one method of invoking functions is obsoleted, and the debug interface has been scrapped. Extensions using the native API will not be affected, however, ThrowNativeError has been deprecated in favor of ReportError. Second, the SourcePawn concept of a "stack" has been unified at the API level. A stack frame iterator now iterates over all SourcePawn invocations, rather than the topmost plugin. This makes error handling more consistent and removes another dependency on context-per-plugin. Finally, the implementation of stack frames has been changed dramatically. Rather than maintain a complicated and expensive return pointer stack, we now rely on the implicit one provided by the CPU. The stack frame iterator now walks the JIT stack directly. This removes many unnecessary bookkeeping instructions from the generated code, in particular making the CALL instruction 40% faster. These changes required some fair surgery to the JIT. Its error paths are now slightly more complicated, as they have to throw an exception rather than return an error code. In addition, any path that can throw an exception is now responsible for creating an "exit frame", which exists to tell the stack frame iterator about transitions from the JIT to the VM.
2015-02-27 09:32:44 +01:00
if (!env_->watchdog()->HandleInterrupt()) {
ReportErrorNumber(SP_ERROR_TIMEOUT);
return false;
}
Implement a new stack and error handling model for the SourcePawn VM. This has three major changes to SourcePawn. First, the API now supports the concept of "exceptions". The exception state is a global property of an instance of the SourcePawn VM. Exceptions can be caught or suppressed. Many places in SourceMod have been updated to check exceptions instead of errors. The new API obsoletes major parts of the embedder API - all but one method of invoking functions is obsoleted, and the debug interface has been scrapped. Extensions using the native API will not be affected, however, ThrowNativeError has been deprecated in favor of ReportError. Second, the SourcePawn concept of a "stack" has been unified at the API level. A stack frame iterator now iterates over all SourcePawn invocations, rather than the topmost plugin. This makes error handling more consistent and removes another dependency on context-per-plugin. Finally, the implementation of stack frames has been changed dramatically. Rather than maintain a complicated and expensive return pointer stack, we now rely on the implicit one provided by the CPU. The stack frame iterator now walks the JIT stack directly. This removes many unnecessary bookkeeping instructions from the generated code, in particular making the CALL instruction 40% faster. These changes required some fair surgery to the JIT. Its error paths are now slightly more complicated, as they have to throw an exception rather than return an error code. In addition, any path that can throw an exception is now responsible for creating an "exit frame", which exists to tell the stack frame iterator about transitions from the JIT to the VM.
2015-02-27 09:32:44 +01:00
assert((fnid & 1) != 0);
2015-02-23 22:40:01 +01:00
unsigned public_id = fnid >> 1;
ScriptedInvoker *cfun = m_pRuntime->GetPublicFunction(public_id);
Implement a new stack and error handling model for the SourcePawn VM. This has three major changes to SourcePawn. First, the API now supports the concept of "exceptions". The exception state is a global property of an instance of the SourcePawn VM. Exceptions can be caught or suppressed. Many places in SourceMod have been updated to check exceptions instead of errors. The new API obsoletes major parts of the embedder API - all but one method of invoking functions is obsoleted, and the debug interface has been scrapped. Extensions using the native API will not be affected, however, ThrowNativeError has been deprecated in favor of ReportError. Second, the SourcePawn concept of a "stack" has been unified at the API level. A stack frame iterator now iterates over all SourcePawn invocations, rather than the topmost plugin. This makes error handling more consistent and removes another dependency on context-per-plugin. Finally, the implementation of stack frames has been changed dramatically. Rather than maintain a complicated and expensive return pointer stack, we now rely on the implicit one provided by the CPU. The stack frame iterator now walks the JIT stack directly. This removes many unnecessary bookkeeping instructions from the generated code, in particular making the CALL instruction 40% faster. These changes required some fair surgery to the JIT. Its error paths are now slightly more complicated, as they have to throw an exception rather than return an error code. In addition, any path that can throw an exception is now responsible for creating an "exit frame", which exists to tell the stack frame iterator about transitions from the JIT to the VM.
2015-02-27 09:32:44 +01:00
if (!cfun) {
ReportErrorNumber(SP_ERROR_NOT_FOUND);
return false;
}
if (m_pRuntime->IsPaused()) {
ReportErrorNumber(SP_ERROR_NOT_RUNNABLE);
return false;
}
Implement a new stack and error handling model for the SourcePawn VM. This has three major changes to SourcePawn. First, the API now supports the concept of "exceptions". The exception state is a global property of an instance of the SourcePawn VM. Exceptions can be caught or suppressed. Many places in SourceMod have been updated to check exceptions instead of errors. The new API obsoletes major parts of the embedder API - all but one method of invoking functions is obsoleted, and the debug interface has been scrapped. Extensions using the native API will not be affected, however, ThrowNativeError has been deprecated in favor of ReportError. Second, the SourcePawn concept of a "stack" has been unified at the API level. A stack frame iterator now iterates over all SourcePawn invocations, rather than the topmost plugin. This makes error handling more consistent and removes another dependency on context-per-plugin. Finally, the implementation of stack frames has been changed dramatically. Rather than maintain a complicated and expensive return pointer stack, we now rely on the implicit one provided by the CPU. The stack frame iterator now walks the JIT stack directly. This removes many unnecessary bookkeeping instructions from the generated code, in particular making the CALL instruction 40% faster. These changes required some fair surgery to the JIT. Its error paths are now slightly more complicated, as they have to throw an exception rather than return an error code. In addition, any path that can throw an exception is now responsible for creating an "exit frame", which exists to tell the stack frame iterator about transitions from the JIT to the VM.
2015-02-27 09:32:44 +01:00
if ((cell_t)(hp_ + 16*sizeof(cell_t)) > (cell_t)(sp_ - (sizeof(cell_t) * (num_params + 1)))) {
ReportErrorNumber(SP_ERROR_STACKLOW);
return false;
}
Implement a new stack and error handling model for the SourcePawn VM. This has three major changes to SourcePawn. First, the API now supports the concept of "exceptions". The exception state is a global property of an instance of the SourcePawn VM. Exceptions can be caught or suppressed. Many places in SourceMod have been updated to check exceptions instead of errors. The new API obsoletes major parts of the embedder API - all but one method of invoking functions is obsoleted, and the debug interface has been scrapped. Extensions using the native API will not be affected, however, ThrowNativeError has been deprecated in favor of ReportError. Second, the SourcePawn concept of a "stack" has been unified at the API level. A stack frame iterator now iterates over all SourcePawn invocations, rather than the topmost plugin. This makes error handling more consistent and removes another dependency on context-per-plugin. Finally, the implementation of stack frames has been changed dramatically. Rather than maintain a complicated and expensive return pointer stack, we now rely on the implicit one provided by the CPU. The stack frame iterator now walks the JIT stack directly. This removes many unnecessary bookkeeping instructions from the generated code, in particular making the CALL instruction 40% faster. These changes required some fair surgery to the JIT. Its error paths are now slightly more complicated, as they have to throw an exception rather than return an error code. In addition, any path that can throw an exception is now responsible for creating an "exit frame", which exists to tell the stack frame iterator about transitions from the JIT to the VM.
2015-02-27 09:32:44 +01:00
// Yuck. We have to do this for compatibility, otherwise something like
// ForwardSys or any sort of multi-callback-fire code would die. Later,
// we'll expose an Invoke() or something that doesn't do this.
env_->clearPendingException();
Implement a new stack and error handling model for the SourcePawn VM. This has three major changes to SourcePawn. First, the API now supports the concept of "exceptions". The exception state is a global property of an instance of the SourcePawn VM. Exceptions can be caught or suppressed. Many places in SourceMod have been updated to check exceptions instead of errors. The new API obsoletes major parts of the embedder API - all but one method of invoking functions is obsoleted, and the debug interface has been scrapped. Extensions using the native API will not be affected, however, ThrowNativeError has been deprecated in favor of ReportError. Second, the SourcePawn concept of a "stack" has been unified at the API level. A stack frame iterator now iterates over all SourcePawn invocations, rather than the topmost plugin. This makes error handling more consistent and removes another dependency on context-per-plugin. Finally, the implementation of stack frames has been changed dramatically. Rather than maintain a complicated and expensive return pointer stack, we now rely on the implicit one provided by the CPU. The stack frame iterator now walks the JIT stack directly. This removes many unnecessary bookkeeping instructions from the generated code, in particular making the CALL instruction 40% faster. These changes required some fair surgery to the JIT. Its error paths are now slightly more complicated, as they have to throw an exception rather than return an error code. In addition, any path that can throw an exception is now responsible for creating an "exit frame", which exists to tell the stack frame iterator about transitions from the JIT to the VM.
2015-02-27 09:32:44 +01:00
cell_t ignore_result;
2015-02-23 22:40:01 +01:00
if (result == NULL)
Implement a new stack and error handling model for the SourcePawn VM. This has three major changes to SourcePawn. First, the API now supports the concept of "exceptions". The exception state is a global property of an instance of the SourcePawn VM. Exceptions can be caught or suppressed. Many places in SourceMod have been updated to check exceptions instead of errors. The new API obsoletes major parts of the embedder API - all but one method of invoking functions is obsoleted, and the debug interface has been scrapped. Extensions using the native API will not be affected, however, ThrowNativeError has been deprecated in favor of ReportError. Second, the SourcePawn concept of a "stack" has been unified at the API level. A stack frame iterator now iterates over all SourcePawn invocations, rather than the topmost plugin. This makes error handling more consistent and removes another dependency on context-per-plugin. Finally, the implementation of stack frames has been changed dramatically. Rather than maintain a complicated and expensive return pointer stack, we now rely on the implicit one provided by the CPU. The stack frame iterator now walks the JIT stack directly. This removes many unnecessary bookkeeping instructions from the generated code, in particular making the CALL instruction 40% faster. These changes required some fair surgery to the JIT. Its error paths are now slightly more complicated, as they have to throw an exception rather than return an error code. In addition, any path that can throw an exception is now responsible for creating an "exit frame", which exists to tell the stack frame iterator about transitions from the JIT to the VM.
2015-02-27 09:32:44 +01:00
result = &ignore_result;
2015-02-23 22:40:01 +01:00
/* We got this far. It's time to start profiling. */
EnterProfileScope scriptScope("SourcePawn", cfun->FullName());
2015-02-23 22:40:01 +01:00
/* See if we have to compile the callee. */
Implement a new stack and error handling model for the SourcePawn VM. This has three major changes to SourcePawn. First, the API now supports the concept of "exceptions". The exception state is a global property of an instance of the SourcePawn VM. Exceptions can be caught or suppressed. Many places in SourceMod have been updated to check exceptions instead of errors. The new API obsoletes major parts of the embedder API - all but one method of invoking functions is obsoleted, and the debug interface has been scrapped. Extensions using the native API will not be affected, however, ThrowNativeError has been deprecated in favor of ReportError. Second, the SourcePawn concept of a "stack" has been unified at the API level. A stack frame iterator now iterates over all SourcePawn invocations, rather than the topmost plugin. This makes error handling more consistent and removes another dependency on context-per-plugin. Finally, the implementation of stack frames has been changed dramatically. Rather than maintain a complicated and expensive return pointer stack, we now rely on the implicit one provided by the CPU. The stack frame iterator now walks the JIT stack directly. This removes many unnecessary bookkeeping instructions from the generated code, in particular making the CALL instruction 40% faster. These changes required some fair surgery to the JIT. Its error paths are now slightly more complicated, as they have to throw an exception rather than return an error code. In addition, any path that can throw an exception is now responsible for creating an "exit frame", which exists to tell the stack frame iterator about transitions from the JIT to the VM.
2015-02-27 09:32:44 +01:00
CompiledFunction *fn = nullptr;
if (env_->IsJitEnabled()) {
2015-02-23 22:40:01 +01:00
/* We might not have to - check pcode offset. */
2015-02-25 08:37:23 +01:00
if ((fn = cfun->cachedCompiledFunction()) == nullptr) {
fn = m_pRuntime->GetJittedFunctionByOffset(cfun->Public()->code_offs);
if (!fn) {
Implement a new stack and error handling model for the SourcePawn VM. This has three major changes to SourcePawn. First, the API now supports the concept of "exceptions". The exception state is a global property of an instance of the SourcePawn VM. Exceptions can be caught or suppressed. Many places in SourceMod have been updated to check exceptions instead of errors. The new API obsoletes major parts of the embedder API - all but one method of invoking functions is obsoleted, and the debug interface has been scrapped. Extensions using the native API will not be affected, however, ThrowNativeError has been deprecated in favor of ReportError. Second, the SourcePawn concept of a "stack" has been unified at the API level. A stack frame iterator now iterates over all SourcePawn invocations, rather than the topmost plugin. This makes error handling more consistent and removes another dependency on context-per-plugin. Finally, the implementation of stack frames has been changed dramatically. Rather than maintain a complicated and expensive return pointer stack, we now rely on the implicit one provided by the CPU. The stack frame iterator now walks the JIT stack directly. This removes many unnecessary bookkeeping instructions from the generated code, in particular making the CALL instruction 40% faster. These changes required some fair surgery to the JIT. Its error paths are now slightly more complicated, as they have to throw an exception rather than return an error code. In addition, any path that can throw an exception is now responsible for creating an "exit frame", which exists to tell the stack frame iterator about transitions from the JIT to the VM.
2015-02-27 09:32:44 +01:00
int err = SP_ERROR_NONE;
if ((fn = CompileFunction(m_pRuntime, cfun->Public()->code_offs, &err)) == NULL) {
ReportErrorNumber(err);
return false;
}
2015-02-25 08:37:23 +01:00
}
cfun->setCachedCompiledFunction(fn);
2015-02-23 22:40:01 +01:00
}
Implement a new stack and error handling model for the SourcePawn VM. This has three major changes to SourcePawn. First, the API now supports the concept of "exceptions". The exception state is a global property of an instance of the SourcePawn VM. Exceptions can be caught or suppressed. Many places in SourceMod have been updated to check exceptions instead of errors. The new API obsoletes major parts of the embedder API - all but one method of invoking functions is obsoleted, and the debug interface has been scrapped. Extensions using the native API will not be affected, however, ThrowNativeError has been deprecated in favor of ReportError. Second, the SourcePawn concept of a "stack" has been unified at the API level. A stack frame iterator now iterates over all SourcePawn invocations, rather than the topmost plugin. This makes error handling more consistent and removes another dependency on context-per-plugin. Finally, the implementation of stack frames has been changed dramatically. Rather than maintain a complicated and expensive return pointer stack, we now rely on the implicit one provided by the CPU. The stack frame iterator now walks the JIT stack directly. This removes many unnecessary bookkeeping instructions from the generated code, in particular making the CALL instruction 40% faster. These changes required some fair surgery to the JIT. Its error paths are now slightly more complicated, as they have to throw an exception rather than return an error code. In addition, any path that can throw an exception is now responsible for creating an "exit frame", which exists to tell the stack frame iterator about transitions from the JIT to the VM.
2015-02-27 09:32:44 +01:00
} else {
ReportError("JIT is not enabled!");
return false;
2015-02-23 22:40:01 +01:00
}
2015-02-23 22:40:01 +01:00
/* Save our previous state. */
Implement a new stack and error handling model for the SourcePawn VM. This has three major changes to SourcePawn. First, the API now supports the concept of "exceptions". The exception state is a global property of an instance of the SourcePawn VM. Exceptions can be caught or suppressed. Many places in SourceMod have been updated to check exceptions instead of errors. The new API obsoletes major parts of the embedder API - all but one method of invoking functions is obsoleted, and the debug interface has been scrapped. Extensions using the native API will not be affected, however, ThrowNativeError has been deprecated in favor of ReportError. Second, the SourcePawn concept of a "stack" has been unified at the API level. A stack frame iterator now iterates over all SourcePawn invocations, rather than the topmost plugin. This makes error handling more consistent and removes another dependency on context-per-plugin. Finally, the implementation of stack frames has been changed dramatically. Rather than maintain a complicated and expensive return pointer stack, we now rely on the implicit one provided by the CPU. The stack frame iterator now walks the JIT stack directly. This removes many unnecessary bookkeeping instructions from the generated code, in particular making the CALL instruction 40% faster. These changes required some fair surgery to the JIT. Its error paths are now slightly more complicated, as they have to throw an exception rather than return an error code. In addition, any path that can throw an exception is now responsible for creating an "exit frame", which exists to tell the stack frame iterator about transitions from the JIT to the VM.
2015-02-27 09:32:44 +01:00
cell_t save_sp = sp_;
cell_t save_hp = hp_;
2015-02-23 22:40:01 +01:00
/* Push parameters */
sp_ -= sizeof(cell_t) * (num_params + 1);
Implement a new stack and error handling model for the SourcePawn VM. This has three major changes to SourcePawn. First, the API now supports the concept of "exceptions". The exception state is a global property of an instance of the SourcePawn VM. Exceptions can be caught or suppressed. Many places in SourceMod have been updated to check exceptions instead of errors. The new API obsoletes major parts of the embedder API - all but one method of invoking functions is obsoleted, and the debug interface has been scrapped. Extensions using the native API will not be affected, however, ThrowNativeError has been deprecated in favor of ReportError. Second, the SourcePawn concept of a "stack" has been unified at the API level. A stack frame iterator now iterates over all SourcePawn invocations, rather than the topmost plugin. This makes error handling more consistent and removes another dependency on context-per-plugin. Finally, the implementation of stack frames has been changed dramatically. Rather than maintain a complicated and expensive return pointer stack, we now rely on the implicit one provided by the CPU. The stack frame iterator now walks the JIT stack directly. This removes many unnecessary bookkeeping instructions from the generated code, in particular making the CALL instruction 40% faster. These changes required some fair surgery to the JIT. Its error paths are now slightly more complicated, as they have to throw an exception rather than return an error code. In addition, any path that can throw an exception is now responsible for creating an "exit frame", which exists to tell the stack frame iterator about transitions from the JIT to the VM.
2015-02-27 09:32:44 +01:00
cell_t *sp = (cell_t *)(memory_ + sp_);
2015-02-23 22:40:01 +01:00
sp[0] = num_params;
for (unsigned int i = 0; i < num_params; i++)
sp[i + 1] = params[i];
2015-02-24 10:12:23 +01:00
// Enter the execution engine.
Implement a new stack and error handling model for the SourcePawn VM. This has three major changes to SourcePawn. First, the API now supports the concept of "exceptions". The exception state is a global property of an instance of the SourcePawn VM. Exceptions can be caught or suppressed. Many places in SourceMod have been updated to check exceptions instead of errors. The new API obsoletes major parts of the embedder API - all but one method of invoking functions is obsoleted, and the debug interface has been scrapped. Extensions using the native API will not be affected, however, ThrowNativeError has been deprecated in favor of ReportError. Second, the SourcePawn concept of a "stack" has been unified at the API level. A stack frame iterator now iterates over all SourcePawn invocations, rather than the topmost plugin. This makes error handling more consistent and removes another dependency on context-per-plugin. Finally, the implementation of stack frames has been changed dramatically. Rather than maintain a complicated and expensive return pointer stack, we now rely on the implicit one provided by the CPU. The stack frame iterator now walks the JIT stack directly. This removes many unnecessary bookkeeping instructions from the generated code, in particular making the CALL instruction 40% faster. These changes required some fair surgery to the JIT. Its error paths are now slightly more complicated, as they have to throw an exception rather than return an error code. In addition, any path that can throw an exception is now responsible for creating an "exit frame", which exists to tell the stack frame iterator about transitions from the JIT to the VM.
2015-02-27 09:32:44 +01:00
int ir;
{
InvokeFrame ivkframe(this, fn->GetCodeOffset());
Environment *env = env_;
ir = env->Invoke(m_pRuntime, fn, result);
}
2015-02-23 22:40:01 +01:00
if (ir == SP_ERROR_NONE) {
Implement a new stack and error handling model for the SourcePawn VM. This has three major changes to SourcePawn. First, the API now supports the concept of "exceptions". The exception state is a global property of an instance of the SourcePawn VM. Exceptions can be caught or suppressed. Many places in SourceMod have been updated to check exceptions instead of errors. The new API obsoletes major parts of the embedder API - all but one method of invoking functions is obsoleted, and the debug interface has been scrapped. Extensions using the native API will not be affected, however, ThrowNativeError has been deprecated in favor of ReportError. Second, the SourcePawn concept of a "stack" has been unified at the API level. A stack frame iterator now iterates over all SourcePawn invocations, rather than the topmost plugin. This makes error handling more consistent and removes another dependency on context-per-plugin. Finally, the implementation of stack frames has been changed dramatically. Rather than maintain a complicated and expensive return pointer stack, we now rely on the implicit one provided by the CPU. The stack frame iterator now walks the JIT stack directly. This removes many unnecessary bookkeeping instructions from the generated code, in particular making the CALL instruction 40% faster. These changes required some fair surgery to the JIT. Its error paths are now slightly more complicated, as they have to throw an exception rather than return an error code. In addition, any path that can throw an exception is now responsible for creating an "exit frame", which exists to tell the stack frame iterator about transitions from the JIT to the VM.
2015-02-27 09:32:44 +01:00
// Verify that our state is still sane.
if (sp_ != save_sp) {
Implement a new stack and error handling model for the SourcePawn VM. This has three major changes to SourcePawn. First, the API now supports the concept of "exceptions". The exception state is a global property of an instance of the SourcePawn VM. Exceptions can be caught or suppressed. Many places in SourceMod have been updated to check exceptions instead of errors. The new API obsoletes major parts of the embedder API - all but one method of invoking functions is obsoleted, and the debug interface has been scrapped. Extensions using the native API will not be affected, however, ThrowNativeError has been deprecated in favor of ReportError. Second, the SourcePawn concept of a "stack" has been unified at the API level. A stack frame iterator now iterates over all SourcePawn invocations, rather than the topmost plugin. This makes error handling more consistent and removes another dependency on context-per-plugin. Finally, the implementation of stack frames has been changed dramatically. Rather than maintain a complicated and expensive return pointer stack, we now rely on the implicit one provided by the CPU. The stack frame iterator now walks the JIT stack directly. This removes many unnecessary bookkeeping instructions from the generated code, in particular making the CALL instruction 40% faster. These changes required some fair surgery to the JIT. Its error paths are now slightly more complicated, as they have to throw an exception rather than return an error code. In addition, any path that can throw an exception is now responsible for creating an "exit frame", which exists to tell the stack frame iterator about transitions from the JIT to the VM.
2015-02-27 09:32:44 +01:00
env_->ReportErrorFmt(
SP_ERROR_STACKLEAK,
"Stack leak detected: sp:%d should be %d!",
sp_,
2015-02-23 22:40:01 +01:00
save_sp);
Implement a new stack and error handling model for the SourcePawn VM. This has three major changes to SourcePawn. First, the API now supports the concept of "exceptions". The exception state is a global property of an instance of the SourcePawn VM. Exceptions can be caught or suppressed. Many places in SourceMod have been updated to check exceptions instead of errors. The new API obsoletes major parts of the embedder API - all but one method of invoking functions is obsoleted, and the debug interface has been scrapped. Extensions using the native API will not be affected, however, ThrowNativeError has been deprecated in favor of ReportError. Second, the SourcePawn concept of a "stack" has been unified at the API level. A stack frame iterator now iterates over all SourcePawn invocations, rather than the topmost plugin. This makes error handling more consistent and removes another dependency on context-per-plugin. Finally, the implementation of stack frames has been changed dramatically. Rather than maintain a complicated and expensive return pointer stack, we now rely on the implicit one provided by the CPU. The stack frame iterator now walks the JIT stack directly. This removes many unnecessary bookkeeping instructions from the generated code, in particular making the CALL instruction 40% faster. These changes required some fair surgery to the JIT. Its error paths are now slightly more complicated, as they have to throw an exception rather than return an error code. In addition, any path that can throw an exception is now responsible for creating an "exit frame", which exists to tell the stack frame iterator about transitions from the JIT to the VM.
2015-02-27 09:32:44 +01:00
return false;
2015-02-23 22:40:01 +01:00
}
if (hp_ != save_hp) {
Implement a new stack and error handling model for the SourcePawn VM. This has three major changes to SourcePawn. First, the API now supports the concept of "exceptions". The exception state is a global property of an instance of the SourcePawn VM. Exceptions can be caught or suppressed. Many places in SourceMod have been updated to check exceptions instead of errors. The new API obsoletes major parts of the embedder API - all but one method of invoking functions is obsoleted, and the debug interface has been scrapped. Extensions using the native API will not be affected, however, ThrowNativeError has been deprecated in favor of ReportError. Second, the SourcePawn concept of a "stack" has been unified at the API level. A stack frame iterator now iterates over all SourcePawn invocations, rather than the topmost plugin. This makes error handling more consistent and removes another dependency on context-per-plugin. Finally, the implementation of stack frames has been changed dramatically. Rather than maintain a complicated and expensive return pointer stack, we now rely on the implicit one provided by the CPU. The stack frame iterator now walks the JIT stack directly. This removes many unnecessary bookkeeping instructions from the generated code, in particular making the CALL instruction 40% faster. These changes required some fair surgery to the JIT. Its error paths are now slightly more complicated, as they have to throw an exception rather than return an error code. In addition, any path that can throw an exception is now responsible for creating an "exit frame", which exists to tell the stack frame iterator about transitions from the JIT to the VM.
2015-02-27 09:32:44 +01:00
env_->ReportErrorFmt(
SP_ERROR_HEAPLEAK,
"Heap leak detected: hp:%d should be %d!",
hp_,
2015-02-23 22:40:01 +01:00
save_hp);
Implement a new stack and error handling model for the SourcePawn VM. This has three major changes to SourcePawn. First, the API now supports the concept of "exceptions". The exception state is a global property of an instance of the SourcePawn VM. Exceptions can be caught or suppressed. Many places in SourceMod have been updated to check exceptions instead of errors. The new API obsoletes major parts of the embedder API - all but one method of invoking functions is obsoleted, and the debug interface has been scrapped. Extensions using the native API will not be affected, however, ThrowNativeError has been deprecated in favor of ReportError. Second, the SourcePawn concept of a "stack" has been unified at the API level. A stack frame iterator now iterates over all SourcePawn invocations, rather than the topmost plugin. This makes error handling more consistent and removes another dependency on context-per-plugin. Finally, the implementation of stack frames has been changed dramatically. Rather than maintain a complicated and expensive return pointer stack, we now rely on the implicit one provided by the CPU. The stack frame iterator now walks the JIT stack directly. This removes many unnecessary bookkeeping instructions from the generated code, in particular making the CALL instruction 40% faster. These changes required some fair surgery to the JIT. Its error paths are now slightly more complicated, as they have to throw an exception rather than return an error code. In addition, any path that can throw an exception is now responsible for creating an "exit frame", which exists to tell the stack frame iterator about transitions from the JIT to the VM.
2015-02-27 09:32:44 +01:00
return false;
2015-02-23 22:40:01 +01:00
}
}
sp_ = save_sp;
hp_ = save_hp;
Implement a new stack and error handling model for the SourcePawn VM. This has three major changes to SourcePawn. First, the API now supports the concept of "exceptions". The exception state is a global property of an instance of the SourcePawn VM. Exceptions can be caught or suppressed. Many places in SourceMod have been updated to check exceptions instead of errors. The new API obsoletes major parts of the embedder API - all but one method of invoking functions is obsoleted, and the debug interface has been scrapped. Extensions using the native API will not be affected, however, ThrowNativeError has been deprecated in favor of ReportError. Second, the SourcePawn concept of a "stack" has been unified at the API level. A stack frame iterator now iterates over all SourcePawn invocations, rather than the topmost plugin. This makes error handling more consistent and removes another dependency on context-per-plugin. Finally, the implementation of stack frames has been changed dramatically. Rather than maintain a complicated and expensive return pointer stack, we now rely on the implicit one provided by the CPU. The stack frame iterator now walks the JIT stack directly. This removes many unnecessary bookkeeping instructions from the generated code, in particular making the CALL instruction 40% faster. These changes required some fair surgery to the JIT. Its error paths are now slightly more complicated, as they have to throw an exception rather than return an error code. In addition, any path that can throw an exception is now responsible for creating an "exit frame", which exists to tell the stack frame iterator about transitions from the JIT to the VM.
2015-02-27 09:32:44 +01:00
return ir == SP_ERROR_NONE;
2015-02-23 22:40:01 +01:00
}
IPluginRuntime *
2015-02-24 21:50:09 +01:00
PluginContext::GetRuntime()
2015-02-23 22:40:01 +01:00
{
return m_pRuntime;
}
2015-02-23 22:40:01 +01:00
int
2015-02-24 21:50:09 +01:00
PluginContext::GetLastNativeError()
{
Implement a new stack and error handling model for the SourcePawn VM. This has three major changes to SourcePawn. First, the API now supports the concept of "exceptions". The exception state is a global property of an instance of the SourcePawn VM. Exceptions can be caught or suppressed. Many places in SourceMod have been updated to check exceptions instead of errors. The new API obsoletes major parts of the embedder API - all but one method of invoking functions is obsoleted, and the debug interface has been scrapped. Extensions using the native API will not be affected, however, ThrowNativeError has been deprecated in favor of ReportError. Second, the SourcePawn concept of a "stack" has been unified at the API level. A stack frame iterator now iterates over all SourcePawn invocations, rather than the topmost plugin. This makes error handling more consistent and removes another dependency on context-per-plugin. Finally, the implementation of stack frames has been changed dramatically. Rather than maintain a complicated and expensive return pointer stack, we now rely on the implicit one provided by the CPU. The stack frame iterator now walks the JIT stack directly. This removes many unnecessary bookkeeping instructions from the generated code, in particular making the CALL instruction 40% faster. These changes required some fair surgery to the JIT. Its error paths are now slightly more complicated, as they have to throw an exception rather than return an error code. In addition, any path that can throw an exception is now responsible for creating an "exit frame", which exists to tell the stack frame iterator about transitions from the JIT to the VM.
2015-02-27 09:32:44 +01:00
Environment *env = env_;
if (!env->hasPendingException())
return SP_ERROR_NONE;
return env->getPendingExceptionCode();
}
2015-02-23 22:40:01 +01:00
cell_t *
2015-02-24 21:50:09 +01:00
PluginContext::GetLocalParams()
{
return (cell_t *)(memory_ + frm_ + (2 * sizeof(cell_t)));
}
2015-02-23 22:40:01 +01:00
void
2015-02-24 21:50:09 +01:00
PluginContext::SetKey(int k, void *value)
{
2015-02-23 22:40:01 +01:00
if (k < 1 || k > 4)
return;
2015-02-23 22:40:01 +01:00
m_keys[k - 1] = value;
m_keys_set[k - 1] = true;
}
2015-02-23 22:40:01 +01:00
bool
2015-02-24 21:50:09 +01:00
PluginContext::GetKey(int k, void **value)
{
2015-02-23 22:40:01 +01:00
if (k < 1 || k > 4 || m_keys_set[k - 1] == false)
return false;
2015-02-23 22:40:01 +01:00
*value = m_keys[k - 1];
return true;
}
2015-02-23 22:40:01 +01:00
void
2015-02-24 21:50:09 +01:00
PluginContext::ClearLastNativeError()
{
Implement a new stack and error handling model for the SourcePawn VM. This has three major changes to SourcePawn. First, the API now supports the concept of "exceptions". The exception state is a global property of an instance of the SourcePawn VM. Exceptions can be caught or suppressed. Many places in SourceMod have been updated to check exceptions instead of errors. The new API obsoletes major parts of the embedder API - all but one method of invoking functions is obsoleted, and the debug interface has been scrapped. Extensions using the native API will not be affected, however, ThrowNativeError has been deprecated in favor of ReportError. Second, the SourcePawn concept of a "stack" has been unified at the API level. A stack frame iterator now iterates over all SourcePawn invocations, rather than the topmost plugin. This makes error handling more consistent and removes another dependency on context-per-plugin. Finally, the implementation of stack frames has been changed dramatically. Rather than maintain a complicated and expensive return pointer stack, we now rely on the implicit one provided by the CPU. The stack frame iterator now walks the JIT stack directly. This removes many unnecessary bookkeeping instructions from the generated code, in particular making the CALL instruction 40% faster. These changes required some fair surgery to the JIT. Its error paths are now slightly more complicated, as they have to throw an exception rather than return an error code. In addition, any path that can throw an exception is now responsible for creating an "exit frame", which exists to tell the stack frame iterator about transitions from the JIT to the VM.
2015-02-27 09:32:44 +01:00
if (env_->hasPendingException())
env_->clearPendingException();
}
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_ - 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_;
const sp_native_t *native = m_pRuntime->GetNative(native_idx);
if (native->status == SP_NATIVE_UNBOUND) {
Implement a new stack and error handling model for the SourcePawn VM. This has three major changes to SourcePawn. First, the API now supports the concept of "exceptions". The exception state is a global property of an instance of the SourcePawn VM. Exceptions can be caught or suppressed. Many places in SourceMod have been updated to check exceptions instead of errors. The new API obsoletes major parts of the embedder API - all but one method of invoking functions is obsoleted, and the debug interface has been scrapped. Extensions using the native API will not be affected, however, ThrowNativeError has been deprecated in favor of ReportError. Second, the SourcePawn concept of a "stack" has been unified at the API level. A stack frame iterator now iterates over all SourcePawn invocations, rather than the topmost plugin. This makes error handling more consistent and removes another dependency on context-per-plugin. Finally, the implementation of stack frames has been changed dramatically. Rather than maintain a complicated and expensive return pointer stack, we now rely on the implicit one provided by the CPU. The stack frame iterator now walks the JIT stack directly. This removes many unnecessary bookkeeping instructions from the generated code, in particular making the CALL instruction 40% faster. These changes required some fair surgery to the JIT. Its error paths are now slightly more complicated, as they have to throw an exception rather than return an error code. In addition, any path that can throw an exception is now responsible for creating an "exit frame", which exists to tell the stack frame iterator about transitions from the JIT to the VM.
2015-02-27 09:32:44 +01:00
ReportErrorNumber(SP_ERROR_INVALID_NATIVE);
return 0;
}
2015-02-25 06:19:29 +01:00
cell_t result = native->pfn(this, params);
if (save_sp != sp_) {
Implement a new stack and error handling model for the SourcePawn VM. This has three major changes to SourcePawn. First, the API now supports the concept of "exceptions". The exception state is a global property of an instance of the SourcePawn VM. Exceptions can be caught or suppressed. Many places in SourceMod have been updated to check exceptions instead of errors. The new API obsoletes major parts of the embedder API - all but one method of invoking functions is obsoleted, and the debug interface has been scrapped. Extensions using the native API will not be affected, however, ThrowNativeError has been deprecated in favor of ReportError. Second, the SourcePawn concept of a "stack" has been unified at the API level. A stack frame iterator now iterates over all SourcePawn invocations, rather than the topmost plugin. This makes error handling more consistent and removes another dependency on context-per-plugin. Finally, the implementation of stack frames has been changed dramatically. Rather than maintain a complicated and expensive return pointer stack, we now rely on the implicit one provided by the CPU. The stack frame iterator now walks the JIT stack directly. This removes many unnecessary bookkeeping instructions from the generated code, in particular making the CALL instruction 40% faster. These changes required some fair surgery to the JIT. Its error paths are now slightly more complicated, as they have to throw an exception rather than return an error code. In addition, any path that can throw an exception is now responsible for creating an "exit frame", which exists to tell the stack frame iterator about transitions from the JIT to the VM.
2015-02-27 09:32:44 +01:00
if (!env_->hasPendingException())
ReportErrorNumber(SP_ERROR_STACKLEAK);
return 0;
}
if (save_hp != hp_) {
Implement a new stack and error handling model for the SourcePawn VM. This has three major changes to SourcePawn. First, the API now supports the concept of "exceptions". The exception state is a global property of an instance of the SourcePawn VM. Exceptions can be caught or suppressed. Many places in SourceMod have been updated to check exceptions instead of errors. The new API obsoletes major parts of the embedder API - all but one method of invoking functions is obsoleted, and the debug interface has been scrapped. Extensions using the native API will not be affected, however, ThrowNativeError has been deprecated in favor of ReportError. Second, the SourcePawn concept of a "stack" has been unified at the API level. A stack frame iterator now iterates over all SourcePawn invocations, rather than the topmost plugin. This makes error handling more consistent and removes another dependency on context-per-plugin. Finally, the implementation of stack frames has been changed dramatically. Rather than maintain a complicated and expensive return pointer stack, we now rely on the implicit one provided by the CPU. The stack frame iterator now walks the JIT stack directly. This removes many unnecessary bookkeeping instructions from the generated code, in particular making the CALL instruction 40% faster. These changes required some fair surgery to the JIT. Its error paths are now slightly more complicated, as they have to throw an exception rather than return an error code. In addition, any path that can throw an exception is now responsible for creating an "exit frame", which exists to tell the stack frame iterator about transitions from the JIT to the VM.
2015-02-27 09:32:44 +01:00
if (!env_->hasPendingException())
ReportErrorNumber(SP_ERROR_HEAPLEAK);
return 0;
}
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 (save_sp != sp_) {
Implement a new stack and error handling model for the SourcePawn VM. This has three major changes to SourcePawn. First, the API now supports the concept of "exceptions". The exception state is a global property of an instance of the SourcePawn VM. Exceptions can be caught or suppressed. Many places in SourceMod have been updated to check exceptions instead of errors. The new API obsoletes major parts of the embedder API - all but one method of invoking functions is obsoleted, and the debug interface has been scrapped. Extensions using the native API will not be affected, however, ThrowNativeError has been deprecated in favor of ReportError. Second, the SourcePawn concept of a "stack" has been unified at the API level. A stack frame iterator now iterates over all SourcePawn invocations, rather than the topmost plugin. This makes error handling more consistent and removes another dependency on context-per-plugin. Finally, the implementation of stack frames has been changed dramatically. Rather than maintain a complicated and expensive return pointer stack, we now rely on the implicit one provided by the CPU. The stack frame iterator now walks the JIT stack directly. This removes many unnecessary bookkeeping instructions from the generated code, in particular making the CALL instruction 40% faster. These changes required some fair surgery to the JIT. Its error paths are now slightly more complicated, as they have to throw an exception rather than return an error code. In addition, any path that can throw an exception is now responsible for creating an "exit frame", which exists to tell the stack frame iterator about transitions from the JIT to the VM.
2015-02-27 09:32:44 +01:00
if (!env_->hasPendingException())
ReportErrorNumber(SP_ERROR_STACKLEAK);
return result;
}
if (save_hp != hp_) {
Implement a new stack and error handling model for the SourcePawn VM. This has three major changes to SourcePawn. First, the API now supports the concept of "exceptions". The exception state is a global property of an instance of the SourcePawn VM. Exceptions can be caught or suppressed. Many places in SourceMod have been updated to check exceptions instead of errors. The new API obsoletes major parts of the embedder API - all but one method of invoking functions is obsoleted, and the debug interface has been scrapped. Extensions using the native API will not be affected, however, ThrowNativeError has been deprecated in favor of ReportError. Second, the SourcePawn concept of a "stack" has been unified at the API level. A stack frame iterator now iterates over all SourcePawn invocations, rather than the topmost plugin. This makes error handling more consistent and removes another dependency on context-per-plugin. Finally, the implementation of stack frames has been changed dramatically. Rather than maintain a complicated and expensive return pointer stack, we now rely on the implicit one provided by the CPU. The stack frame iterator now walks the JIT stack directly. This removes many unnecessary bookkeeping instructions from the generated code, in particular making the CALL instruction 40% faster. These changes required some fair surgery to the JIT. Its error paths are now slightly more complicated, as they have to throw an exception rather than return an error code. In addition, any path that can throw an exception is now responsible for creating an "exit frame", which exists to tell the stack frame iterator about transitions from the JIT to the VM.
2015-02-27 09:32:44 +01:00
if (!env_->hasPendingException())
ReportErrorNumber(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 *>(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 *>(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(memory_ + hp_) >= uintptr_t(stk))
return SP_ERROR_HEAPLOW;
if (int err = pushTracker(bytes))
return err;
if (autozero)
memset(memory_ + hp_, 0, bytes);
return SP_ERROR_NONE;
}
if (int err = generateFullArray(dims, stk, autozero))
return err;
return SP_ERROR_NONE;
}
Implement a new stack and error handling model for the SourcePawn VM. This has three major changes to SourcePawn. First, the API now supports the concept of "exceptions". The exception state is a global property of an instance of the SourcePawn VM. Exceptions can be caught or suppressed. Many places in SourceMod have been updated to check exceptions instead of errors. The new API obsoletes major parts of the embedder API - all but one method of invoking functions is obsoleted, and the debug interface has been scrapped. Extensions using the native API will not be affected, however, ThrowNativeError has been deprecated in favor of ReportError. Second, the SourcePawn concept of a "stack" has been unified at the API level. A stack frame iterator now iterates over all SourcePawn invocations, rather than the topmost plugin. This makes error handling more consistent and removes another dependency on context-per-plugin. Finally, the implementation of stack frames has been changed dramatically. Rather than maintain a complicated and expensive return pointer stack, we now rely on the implicit one provided by the CPU. The stack frame iterator now walks the JIT stack directly. This removes many unnecessary bookkeeping instructions from the generated code, in particular making the CALL instruction 40% faster. These changes required some fair surgery to the JIT. Its error paths are now slightly more complicated, as they have to throw an exception rather than return an error code. In addition, any path that can throw an exception is now responsible for creating an "exit frame", which exists to tell the stack frame iterator about transitions from the JIT to the VM.
2015-02-27 09:32:44 +01:00
ISourcePawnEngine2 *
PluginContext::APIv2()
{
return env_->APIv2();
}
void
PluginContext::ReportError(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
env_->ReportErrorVA(fmt, ap);
va_end(ap);
}
void
PluginContext::ReportErrorVA(const char *fmt, va_list ap)
{
env_->ReportErrorVA(fmt, ap);
}
void
PluginContext::ReportFatalError(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
env_->ReportErrorVA(SP_ERROR_FATAL, fmt, ap);
va_end(ap);
}
void
PluginContext::ReportFatalErrorVA(const char *fmt, va_list ap)
{
env_->ReportErrorVA(SP_ERROR_FATAL, fmt, ap);
}
void
PluginContext::ReportErrorNumber(int error)
{
env_->ReportError(error);
}