Refactor the JIT to use a newer, simpler macro assembler. (bug 5827, r=ann)
This commit is contained in:
parent
ad543c909c
commit
9e56725406
294
public/jit/assembler.h
Normal file
294
public/jit/assembler.h
Normal file
@ -0,0 +1,294 @@
|
||||
/**
|
||||
* vim: set ts=8 sts=2 sw=2 tw=99 et:
|
||||
* =============================================================================
|
||||
* SourcePawn JIT SDK
|
||||
* Copyright (C) 2004-2013 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
#ifndef _include_sourcepawn_assembler_h__
|
||||
#define _include_sourcepawn_assembler_h__
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <limits.h>
|
||||
|
||||
class Assembler
|
||||
{
|
||||
public:
|
||||
static const size_t kMinBufferSize = 4096;
|
||||
static const size_t kMaxInstructionSize = 32;
|
||||
static const size_t kMaxBufferSize = INT_MAX / 2;
|
||||
|
||||
public:
|
||||
Assembler() {
|
||||
buffer_ = (uint8_t *)malloc(kMinBufferSize);
|
||||
pos_ = buffer_;
|
||||
end_ = buffer_ + kMinBufferSize;
|
||||
outOfMemory_ = !buffer_;
|
||||
}
|
||||
~Assembler() {
|
||||
free(buffer_);
|
||||
}
|
||||
|
||||
bool outOfMemory() const {
|
||||
return outOfMemory_;
|
||||
}
|
||||
|
||||
// Amount needed to allocate for executable code.
|
||||
size_t length() const {
|
||||
return pos_ - buffer_;
|
||||
}
|
||||
|
||||
protected:
|
||||
void writeByte(uint8_t byte) {
|
||||
write<uint8_t>(byte);
|
||||
}
|
||||
void writeInt32(int32_t word) {
|
||||
write<int32_t>(word);
|
||||
}
|
||||
void writeUint32(uint32_t word) {
|
||||
write<uint32_t>(word);
|
||||
}
|
||||
void writePointer(void *ptr) {
|
||||
write<void *>(ptr);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void write(const T &t) {
|
||||
assertCanWrite(sizeof(T));
|
||||
*reinterpret_cast<T *>(pos_) = t;
|
||||
pos_ += sizeof(T);
|
||||
}
|
||||
|
||||
// Normally this does not need to be checked, but it must be called before
|
||||
// emitting any instruction.
|
||||
bool ensureSpace() {
|
||||
if (pos_ + kMaxInstructionSize <= end_)
|
||||
return true;
|
||||
|
||||
if (outOfMemory())
|
||||
return false;
|
||||
|
||||
size_t oldlength = size_t(end_ - buffer_);
|
||||
|
||||
if (oldlength * 2 > kMaxBufferSize) {
|
||||
// See comment when if realloc() fails.
|
||||
pos_ = buffer_;
|
||||
outOfMemory_ = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t oldpos = size_t(pos_ - buffer_);
|
||||
uint8_t *newbuf = (uint8_t *)realloc(buffer_, oldlength * 2);
|
||||
if (!newbuf) {
|
||||
// Writes will be safe, though we'll corrupt the instruction stream, so
|
||||
// actually using the buffer will be invalid and compilation should be
|
||||
// aborted when possible.
|
||||
pos_ = buffer_;
|
||||
outOfMemory_ = true;
|
||||
return false;
|
||||
}
|
||||
buffer_ = newbuf;
|
||||
end_ = newbuf + oldlength * 2;
|
||||
pos_ = buffer_ + oldpos;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Position will never be negative, but it's nice to have signed results
|
||||
// for relative address calculation.
|
||||
int32_t position() const {
|
||||
return int32_t(pos_ - buffer_);
|
||||
}
|
||||
|
||||
// pc is the unsigned version of position().
|
||||
uint32_t pc() const {
|
||||
return uint32_t(pos_ - buffer_);
|
||||
}
|
||||
|
||||
protected:
|
||||
void assertCanWrite(size_t bytes) {
|
||||
assert(pos_ + bytes <= end_);
|
||||
}
|
||||
uint8_t *buffer() const {
|
||||
return buffer_;
|
||||
}
|
||||
|
||||
private:
|
||||
uint8_t *buffer_;
|
||||
uint8_t *end_;
|
||||
|
||||
protected:
|
||||
uint8_t *pos_;
|
||||
bool outOfMemory_;
|
||||
};
|
||||
|
||||
class ExternalAddress
|
||||
{
|
||||
public:
|
||||
explicit ExternalAddress(void *p)
|
||||
: p_(p)
|
||||
{
|
||||
}
|
||||
|
||||
void *address() const {
|
||||
return p_;
|
||||
}
|
||||
uintptr_t value() const {
|
||||
return uintptr_t(p_);
|
||||
}
|
||||
|
||||
private:
|
||||
void *p_;
|
||||
};
|
||||
|
||||
// A label is a lightweight object to assist in managing relative jumps. It
|
||||
// exists in three states:
|
||||
// * Unbound, Unused: The label has no incoming jumps, and its position has
|
||||
// not yet been fixed in the instruction stream.
|
||||
// * Unbound, Used: The label has not yet been fixed at a position in the
|
||||
// instruction stream, but it has incoming jumps.
|
||||
// * Bound: The label has been fixed at a position in the instruction stream.
|
||||
//
|
||||
// When a label is unbound and used, the offset stored in the Label is a linked
|
||||
// list threaded through each individual jump. When the label is bound, each
|
||||
// jump instruction in this list is immediately patched with the correctly
|
||||
// computed relative distance to the label.
|
||||
//
|
||||
// We keep sizeof(Label) == 4 to make it embeddable within code streams if
|
||||
// need be (for example, SourcePawn mirrors the source code to maintain jump
|
||||
// maps).
|
||||
class Label
|
||||
{
|
||||
// If set on status_, the label is bound.
|
||||
static const int32_t kBound = (1 << 0);
|
||||
|
||||
public:
|
||||
Label()
|
||||
: status_(0)
|
||||
{
|
||||
}
|
||||
~Label()
|
||||
{
|
||||
assert(!used() || bound());
|
||||
}
|
||||
|
||||
static inline bool More(uint32_t status) {
|
||||
return status != 0;
|
||||
}
|
||||
static inline uint32_t ToOffset(uint32_t status) {
|
||||
return status >> 1;
|
||||
}
|
||||
|
||||
bool used() const {
|
||||
return bound() || !!(status_ >> 1);
|
||||
}
|
||||
bool bound() const {
|
||||
return !!(status_ & kBound);
|
||||
}
|
||||
uint32_t offset() const {
|
||||
assert(bound());
|
||||
return ToOffset(status_);
|
||||
}
|
||||
uint32_t status() const {
|
||||
assert(!bound());
|
||||
return status_;
|
||||
}
|
||||
uint32_t addPending(uint32_t pc) {
|
||||
assert(pc <= INT_MAX / 2);
|
||||
uint32_t prev = status_;
|
||||
status_ = pc << 1;
|
||||
return prev;
|
||||
}
|
||||
void bind(uint32_t offset) {
|
||||
assert(!bound());
|
||||
status_ = (offset << 1) | kBound;
|
||||
assert(this->offset() == offset);
|
||||
}
|
||||
|
||||
private:
|
||||
// Note that 0 as an invalid offset is okay, because the offset we save for
|
||||
// pending jumps are after the jump opcode itself, and therefore 0 is never
|
||||
// valid, since there are no 0-byte jumps.
|
||||
uint32_t status_;
|
||||
};
|
||||
|
||||
// A DataLabel is a special form of Label intended for absolute addresses that
|
||||
// are within the code buffer, and thus aren't known yet, and will be
|
||||
// automatically fixed up when calling emitToExecutableMemory().
|
||||
//
|
||||
// Unlike normal Labels, these do not store a list of incoming uses.
|
||||
class DataLabel
|
||||
{
|
||||
// If set on status_, the label is bound.
|
||||
static const int32_t kBound = (1 << 0);
|
||||
|
||||
public:
|
||||
DataLabel()
|
||||
: status_(0)
|
||||
{
|
||||
}
|
||||
~DataLabel()
|
||||
{
|
||||
assert(!used() || bound());
|
||||
}
|
||||
|
||||
static inline uint32_t ToOffset(uint32_t status) {
|
||||
return status >> 1;
|
||||
}
|
||||
|
||||
bool used() const {
|
||||
return bound() || !!(status_ >> 1);
|
||||
}
|
||||
bool bound() const {
|
||||
return !!(status_ & kBound);
|
||||
}
|
||||
uint32_t offset() const {
|
||||
assert(bound());
|
||||
return ToOffset(status_);
|
||||
}
|
||||
uint32_t status() const {
|
||||
assert(!bound());
|
||||
return status_;
|
||||
}
|
||||
void use(uint32_t pc) {
|
||||
assert(!used());
|
||||
status_ = (pc << 1);
|
||||
assert(ToOffset(status_) == pc);
|
||||
}
|
||||
void bind(uint32_t offset) {
|
||||
assert(!bound());
|
||||
status_ = (offset << 1) | kBound;
|
||||
assert(this->offset() == offset);
|
||||
}
|
||||
|
||||
private:
|
||||
uint32_t status_;
|
||||
};
|
||||
|
||||
#endif // _include_sourcepawn_assembler_h__
|
||||
|
842
public/jit/x86/assembler-x86.h
Normal file
842
public/jit/x86/assembler-x86.h
Normal file
@ -0,0 +1,842 @@
|
||||
/**
|
||||
* vim: set ts=8 sts=2 sw=2 tw=99 et:
|
||||
* =============================================================================
|
||||
* SourcePawn JIT SDK
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
#ifndef _include_sourcepawn_assembler_x86_h__
|
||||
#define _include_sourcepawn_assembler_x86_h__
|
||||
|
||||
#include <assembler.h>
|
||||
#include <ke_vector.h>
|
||||
#include <string.h>
|
||||
|
||||
struct Register
|
||||
{
|
||||
const char *name() const {
|
||||
static const char *names[] = {
|
||||
"eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi"
|
||||
};
|
||||
return names[code];
|
||||
}
|
||||
|
||||
int code;
|
||||
|
||||
bool operator == (const Register &other) const {
|
||||
return code == other.code;
|
||||
}
|
||||
bool operator != (const Register &other) const {
|
||||
return code != other.code;
|
||||
}
|
||||
};
|
||||
|
||||
// X86 has an ancient FPU (called x87) which has a stack of registers
|
||||
// numbered st0 through st7.
|
||||
struct FpuRegister
|
||||
{
|
||||
const char *name() const {
|
||||
static const char *names[] = {
|
||||
"st0", "st1", "st2", "st3", "st4", "st5", "st6", "st7"
|
||||
};
|
||||
return names[code];
|
||||
}
|
||||
|
||||
int code;
|
||||
|
||||
bool operator == (const FpuRegister &other) const {
|
||||
return code == other.code;
|
||||
}
|
||||
bool operator != (const FpuRegister &other) const {
|
||||
return code != other.code;
|
||||
}
|
||||
};
|
||||
|
||||
struct FloatRegister
|
||||
{
|
||||
const char *name() const {
|
||||
static const char *names[] = {
|
||||
"xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7"
|
||||
};
|
||||
return names[code];
|
||||
}
|
||||
|
||||
int code;
|
||||
|
||||
bool operator == (const FloatRegister &other) const {
|
||||
return code == other.code;
|
||||
}
|
||||
bool operator != (const FloatRegister &other) const {
|
||||
return code != other.code;
|
||||
}
|
||||
};
|
||||
|
||||
const Register eax = { 0 };
|
||||
const Register ecx = { 1 };
|
||||
const Register edx = { 2 };
|
||||
const Register ebx = { 3 };
|
||||
const Register esp = { 4 };
|
||||
const Register ebp = { 5 };
|
||||
const Register esi = { 6 };
|
||||
const Register edi = { 7 };
|
||||
|
||||
const Register r8_al = { 0 };
|
||||
const Register r8_cl = { 1 };
|
||||
const Register r8_dl = { 2 };
|
||||
const Register r8_bl = { 3 };
|
||||
const Register r8_ah = { 4 };
|
||||
const Register r8_ch = { 5 };
|
||||
const Register r8_dh = { 6 };
|
||||
const Register r8_bh = { 7 };
|
||||
|
||||
const FpuRegister st0 = { 0 };
|
||||
const FpuRegister st1 = { 1 };
|
||||
const FpuRegister st2 = { 2 };
|
||||
const FpuRegister st3 = { 3 };
|
||||
const FpuRegister st4 = { 4 };
|
||||
const FpuRegister st5 = { 5 };
|
||||
const FpuRegister st6 = { 6 };
|
||||
const FpuRegister st7 = { 7 };
|
||||
|
||||
const FloatRegister xmm0 = { 0 };
|
||||
const FloatRegister xmm1 = { 1 };
|
||||
const FloatRegister xmm2 = { 2 };
|
||||
const FloatRegister xmm3 = { 3 };
|
||||
const FloatRegister xmm4 = { 4 };
|
||||
const FloatRegister xmm5 = { 5 };
|
||||
const FloatRegister xmm6 = { 6 };
|
||||
const FloatRegister xmm7 = { 7 };
|
||||
|
||||
static const uint8_t kModeDisp0 = 0;
|
||||
static const uint8_t kModeDisp8 = 1;
|
||||
static const uint8_t kModeDisp32 = 2;
|
||||
static const uint8_t kModeReg = 3;
|
||||
static const uint8_t kNoIndex = 4;
|
||||
static const uint8_t kSIB = 4;
|
||||
static const uint8_t kRIP = 5;
|
||||
|
||||
enum ConditionCode {
|
||||
overflow,
|
||||
no_overflow,
|
||||
below,
|
||||
not_below,
|
||||
equal,
|
||||
not_equal,
|
||||
not_above,
|
||||
above,
|
||||
negative,
|
||||
not_negative,
|
||||
even_parity,
|
||||
odd_parity,
|
||||
less,
|
||||
not_less,
|
||||
not_greater,
|
||||
greater,
|
||||
|
||||
zero = equal,
|
||||
not_zero = not_equal,
|
||||
less_equal = not_greater,
|
||||
greater_equal = not_less
|
||||
};
|
||||
|
||||
enum Scale {
|
||||
NoScale,
|
||||
ScaleTwo,
|
||||
ScaleFour,
|
||||
ScaleEight,
|
||||
ScalePointer = ScaleFour
|
||||
};
|
||||
|
||||
struct Operand
|
||||
{
|
||||
friend class AssemblerX86;
|
||||
|
||||
public:
|
||||
Operand(Register reg, int32_t disp) {
|
||||
if (reg == esp) {
|
||||
// If the reg is esp, we need a SIB encoding.
|
||||
if (disp == 0)
|
||||
sib_disp0(NoScale, kNoIndex, reg.code);
|
||||
else if (disp >= SCHAR_MIN && disp <= SCHAR_MAX)
|
||||
sib_disp8(NoScale, kNoIndex, reg.code, disp);
|
||||
else
|
||||
sib_disp32(NoScale, kNoIndex, reg.code, disp);
|
||||
} else if (disp == 0 && reg != ebp) {
|
||||
// note, [ebp+0] is disp32/rip
|
||||
modrm_disp0(reg.code);
|
||||
} else if (disp >= SCHAR_MIN && disp <= SCHAR_MAX) {
|
||||
modrm_disp8(reg.code, disp);
|
||||
} else {
|
||||
modrm_disp32(reg.code, disp);
|
||||
}
|
||||
}
|
||||
|
||||
Operand(Register base, Scale scale, int32_t disp = 0) {
|
||||
if (disp == 0 && base != ebp)
|
||||
sib_disp0(scale, kNoIndex, base.code);
|
||||
else if (disp >= SCHAR_MIN && disp <= SCHAR_MAX)
|
||||
sib_disp8(scale, kNoIndex, base.code, disp);
|
||||
else
|
||||
sib_disp32(scale, kNoIndex, base.code, disp);
|
||||
}
|
||||
|
||||
Operand(Register base, Register index, Scale scale, int32_t disp = 0) {
|
||||
assert(index.code != kNoIndex);
|
||||
if (disp == 0 && base != ebp)
|
||||
sib_disp0(scale, index.code, base.code);
|
||||
else if (disp >= SCHAR_MIN && disp <= SCHAR_MAX)
|
||||
sib_disp8(scale, index.code, base.code, disp);
|
||||
else
|
||||
sib_disp32(scale, index.code, base.code, disp);
|
||||
}
|
||||
|
||||
explicit Operand(ExternalAddress address) {
|
||||
modrm(kModeDisp0, kRIP);
|
||||
*reinterpret_cast<const void **>(bytes_ + 1) = address.address();
|
||||
}
|
||||
|
||||
bool isRegister() const {
|
||||
return mode() == kModeReg;
|
||||
}
|
||||
bool isRegister(Register r) const {
|
||||
return mode() == kModeReg && rm() == r.code;
|
||||
}
|
||||
int registerCode() const {
|
||||
return rm();
|
||||
}
|
||||
|
||||
uint8_t getByte(size_t index) const {
|
||||
assert(index < length());
|
||||
return bytes_[index];
|
||||
}
|
||||
|
||||
size_t length() const {
|
||||
if (mode() == kModeDisp0 && rm() == kRIP)
|
||||
return 5;
|
||||
size_t sib = (mode() != kModeReg && rm() == kSIB);
|
||||
if (mode() == kModeDisp32)
|
||||
return 5 + sib;
|
||||
if (mode() == kModeDisp8)
|
||||
return 2 + sib;
|
||||
return 1 + sib;
|
||||
}
|
||||
|
||||
private:
|
||||
explicit Operand(Register reg) {
|
||||
modrm(kModeReg, reg.code);
|
||||
}
|
||||
|
||||
void modrm(uint8_t mode, uint8_t rm) {
|
||||
assert(mode <= 3);
|
||||
assert(rm <= 7);
|
||||
bytes_[0] = (mode << 6) | rm;
|
||||
}
|
||||
void modrm_disp0(uint8_t rm) {
|
||||
modrm(kModeDisp0, rm);
|
||||
}
|
||||
void modrm_disp8(uint8_t rm, int8_t disp) {
|
||||
modrm(kModeDisp8, rm);
|
||||
bytes_[1] = disp;
|
||||
}
|
||||
void modrm_disp32(uint8_t rm, int32_t disp) {
|
||||
modrm(kModeDisp32, rm);
|
||||
*reinterpret_cast<int32_t *>(bytes_ + 1) = disp;
|
||||
}
|
||||
void sib(uint8_t mode, Scale scale, uint8_t index, uint8_t base) {
|
||||
modrm(mode, kSIB);
|
||||
|
||||
assert(scale <= 3);
|
||||
assert(index <= 7);
|
||||
assert(base <= 7);
|
||||
bytes_[1] = (uint8_t(scale) << 6) | (index << 3) | base;
|
||||
}
|
||||
void sib_disp0(Scale scale, uint8_t index, uint8_t base) {
|
||||
sib(kModeDisp0, scale, index, base);
|
||||
}
|
||||
void sib_disp8(Scale scale, uint8_t index, uint8_t base, int8_t disp) {
|
||||
sib(kModeDisp8, scale, index, base);
|
||||
bytes_[2] = disp;
|
||||
}
|
||||
void sib_disp32(Scale scale, uint8_t index, uint8_t base, int32_t disp) {
|
||||
sib(kModeDisp32, scale, index, base);
|
||||
*reinterpret_cast<int32_t *>(bytes_ + 2) = disp;
|
||||
}
|
||||
|
||||
private:
|
||||
uint8_t rm() const {
|
||||
return bytes_[0] & 7;
|
||||
}
|
||||
uint8_t mode() const {
|
||||
return bytes_[0] >> 6;
|
||||
}
|
||||
|
||||
private:
|
||||
uint8_t bytes_[6];
|
||||
};
|
||||
|
||||
class AssemblerX86 : public Assembler
|
||||
{
|
||||
public:
|
||||
void movl(Register dest, Register src) {
|
||||
emit1(0x89, src.code, dest.code);
|
||||
}
|
||||
void movl(Register dest, const Operand &src) {
|
||||
emit1(0x8b, dest.code, src);
|
||||
}
|
||||
void movl(const Operand &dest, Register src) {
|
||||
emit1(0x89, src.code, dest);
|
||||
}
|
||||
void movl(Register dest, int32_t imm) {
|
||||
emit1(0xb8 + dest.code);
|
||||
writeInt32(imm);
|
||||
}
|
||||
void movl(const Operand &dest, int32_t imm) {
|
||||
if (dest.isRegister())
|
||||
emit1(0xb8 + dest.registerCode());
|
||||
else
|
||||
emit1(0xc7, 0, dest);
|
||||
writeInt32(imm);
|
||||
}
|
||||
void movw(const Operand &dest, Register src) {
|
||||
emit1(0x89, src.code, dest);
|
||||
}
|
||||
void movw(Register dest, const Operand &src) {
|
||||
emit1(0x8b, dest.code, src);
|
||||
}
|
||||
void movb(const Operand &dest, Register src) {
|
||||
emit1(0x88, src.code, dest);
|
||||
}
|
||||
void movb(Register dest, const Operand &src) {
|
||||
emit1(0x8a, dest.code, src);
|
||||
}
|
||||
void movzxb(Register dest, const Operand &src) {
|
||||
emit2(0x0f, 0xb6, dest.code, src);
|
||||
}
|
||||
void movzxb(Register dest, const Register src) {
|
||||
emit2(0x0f, 0xb6, dest.code, src.code);
|
||||
}
|
||||
void movzxw(Register dest, const Operand &src) {
|
||||
emit2(0x0f, 0xb7, dest.code, src);
|
||||
}
|
||||
void movzxw(Register dest, const Register src) {
|
||||
emit2(0x0f, 0xb7, dest.code, src.code);
|
||||
}
|
||||
|
||||
void lea(Register dest, const Operand &src) {
|
||||
emit1(0x8d, dest.code, src);
|
||||
}
|
||||
|
||||
void xchgl(Register dest, Register src) {
|
||||
if (src == eax)
|
||||
emit1(0x90 + dest.code);
|
||||
else if (dest == eax)
|
||||
emit1(0x90 + src.code);
|
||||
else
|
||||
emit1(0x87, src.code, dest.code);
|
||||
}
|
||||
|
||||
void shll_cl(Register dest) {
|
||||
shift_cl(dest.code, 4);
|
||||
}
|
||||
void shll(Register dest, uint8_t imm) {
|
||||
shift_imm(dest.code, 4, imm);
|
||||
}
|
||||
void shll(const Operand &dest, uint8_t imm) {
|
||||
shift_imm(dest, 4, imm);
|
||||
}
|
||||
void shrl_cl(Register dest) {
|
||||
shift_cl(dest.code, 5);
|
||||
}
|
||||
void shrl(Register dest, uint8_t imm) {
|
||||
shift_imm(dest.code, 5, imm);
|
||||
}
|
||||
void shrl(const Operand &dest, uint8_t imm) {
|
||||
shift_imm(dest, 5, imm);
|
||||
}
|
||||
void sarl_cl(Register dest) {
|
||||
shift_cl(dest.code, 7);
|
||||
}
|
||||
void sarl(Register dest, uint8_t imm) {
|
||||
shift_imm(dest.code, 7, imm);
|
||||
}
|
||||
void sarl(const Operand &dest, uint8_t imm) {
|
||||
shift_imm(dest, 7, imm);
|
||||
}
|
||||
|
||||
void cmpl(Register left, int32_t imm) {
|
||||
alu_imm(7, imm, Operand(left));
|
||||
}
|
||||
void cmpl(const Operand &left, int32_t imm) {
|
||||
alu_imm(7, imm, left);
|
||||
}
|
||||
void cmpl(Register left, Register right) {
|
||||
emit1(0x39, right.code, left.code);
|
||||
}
|
||||
void cmpl(const Operand &left, Register right) {
|
||||
emit1(0x39, right.code, left);
|
||||
}
|
||||
void cmpl(Register left, const Operand &right) {
|
||||
emit1(0x3b, left.code, right);
|
||||
}
|
||||
void andl(Register dest, int32_t imm) {
|
||||
alu_imm(4, imm, Operand(dest));
|
||||
}
|
||||
void andl(const Operand &dest, int32_t imm) {
|
||||
alu_imm(4, imm, dest);
|
||||
}
|
||||
void andl(Register dest, Register src) {
|
||||
emit1(0x21, src.code, dest.code);
|
||||
}
|
||||
void andl(const Operand &dest, Register src) {
|
||||
emit1(0x21, src.code, dest);
|
||||
}
|
||||
void andl(Register dest, const Operand &src) {
|
||||
emit1(0x23, dest.code, src);
|
||||
}
|
||||
void orl(Register dest, Register src) {
|
||||
emit1(0x09, src.code, dest.code);
|
||||
}
|
||||
void orl(const Operand &dest, Register src) {
|
||||
emit1(0x09, src.code, dest);
|
||||
}
|
||||
void orl(Register dest, const Operand &src) {
|
||||
emit1(0x0b, dest.code, src);
|
||||
}
|
||||
void xorl(Register dest, Register src) {
|
||||
emit1(0x31, src.code, dest.code);
|
||||
}
|
||||
void xorl(const Operand &dest, Register src) {
|
||||
emit1(0x31, src.code, dest);
|
||||
}
|
||||
void xorl(Register dest, const Operand &src) {
|
||||
emit1(0x33, dest.code, src);
|
||||
}
|
||||
|
||||
void subl(Register dest, Register src) {
|
||||
emit1(0x29, src.code, dest.code);
|
||||
}
|
||||
void subl(const Operand &dest, Register src) {
|
||||
emit1(0x29, src.code, dest);
|
||||
}
|
||||
void subl(Register dest, const Operand &src) {
|
||||
emit1(0x2b, dest.code, src);
|
||||
}
|
||||
void subl(Register dest, int32_t imm) {
|
||||
alu_imm(5, imm, Operand(dest));
|
||||
}
|
||||
void subl(const Operand &dest, int32_t imm) {
|
||||
alu_imm(5, imm, dest);
|
||||
}
|
||||
void addl(Register dest, Register src) {
|
||||
emit1(0x01, src.code, dest.code);
|
||||
}
|
||||
void addl(const Operand &dest, Register src) {
|
||||
emit1(0x01, src.code, dest);
|
||||
}
|
||||
void addl(Register dest, const Operand &src) {
|
||||
emit1(0x03, dest.code, src);
|
||||
}
|
||||
void addl(Register dest, int32_t imm) {
|
||||
alu_imm(0, imm, Operand(dest));
|
||||
}
|
||||
void addl(const Operand &dest, int32_t imm) {
|
||||
alu_imm(0, imm, dest);
|
||||
}
|
||||
|
||||
void imull(Register dest, const Operand &src) {
|
||||
emit2(0x0f, 0xaf, dest.code, src);
|
||||
}
|
||||
void imull(Register dest, Register src) {
|
||||
emit2(0x0f, 0xaf, dest.code, src.code);
|
||||
}
|
||||
void imull(Register dest, const Operand &src, int32_t imm) {
|
||||
if (imm >= SCHAR_MIN && imm <= SCHAR_MAX) {
|
||||
emit1(0x6b, dest.code, src);
|
||||
*pos_++ = imm;
|
||||
} else {
|
||||
emit1(0x69, dest.code, src);
|
||||
writeInt32(imm);
|
||||
}
|
||||
}
|
||||
void imull(Register dest, Register src, int32_t imm) {
|
||||
imull(dest, Operand(src), imm);
|
||||
}
|
||||
|
||||
void testl(const Operand &op1, Register op2) {
|
||||
emit1(0x85, op2.code, op1);
|
||||
}
|
||||
void testl(Register op1, Register op2) {
|
||||
emit1(0x85, op2.code, op1.code);
|
||||
}
|
||||
void set(ConditionCode cc, const Operand &dest) {
|
||||
emit2(0x0f, 0x90 + uint8_t(cc), 0, dest);
|
||||
}
|
||||
void set(ConditionCode cc, Register dest) {
|
||||
emit2(0x0f, 0x90 + uint8_t(cc), 0, dest.code);
|
||||
}
|
||||
void negl(Register srcdest) {
|
||||
emit1(0xf7, 3, srcdest.code);
|
||||
}
|
||||
void negl(const Operand &srcdest) {
|
||||
emit1(0xf7, 3, srcdest);
|
||||
}
|
||||
void notl(Register srcdest) {
|
||||
emit1(0xf7, 2, srcdest.code);
|
||||
}
|
||||
void notl(const Operand &srcdest) {
|
||||
emit1(0xf7, 2, srcdest);
|
||||
}
|
||||
void idivl(Register dividend) {
|
||||
emit1(0xf7, 7, dividend.code);
|
||||
}
|
||||
void idivl(const Operand ÷nd) {
|
||||
emit1(0xf7, 7, dividend);
|
||||
}
|
||||
|
||||
void ret() {
|
||||
emit1(0xc3);
|
||||
}
|
||||
void cld() {
|
||||
emit1(0xfc);
|
||||
}
|
||||
void push(Register reg) {
|
||||
emit1(0x50 + reg.code);
|
||||
}
|
||||
void push(const Operand &src) {
|
||||
if (src.isRegister())
|
||||
emit1(0x50 + src.registerCode());
|
||||
else
|
||||
emit1(0xff, 6, src);
|
||||
}
|
||||
void push(int32_t imm) {
|
||||
emit1(0x68);
|
||||
writeInt32(imm);
|
||||
}
|
||||
void pop(Register reg) {
|
||||
emit1(0x58 + reg.code);
|
||||
}
|
||||
void pop(const Operand &src) {
|
||||
if (src.isRegister())
|
||||
emit1(0x58 + src.registerCode());
|
||||
else
|
||||
emit1(0x8f, 0, src);
|
||||
}
|
||||
|
||||
void rep_movsb() {
|
||||
emit2(0xf3, 0xa4);
|
||||
}
|
||||
void rep_movsd() {
|
||||
emit2(0xf3, 0xa5);
|
||||
}
|
||||
void rep_stosd() {
|
||||
emit2(0xf3, 0xab);
|
||||
}
|
||||
void breakpoint() {
|
||||
emit1(0xcc);
|
||||
}
|
||||
|
||||
void fld32(const Operand &src) {
|
||||
emit1(0xd9, 0, src);
|
||||
}
|
||||
void fild32(const Operand &src) {
|
||||
emit1(0xdb, 0, src);
|
||||
}
|
||||
void fistp32(const Operand &dest) {
|
||||
emit1(0xdb, 3, dest);
|
||||
}
|
||||
void fadd32(const Operand &src) {
|
||||
emit1(0xd8, 0, src);
|
||||
}
|
||||
void fsub32(const Operand &src) {
|
||||
emit1(0xd8, 4, src);
|
||||
}
|
||||
void fmul32(const Operand &src) {
|
||||
emit1(0xd8, 1, src);
|
||||
}
|
||||
void fdiv32(const Operand &src) {
|
||||
emit1(0xd8, 6, src);
|
||||
}
|
||||
void fstp32(const Operand &dest) {
|
||||
emit1(0xd9, 3, dest);
|
||||
}
|
||||
void fstp(FpuRegister src) {
|
||||
emit2(0xdd, 0xd8 + src.code);
|
||||
}
|
||||
void fldcw(const Operand &src) {
|
||||
emit1(0xd9, 5, src);
|
||||
}
|
||||
void fstcw(const Operand &dest) {
|
||||
emit2(0x9b, 0xd9, 7, dest);
|
||||
}
|
||||
void fsubr32(const Operand &src) {
|
||||
emit1(0xd8, 5, src);
|
||||
}
|
||||
|
||||
// Compare st0 with stN.
|
||||
void fucomip(FpuRegister other) {
|
||||
emit2(0xdf, 0xe8 + other.code);
|
||||
}
|
||||
|
||||
// At least one argument of these forms must be st0.
|
||||
void fadd32(FpuRegister dest, FpuRegister src) {
|
||||
assert(dest == st0 || src == st0);
|
||||
if (dest == st0)
|
||||
emit2(0xd8, 0xc0 + dest.code);
|
||||
else
|
||||
emit2(0xdc, 0xc0 + src.code);
|
||||
}
|
||||
|
||||
void jmp(Label *dest) {
|
||||
int8_t d8;
|
||||
if (canEmitSmallJump(dest, &d8)) {
|
||||
emit2(0xeb, d8);
|
||||
} else {
|
||||
emit1(0xe9);
|
||||
emitJumpTarget(dest);
|
||||
}
|
||||
}
|
||||
void jmp(Register target) {
|
||||
emit1(0xff, 4, target.code);
|
||||
}
|
||||
void jmp(const Operand &target) {
|
||||
emit1(0xff, 4, target);
|
||||
}
|
||||
void j(ConditionCode cc, Label *dest) {
|
||||
int8_t d8;
|
||||
if (canEmitSmallJump(dest, &d8)) {
|
||||
emit2(0x70 + uint8_t(cc), d8);
|
||||
} else {
|
||||
emit2(0x0f, 0x80 + uint8_t(cc));
|
||||
emitJumpTarget(dest);
|
||||
}
|
||||
}
|
||||
void call(Label *dest) {
|
||||
emit1(0xe8);
|
||||
emitJumpTarget(dest);
|
||||
}
|
||||
void bind(Label *target) {
|
||||
if (outOfMemory()) {
|
||||
// If we ran out of memory, the code stream is potentially invalid and
|
||||
// we cannot use the embedded linked list.
|
||||
target->bind(pc());
|
||||
return;
|
||||
}
|
||||
|
||||
assert(!target->bound());
|
||||
uint32_t status = target->status();
|
||||
while (Label::More(status)) {
|
||||
// Grab the offset. It should be at least a 1byte op + rel32.
|
||||
uint32_t offset = Label::ToOffset(status);
|
||||
assert(offset >= 5);
|
||||
|
||||
// Grab the delta from target to pc.
|
||||
ptrdiff_t delta = pos_ - (buffer() + offset);
|
||||
assert(delta >= INT_MIN && delta <= INT_MAX);
|
||||
|
||||
int32_t *p = reinterpret_cast<int32_t *>(buffer() + offset - 4);
|
||||
status = *p;
|
||||
*p = delta;
|
||||
}
|
||||
target->bind(pc());
|
||||
}
|
||||
|
||||
void bind(DataLabel *address) {
|
||||
if (outOfMemory())
|
||||
return;
|
||||
if (address->used()) {
|
||||
uint32_t offset = DataLabel::ToOffset(address->status());
|
||||
*reinterpret_cast<int32_t *>(buffer() + offset - 4) = position() - int32_t(offset);
|
||||
}
|
||||
address->bind(pc());
|
||||
}
|
||||
void movl(Register dest, DataLabel *src) {
|
||||
emit1(0xb8 + dest.code);
|
||||
if (src->bound()) {
|
||||
writeInt32(int32_t(src->offset()) - (position() + 4));
|
||||
} else {
|
||||
writeInt32(0xabcdef0);
|
||||
src->use(pc());
|
||||
}
|
||||
if (!local_refs_.append(pc()))
|
||||
outOfMemory_ = true;
|
||||
}
|
||||
void emit_absolute_address(Label *address) {
|
||||
if (address->bound())
|
||||
writeUint32(int32_t(address->offset()) - (position() + 4));
|
||||
else
|
||||
writeUint32(address->addPending(position() + 4));
|
||||
if (!local_refs_.append(pc()))
|
||||
outOfMemory_ = true;
|
||||
}
|
||||
|
||||
void call(Register target) {
|
||||
emit1(0xff, 2, target.code);
|
||||
}
|
||||
void call(const Operand &target) {
|
||||
emit1(0xff, 2, target);
|
||||
}
|
||||
void call(ExternalAddress address) {
|
||||
emit1(0xe8);
|
||||
writeInt32(address.value());
|
||||
if (!external_refs_.append(pc()))
|
||||
outOfMemory_ = true;
|
||||
}
|
||||
void jmp(ExternalAddress address) {
|
||||
assert(sizeof(address) == sizeof(int32_t));
|
||||
emit1(0xe9);
|
||||
writeInt32(address.value());
|
||||
if (!external_refs_.append(pc()))
|
||||
outOfMemory_ = true;
|
||||
}
|
||||
|
||||
static void PatchRel32Absolute(uint8_t *ip, void *ptr) {
|
||||
int32_t delta = uint32_t(ptr) - uint32_t(ip);
|
||||
*reinterpret_cast<int32_t *>(ip - 4) = delta;
|
||||
}
|
||||
|
||||
void emitToExecutableMemory(void *code) {
|
||||
assert(!outOfMemory());
|
||||
|
||||
// Relocate anything we emitted as rel32 with an external pointer.
|
||||
uint8_t *base = reinterpret_cast<uint8_t *>(code);
|
||||
memcpy(base, buffer(), length());
|
||||
for (size_t i = 0; i < external_refs_.length(); i++) {
|
||||
size_t offset = external_refs_[i];
|
||||
PatchRel32Absolute(base + offset, *reinterpret_cast<void **>(base + offset - 4));
|
||||
}
|
||||
|
||||
// Relocate everything we emitted as an abs32 with an internal offset. Note
|
||||
// that in the code stream, we use relative offsets so we can use both Label
|
||||
// and DataLabel.
|
||||
for (size_t i = 0; i < local_refs_.length(); i++) {
|
||||
size_t offset = local_refs_[i];
|
||||
int32_t delta = *reinterpret_cast<int32_t *>(base + offset - 4);
|
||||
*reinterpret_cast<void **>(base + offset - 4) = base + offset + delta;
|
||||
}
|
||||
}
|
||||
|
||||
void align(uint32_t bytes) {
|
||||
int32_t delta = (pc() & ~(bytes - 1)) + bytes - pc();
|
||||
for (int32_t i = 0; i < delta; i++)
|
||||
emit1(0xcc);
|
||||
}
|
||||
|
||||
private:
|
||||
bool canEmitSmallJump(Label *dest, int8_t *deltap) {
|
||||
if (!dest->bound())
|
||||
return false;
|
||||
|
||||
// All small jumps are assumed to be 2 bytes.
|
||||
ptrdiff_t delta = ptrdiff_t(dest->offset()) - (position() + 2);
|
||||
if (delta < SCHAR_MIN || delta > SCHAR_MAX)
|
||||
return false;
|
||||
*deltap = delta;
|
||||
return true;
|
||||
}
|
||||
void emitJumpTarget(Label *dest) {
|
||||
if (dest->bound()) {
|
||||
ptrdiff_t delta = ptrdiff_t(dest->offset()) - (position() + 4);
|
||||
assert(delta >= INT_MIN && delta <= INT_MAX);
|
||||
writeInt32(delta);
|
||||
} else {
|
||||
writeUint32(dest->addPending(position() + 4));
|
||||
}
|
||||
}
|
||||
|
||||
void emit(uint8_t reg, const Operand &operand) {
|
||||
*pos_++ = operand.getByte(0) | (reg << 3);
|
||||
size_t length = operand.length();
|
||||
for (size_t i = 1; i < length; i++)
|
||||
*pos_++ = operand.getByte(i);
|
||||
}
|
||||
|
||||
void emit1(uint8_t opcode) {
|
||||
ensureSpace();
|
||||
*pos_++ = opcode;
|
||||
}
|
||||
void emit1(uint8_t opcode, uint8_t reg, uint8_t opreg) {
|
||||
ensureSpace();
|
||||
assert(reg <= 7);
|
||||
assert(opreg <= 7);
|
||||
*pos_++ = opcode;
|
||||
*pos_++ = (kModeReg << 6) | (reg << 3) | opreg;
|
||||
}
|
||||
void emit1(uint8_t opcode, uint8_t reg, const Operand &operand) {
|
||||
ensureSpace();
|
||||
assert(reg <= 7);
|
||||
*pos_++ = opcode;
|
||||
emit(reg, operand);
|
||||
}
|
||||
|
||||
void emit2(uint8_t prefix, uint8_t opcode) {
|
||||
ensureSpace();
|
||||
*pos_++ = prefix;
|
||||
*pos_++ = opcode;
|
||||
}
|
||||
void emit2(uint8_t prefix, uint8_t opcode, uint8_t reg, uint8_t opreg) {
|
||||
emit2(prefix, opcode);
|
||||
assert(reg <= 7);
|
||||
*pos_++ = (kModeReg << 6) | (reg << 3) | opreg;
|
||||
}
|
||||
void emit2(uint8_t prefix, uint8_t opcode, uint8_t reg, const Operand &operand) {
|
||||
emit2(prefix, opcode);
|
||||
emit(reg, operand);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void shift_cl(const T &t, uint8_t r) {
|
||||
emit1(0xd3, r, t);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void shift_imm(const T &t, uint8_t r, int32_t imm) {
|
||||
if (imm == 1) {
|
||||
emit1(0xd1, r, t);
|
||||
} else {
|
||||
emit1(0xc1, r, t);
|
||||
*pos_++ = imm & 0x1F;
|
||||
}
|
||||
}
|
||||
void alu_imm(uint8_t r, int32_t imm, const Operand &operand) {
|
||||
if (imm >= SCHAR_MIN && imm <= SCHAR_MAX) {
|
||||
emit1(0x83, r, operand);
|
||||
*pos_++ = uint8_t(imm & 0xff);
|
||||
} else if (operand.isRegister(eax)) {
|
||||
emit1(0x05 | (r << 3));
|
||||
writeInt32(imm);
|
||||
} else {
|
||||
emit1(0x81, r, operand);
|
||||
writeInt32(imm);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
ke::Vector<uint32_t> external_refs_;
|
||||
ke::Vector<uint32_t> local_refs_;
|
||||
};
|
||||
|
||||
#endif // _include_sourcepawn_assembler_x86_h__
|
||||
|
File diff suppressed because it is too large
Load Diff
53
public/sourcepawn/ke_allocator_policies.h
Normal file
53
public/sourcepawn/ke_allocator_policies.h
Normal file
@ -0,0 +1,53 @@
|
||||
/* vim: set ts=2 sw=2 tw=99 et:
|
||||
*
|
||||
* Copyright (C) 2012 David Anderson
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* SourcePawn. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
#ifndef _include_sourcepawn_allocatorpolicies_h_
|
||||
#define _include_sourcepawn_allocatorpolicies_h_
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
namespace ke {
|
||||
|
||||
class SystemAllocatorPolicy
|
||||
{
|
||||
protected:
|
||||
void reportOutOfMemory() {
|
||||
fprintf(stderr, "OUT OF MEMORY\n");
|
||||
abort();
|
||||
}
|
||||
void reportAllocationOverflow() {
|
||||
fprintf(stderr, "OUT OF MEMORY\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
public:
|
||||
void free(void *memory) {
|
||||
::free(memory);
|
||||
}
|
||||
void *malloc(size_t bytes) {
|
||||
void *ptr = ::malloc(bytes);
|
||||
if (!ptr)
|
||||
reportOutOfMemory();
|
||||
return ptr;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // _include_sourcepawn_allocatorpolicies_h_
|
318
public/sourcepawn/ke_utility.h
Normal file
318
public/sourcepawn/ke_utility.h
Normal file
@ -0,0 +1,318 @@
|
||||
/* vim: set ts=4 sw=4 tw=99 et:
|
||||
*
|
||||
* Copyright (C) 2012-2013 David Anderson
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* SourcePawn. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
#ifndef _include_jitcraft_utility_h_
|
||||
#define _include_jitcraft_utility_h_
|
||||
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#if defined(_MSC_VER)
|
||||
# include <intrin.h>
|
||||
#endif
|
||||
|
||||
#define KE_32BIT
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
# pragma warning(disable:4355)
|
||||
#endif
|
||||
|
||||
namespace ke {
|
||||
|
||||
static const size_t kMallocAlignment = sizeof(void *) * 2;
|
||||
|
||||
typedef uint8_t uint8;
|
||||
typedef int32_t int32;
|
||||
typedef uint32_t uint32;
|
||||
typedef int64_t int64;
|
||||
typedef uint64_t uint64;
|
||||
|
||||
typedef uint8 * Address;
|
||||
|
||||
static const size_t kKB = 1024;
|
||||
static const size_t kMB = 1024 * kKB;
|
||||
static const size_t kGB = 1024 * kMB;
|
||||
|
||||
template <typename T>
|
||||
class AutoFree
|
||||
{
|
||||
T *t_;
|
||||
|
||||
public:
|
||||
AutoFree()
|
||||
: t_(NULL)
|
||||
{
|
||||
}
|
||||
AutoFree(T *t)
|
||||
: t_(t)
|
||||
{
|
||||
}
|
||||
~AutoFree() {
|
||||
free(t_);
|
||||
}
|
||||
T *take() {
|
||||
T *t = t_;
|
||||
t_ = NULL;
|
||||
return t;
|
||||
}
|
||||
T *operator *() const {
|
||||
return t_;
|
||||
}
|
||||
void operator =(T *t) {
|
||||
if (t_)
|
||||
free(t_);
|
||||
t_ = t;
|
||||
}
|
||||
};
|
||||
|
||||
// Bob Jenkin's one-at-a-time hash function[1].
|
||||
//
|
||||
// [1] http://burtleburtle.net/bob/hash/doobs.html
|
||||
class CharacterStreamHasher
|
||||
{
|
||||
uint32 hash;
|
||||
|
||||
public:
|
||||
CharacterStreamHasher()
|
||||
: hash(0)
|
||||
{ }
|
||||
|
||||
void add(char c) {
|
||||
hash += c;
|
||||
hash += (hash << 10);
|
||||
hash ^= (hash >> 6);
|
||||
}
|
||||
|
||||
void add(const char *s, size_t length) {
|
||||
for (size_t i = 0; i < length; i++)
|
||||
add(s[i]);
|
||||
}
|
||||
|
||||
uint32 result() {
|
||||
hash += (hash << 3);
|
||||
hash ^= (hash >> 11);
|
||||
hash += (hash << 15);
|
||||
return hash;
|
||||
}
|
||||
};
|
||||
|
||||
static inline uint32
|
||||
HashCharSequence(const char *s, size_t length)
|
||||
{
|
||||
CharacterStreamHasher hasher;
|
||||
hasher.add(s, length);
|
||||
return hasher.result();
|
||||
}
|
||||
|
||||
// From http://burtleburtle.net/bob/hash/integer.html
|
||||
static inline uint32
|
||||
HashInt32(int32 a)
|
||||
{
|
||||
a = (a ^ 61) ^ (a >> 16);
|
||||
a = a + (a << 3);
|
||||
a = a ^ (a >> 4);
|
||||
a = a * 0x27d4eb2d;
|
||||
a = a ^ (a >> 15);
|
||||
return a;
|
||||
}
|
||||
|
||||
// From http://www.cris.com/~Ttwang/tech/inthash.htm
|
||||
static inline uint32
|
||||
HashInt64(int64 key)
|
||||
{
|
||||
key = (~key) + (key << 18); // key = (key << 18) - key - 1;
|
||||
key = key ^ (uint64(key) >> 31);
|
||||
key = key * 21; // key = (key + (key << 2)) + (key << 4);
|
||||
key = key ^ (uint64(key) >> 11);
|
||||
key = key + (key << 6);
|
||||
key = key ^ (uint64(key) >> 22);
|
||||
return uint32(key);
|
||||
}
|
||||
|
||||
static inline uint32
|
||||
HashPointer(void *p)
|
||||
{
|
||||
#if defined(KE_32BIT)
|
||||
return HashInt32(reinterpret_cast<int32>(p));
|
||||
#elif defined(KE_64BIT)
|
||||
return HashInt64(reinterpret_cast<int64>(p));
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline size_t
|
||||
Log2(size_t number)
|
||||
{
|
||||
assert(number != 0);
|
||||
|
||||
#ifdef _MSC_VER
|
||||
unsigned long rval;
|
||||
# ifdef _M_IX86
|
||||
_BitScanReverse(&rval, number);
|
||||
# elif _M_X64
|
||||
_BitScanReverse64(&rval, number);
|
||||
# endif
|
||||
return rval;
|
||||
#else
|
||||
size_t bit;
|
||||
asm("bsr %1, %0\n"
|
||||
: "=r" (bit)
|
||||
: "rm" (number));
|
||||
return bit;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline size_t
|
||||
FindRightmostBit(size_t number)
|
||||
{
|
||||
assert(number != 0);
|
||||
|
||||
#ifdef _MSC_VER
|
||||
unsigned long rval;
|
||||
# ifdef _M_IX86
|
||||
_BitScanForward(&rval, number);
|
||||
# elif _M_X64
|
||||
_BitScanForward64(&rval, number);
|
||||
# endif
|
||||
return rval;
|
||||
#else
|
||||
size_t bit;
|
||||
asm("bsf %1, %0\n"
|
||||
: "=r" (bit)
|
||||
: "rm" (number));
|
||||
return bit;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline bool
|
||||
IsPowerOfTwo(size_t value)
|
||||
{
|
||||
if (value == 0)
|
||||
return false;
|
||||
return !(value & (value - 1));
|
||||
}
|
||||
|
||||
static inline size_t
|
||||
Align(size_t count, size_t alignment)
|
||||
{
|
||||
assert(IsPowerOfTwo(alignment));
|
||||
return count + (alignment - (count % alignment)) % alignment;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
IsUint32AddSafe(unsigned a, unsigned b)
|
||||
{
|
||||
if (!a || !b)
|
||||
return true;
|
||||
size_t log2_a = Log2(a);
|
||||
size_t log2_b = Log2(b);
|
||||
return (log2_a < sizeof(unsigned) * 8) &&
|
||||
(log2_b < sizeof(unsigned) * 8);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
IsUintPtrAddSafe(size_t a, size_t b)
|
||||
{
|
||||
if (!a || !b)
|
||||
return true;
|
||||
size_t log2_a = Log2(a);
|
||||
size_t log2_b = Log2(b);
|
||||
return (log2_a < sizeof(size_t) * 8) &&
|
||||
(log2_b < sizeof(size_t) * 8);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
IsUint32MultiplySafe(unsigned a, unsigned b)
|
||||
{
|
||||
if (a <= 1 || b <= 1)
|
||||
return true;
|
||||
|
||||
size_t log2_a = Log2(a);
|
||||
size_t log2_b = Log2(b);
|
||||
return log2_a + log2_b <= sizeof(unsigned) * 8;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
IsUintPtrMultiplySafe(size_t a, size_t b)
|
||||
{
|
||||
if (a <= 1 || b <= 1)
|
||||
return true;
|
||||
|
||||
size_t log2_a = Log2(a);
|
||||
size_t log2_b = Log2(b);
|
||||
return log2_a + log2_b <= sizeof(size_t) * 8;
|
||||
}
|
||||
|
||||
#define ARRAY_LENGTH(array) (sizeof(array) / sizeof(array[0]))
|
||||
#define STATIC_ASSERT(cond) extern int static_assert_f(int a[(cond) ? 1 : -1])
|
||||
|
||||
#define IS_ALIGNED(addr, alignment) (!(uintptr_t(addr) & ((alignment) - 1)))
|
||||
|
||||
template <typename T>
|
||||
static inline bool
|
||||
IsAligned(T addr, size_t alignment)
|
||||
{
|
||||
assert(IsPowerOfTwo(alignment));
|
||||
return !(uintptr_t(addr) & (alignment - 1));
|
||||
}
|
||||
|
||||
static inline Address
|
||||
AlignedBase(Address addr, size_t alignment)
|
||||
{
|
||||
assert(IsPowerOfTwo(alignment));
|
||||
return Address(uintptr_t(addr) & ~(alignment - 1));
|
||||
}
|
||||
|
||||
template <typename T> static inline T
|
||||
Min(const T &t1, const T &t2)
|
||||
{
|
||||
return t1 < t2 ? t1 : t2;
|
||||
}
|
||||
|
||||
template <typename T> static inline T
|
||||
Max(const T &t1, const T &t2)
|
||||
{
|
||||
return t1 > t2 ? t1 : t2;
|
||||
}
|
||||
|
||||
template <typename T> T
|
||||
ReturnAndVoid(T &t)
|
||||
{
|
||||
T saved = t;
|
||||
t = T();
|
||||
return saved;
|
||||
}
|
||||
|
||||
#define OFFSETOF(Class, Member) reinterpret_cast<size_t>(&((Class *)NULL)->Member)
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
# define KE_SIZET_FMT "%Iu"
|
||||
#elif defined(__GNUC__)
|
||||
# define KE_SIZET_FMT "%zu"
|
||||
#else
|
||||
# error "Implement format specifier string"
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__)
|
||||
# define KE_CRITICAL_LIKELY(x) __builtin_expect(!!(x), 1)
|
||||
#else
|
||||
# define KE_CRITICAL_LIKELY(x) x
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#endif // _include_jitcraft_utility_h_
|
166
public/sourcepawn/ke_vector.h
Normal file
166
public/sourcepawn/ke_vector.h
Normal file
@ -0,0 +1,166 @@
|
||||
/* vim: set ts=2 sw=2 tw=99 et:
|
||||
*
|
||||
* Copyright (C) 2012 David Anderson
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* SourcePawn. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
#ifndef _INCLUDE_KEIMA_TPL_CPP_VECTOR_H_
|
||||
#define _INCLUDE_KEIMA_TPL_CPP_VECTOR_H_
|
||||
|
||||
#include <new>
|
||||
#include <stdlib.h>
|
||||
#include <ke_allocator_policies.h>
|
||||
#include <ke_utility.h>
|
||||
|
||||
namespace ke {
|
||||
|
||||
template <typename T, typename AllocPolicy = SystemAllocatorPolicy>
|
||||
class Vector : public AllocPolicy
|
||||
{
|
||||
public:
|
||||
Vector(AllocPolicy = AllocPolicy())
|
||||
: data(NULL),
|
||||
nitems(0),
|
||||
maxsize(0)
|
||||
{
|
||||
}
|
||||
|
||||
~Vector()
|
||||
{
|
||||
zap();
|
||||
}
|
||||
|
||||
void steal(Vector &other) {
|
||||
zap();
|
||||
data = other.data;
|
||||
nitems = other.nitems;
|
||||
maxsize = other.maxsize;
|
||||
other.reset();
|
||||
}
|
||||
|
||||
bool append(const T& item) {
|
||||
if (!growIfNeeded(1))
|
||||
return false;
|
||||
new (&data[nitems]) T(item);
|
||||
nitems++;
|
||||
return true;
|
||||
}
|
||||
void infallibleAppend(const T &item) {
|
||||
assert(growIfNeeded(1));
|
||||
new (&data[nitems]) T(item);
|
||||
nitems++;
|
||||
}
|
||||
T popCopy() {
|
||||
T t = at(length() - 1);
|
||||
pop();
|
||||
return t;
|
||||
}
|
||||
void pop() {
|
||||
assert(nitems);
|
||||
data[nitems - 1].~T();
|
||||
nitems--;
|
||||
}
|
||||
bool empty() const {
|
||||
return length() == 0;
|
||||
}
|
||||
size_t length() const {
|
||||
return nitems;
|
||||
}
|
||||
T& at(size_t i) {
|
||||
assert(i < length());
|
||||
return data[i];
|
||||
}
|
||||
const T& at(size_t i) const {
|
||||
assert(i < length());
|
||||
return data[i];
|
||||
}
|
||||
T& operator [](size_t i) {
|
||||
return at(i);
|
||||
}
|
||||
const T& operator [](size_t i) const {
|
||||
return at(i);
|
||||
}
|
||||
void clear() {
|
||||
nitems = 0;
|
||||
}
|
||||
const T &back() const {
|
||||
return at(length() - 1);
|
||||
}
|
||||
T &back() {
|
||||
return at(length() - 1);
|
||||
}
|
||||
|
||||
T *buffer() const {
|
||||
return data;
|
||||
}
|
||||
|
||||
bool ensure(size_t desired) {
|
||||
if (desired <= length())
|
||||
return true;
|
||||
|
||||
return growIfNeeded(desired - length());
|
||||
}
|
||||
|
||||
private:
|
||||
void zap() {
|
||||
for (size_t i = 0; i < nitems; i++)
|
||||
data[i].~T();
|
||||
this->free(data);
|
||||
}
|
||||
void reset() {
|
||||
data = NULL;
|
||||
nitems = 0;
|
||||
maxsize = 0;
|
||||
}
|
||||
|
||||
bool growIfNeeded(size_t needed)
|
||||
{
|
||||
if (!IsUintPtrAddSafe(nitems, needed)) {
|
||||
this->reportAllocationOverflow();
|
||||
return false;
|
||||
}
|
||||
if (nitems + needed < maxsize)
|
||||
return true;
|
||||
if (maxsize == 0)
|
||||
maxsize = 8;
|
||||
while (nitems + needed > maxsize) {
|
||||
if (!IsUintPtrMultiplySafe(maxsize, 2)) {
|
||||
this->reportAllocationOverflow();
|
||||
return false;
|
||||
}
|
||||
maxsize *= 2;
|
||||
}
|
||||
T* newdata = (T*)this->malloc(sizeof(T) * maxsize);
|
||||
if (newdata == NULL)
|
||||
return false;
|
||||
for (size_t i = 0; i < nitems; i++) {
|
||||
new (&newdata[i]) T(data[i]);
|
||||
data[i].~T();
|
||||
}
|
||||
this->free(data);
|
||||
data = newdata;
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
T* data;
|
||||
size_t nitems;
|
||||
size_t maxsize;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* _INCLUDE_KEIMA_TPL_CPP_VECTOR_H_ */
|
||||
|
@ -1,5 +1,5 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* vim: set ts=4 sw=4 tw=99 noet:
|
||||
* =============================================================================
|
||||
* SourcePawn
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
@ -85,6 +85,8 @@ typedef uint32_t funcid_t; /**< Function index code */
|
||||
#define SP_ERROR_ABORTED 25 /**< Function call was aborted */
|
||||
#define SP_ERROR_CODE_TOO_OLD 26 /**< Code is too old for this VM */
|
||||
#define SP_ERROR_CODE_TOO_NEW 27 /**< Code is too new for this VM */
|
||||
#define SP_ERROR_OUT_OF_MEMORY 28 /**< Out of memory */
|
||||
#define SP_ERROR_INTEGER_OVERFLOW 29 /**< Integer overflow (-INT_MIN / -1) */
|
||||
//Hey you! Update the string table if you add to the end of me! */
|
||||
|
||||
/**********************************************
|
||||
|
@ -22,8 +22,8 @@ binary.AddSourceFiles('sourcepawn/jit', [
|
||||
'sp_vm_basecontext.cpp',
|
||||
'sp_vm_engine.cpp',
|
||||
'sp_vm_function.cpp',
|
||||
'opcodes.cpp',
|
||||
'x86/jit_x86.cpp',
|
||||
'x86/opcode_helpers.cpp',
|
||||
'zlib/adler32.c',
|
||||
'zlib/compress.c',
|
||||
'zlib/crc32.c',
|
||||
|
@ -1,3 +1,4 @@
|
||||
// vim: set ts=8 sts=2 sw=2 tw=99 et:
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@ -12,573 +13,571 @@
|
||||
|
||||
using namespace SourcePawn;
|
||||
|
||||
BaseRuntime::BaseRuntime() : m_Debug(&m_plugin), m_pPlugin(&m_plugin), m_pCtx(NULL),
|
||||
m_PubFuncs(NULL), m_PubJitFuncs(NULL), m_pCo(NULL), m_CompSerial(0)
|
||||
static inline bool
|
||||
IsPointerCellAligned(void *p)
|
||||
{
|
||||
memset(&m_plugin, 0, sizeof(m_plugin));
|
||||
return uintptr_t(p) % 4 == 0;
|
||||
}
|
||||
|
||||
m_FuncCache = NULL;
|
||||
m_MaxFuncs = 0;
|
||||
m_NumFuncs = 0;
|
||||
|
||||
memset(m_CodeHash, 0, sizeof(m_CodeHash));
|
||||
memset(m_DataHash, 0, sizeof(m_DataHash));
|
||||
BaseRuntime::BaseRuntime()
|
||||
: m_Debug(&m_plugin),
|
||||
m_pCtx(NULL),
|
||||
m_PubFuncs(NULL),
|
||||
m_PubJitFuncs(NULL),
|
||||
co_(NULL),
|
||||
m_CompSerial(0)
|
||||
{
|
||||
memset(&m_plugin, 0, sizeof(m_plugin));
|
||||
|
||||
m_MaxFuncs = 0;
|
||||
m_NumFuncs = 0;
|
||||
float_table_ = NULL;
|
||||
function_map_ = NULL;
|
||||
alt_pcode_ = NULL;
|
||||
|
||||
memset(m_CodeHash, 0, sizeof(m_CodeHash));
|
||||
memset(m_DataHash, 0, sizeof(m_DataHash));
|
||||
}
|
||||
|
||||
BaseRuntime::~BaseRuntime()
|
||||
{
|
||||
for (uint32_t i = 0; i < m_pPlugin->num_publics; i++)
|
||||
{
|
||||
delete m_PubFuncs[i];
|
||||
m_PubFuncs[i] = NULL;
|
||||
}
|
||||
delete [] m_PubFuncs;
|
||||
delete [] m_PubJitFuncs;
|
||||
for (uint32_t i = 0; i < m_plugin.num_publics; i++)
|
||||
delete m_PubFuncs[i];
|
||||
delete [] m_PubFuncs;
|
||||
delete [] m_PubJitFuncs;
|
||||
delete [] float_table_;
|
||||
delete [] function_map_;
|
||||
delete [] alt_pcode_;
|
||||
|
||||
for (unsigned int i = 0; i < m_NumFuncs; i++)
|
||||
{
|
||||
delete m_FuncCache[i];
|
||||
}
|
||||
free(m_FuncCache);
|
||||
for (size_t i = 0; i < m_JitFunctions.length(); i++)
|
||||
delete m_JitFunctions[i];
|
||||
|
||||
delete m_pCtx;
|
||||
if (m_pCo != NULL)
|
||||
{
|
||||
m_pCo->Abort();
|
||||
}
|
||||
delete m_pCtx;
|
||||
if (co_)
|
||||
co_->Abort();
|
||||
|
||||
free(m_pPlugin->base);
|
||||
delete [] m_pPlugin->memory;
|
||||
delete [] m_pPlugin->publics;
|
||||
delete [] m_pPlugin->pubvars;
|
||||
delete [] m_pPlugin->natives;
|
||||
free(m_pPlugin->name);
|
||||
free(m_plugin.base);
|
||||
delete [] m_plugin.memory;
|
||||
delete [] m_plugin.publics;
|
||||
delete [] m_plugin.pubvars;
|
||||
delete [] m_plugin.natives;
|
||||
free(m_plugin.name);
|
||||
}
|
||||
|
||||
void
|
||||
BaseRuntime::SetupFloatNativeRemapping()
|
||||
{
|
||||
float_table_ = new floattbl_t[m_plugin.num_natives];
|
||||
for (size_t i = 0; i < m_plugin.num_natives; i++) {
|
||||
const char *name = m_plugin.natives[i].name;
|
||||
if (!strcmp(name, "FloatAbs")) {
|
||||
float_table_[i].found = true;
|
||||
float_table_[i].index = OP_FABS;
|
||||
} else if (!strcmp(name, "FloatAdd")) {
|
||||
float_table_[i].found = true;
|
||||
float_table_[i].index = OP_FLOATADD;
|
||||
} else if (!strcmp(name, "FloatSub")) {
|
||||
float_table_[i].found = true;
|
||||
float_table_[i].index = OP_FLOATSUB;
|
||||
} else if (!strcmp(name, "FloatMul")) {
|
||||
float_table_[i].found = true;
|
||||
float_table_[i].index = OP_FLOATMUL;
|
||||
} else if (!strcmp(name, "FloatDiv")) {
|
||||
float_table_[i].found = true;
|
||||
float_table_[i].index = OP_FLOATDIV;
|
||||
} else if (!strcmp(name, "float")) {
|
||||
float_table_[i].found = true;
|
||||
float_table_[i].index = OP_FLOAT;
|
||||
} else if (!strcmp(name, "FloatCompare")) {
|
||||
float_table_[i].found = true;
|
||||
float_table_[i].index = OP_FLOATCMP;
|
||||
} else if (!strcmp(name, "RoundToZero")) {
|
||||
float_table_[i].found = true;
|
||||
float_table_[i].index = OP_RND_TO_ZERO;
|
||||
} else if (!strcmp(name, "RoundToCeil")) {
|
||||
float_table_[i].found = true;
|
||||
float_table_[i].index = OP_RND_TO_CEIL;
|
||||
} else if (!strcmp(name, "RoundToFloor")) {
|
||||
float_table_[i].found = true;
|
||||
float_table_[i].index = OP_RND_TO_FLOOR;
|
||||
} else if (!strcmp(name, "RoundToNearest")) {
|
||||
float_table_[i].found = true;
|
||||
float_table_[i].index = OP_RND_TO_NEAREST;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned
|
||||
BaseRuntime::GetNativeReplacement(size_t index)
|
||||
{
|
||||
if (!float_table_[index].found)
|
||||
return OP_NOP;
|
||||
return float_table_[index].index;
|
||||
}
|
||||
|
||||
void
|
||||
BaseRuntime::SetName(const char *name)
|
||||
{
|
||||
m_plugin.name = strdup(name);
|
||||
}
|
||||
|
||||
static cell_t InvalidNative(IPluginContext *pCtx, const cell_t *params)
|
||||
{
|
||||
return pCtx->ThrowNativeErrorEx(SP_ERROR_INVALID_NATIVE, "Invalid native");
|
||||
return pCtx->ThrowNativeErrorEx(SP_ERROR_INVALID_NATIVE, "Invalid native");
|
||||
}
|
||||
|
||||
int BaseRuntime::CreateFromMemory(sp_file_hdr_t *hdr, uint8_t *base)
|
||||
{
|
||||
int set_err;
|
||||
char *nameptr;
|
||||
uint8_t sectnum = 0;
|
||||
sp_plugin_t *plugin = m_pPlugin;
|
||||
sp_file_section_t *secptr = (sp_file_section_t *)(base + sizeof(sp_file_hdr_t));
|
||||
char *nameptr;
|
||||
uint8_t sectnum = 0;
|
||||
sp_file_section_t *secptr = (sp_file_section_t *)(base + sizeof(sp_file_hdr_t));
|
||||
|
||||
memset(plugin, 0, sizeof(sp_plugin_t));
|
||||
memset(&m_plugin, 0, sizeof(m_plugin));
|
||||
|
||||
plugin->base = base;
|
||||
plugin->base_size = hdr->imagesize;
|
||||
set_err = SP_ERROR_NONE;
|
||||
m_plugin.base = base;
|
||||
m_plugin.base_size = hdr->imagesize;
|
||||
|
||||
if (hdr->version == 0x0101)
|
||||
{
|
||||
plugin->debug.unpacked = true;
|
||||
}
|
||||
if (hdr->version == 0x0101)
|
||||
m_plugin.debug.unpacked = true;
|
||||
|
||||
/* We have to read the name section first */
|
||||
for (sectnum = 0; sectnum < hdr->sections; sectnum++)
|
||||
{
|
||||
nameptr = (char *)(base + hdr->stringtab + secptr[sectnum].nameoffs);
|
||||
if (strcmp(nameptr, ".names") == 0)
|
||||
{
|
||||
plugin->stringbase = (const char *)(base + secptr[sectnum].dataoffs);
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* We have to read the name section first */
|
||||
for (sectnum = 0; sectnum < hdr->sections; sectnum++) {
|
||||
nameptr = (char *)(base + hdr->stringtab + secptr[sectnum].nameoffs);
|
||||
if (strcmp(nameptr, ".names") == 0) {
|
||||
m_plugin.stringbase = (const char *)(base + secptr[sectnum].dataoffs);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
sectnum = 0;
|
||||
sectnum = 0;
|
||||
|
||||
/* Now read the rest of the sections */
|
||||
while (sectnum < hdr->sections)
|
||||
{
|
||||
nameptr = (char *)(base + hdr->stringtab + secptr->nameoffs);
|
||||
/* Now read the rest of the sections */
|
||||
while (sectnum < hdr->sections) {
|
||||
nameptr = (char *)(base + hdr->stringtab + secptr->nameoffs);
|
||||
|
||||
if (!(plugin->pcode) && !strcmp(nameptr, ".code"))
|
||||
{
|
||||
sp_file_code_t *cod = (sp_file_code_t *)(base + secptr->dataoffs);
|
||||
if (!(m_plugin.pcode) && !strcmp(nameptr, ".code")) {
|
||||
sp_file_code_t *cod = (sp_file_code_t *)(base + secptr->dataoffs);
|
||||
|
||||
if (cod->codeversion < SP_CODEVERS_JIT1)
|
||||
{
|
||||
return SP_ERROR_CODE_TOO_OLD;
|
||||
}
|
||||
else if (cod->codeversion > SP_CODEVERS_JIT2)
|
||||
{
|
||||
return SP_ERROR_CODE_TOO_NEW;
|
||||
}
|
||||
if (cod->codeversion < SP_CODEVERS_JIT1)
|
||||
return SP_ERROR_CODE_TOO_OLD;
|
||||
if (cod->codeversion > SP_CODEVERS_JIT2)
|
||||
return SP_ERROR_CODE_TOO_NEW;
|
||||
|
||||
plugin->pcode = base + secptr->dataoffs + cod->code;
|
||||
plugin->pcode_size = cod->codesize;
|
||||
plugin->flags = cod->flags;
|
||||
plugin->pcode_version = cod->codeversion;
|
||||
}
|
||||
else if (!(plugin->data) && !strcmp(nameptr, ".data"))
|
||||
{
|
||||
sp_file_data_t *dat = (sp_file_data_t *)(base + secptr->dataoffs);
|
||||
plugin->data = base + secptr->dataoffs + dat->data;
|
||||
plugin->data_size = dat->datasize;
|
||||
plugin->mem_size = dat->memsize;
|
||||
plugin->memory = new uint8_t[plugin->mem_size];
|
||||
memcpy(plugin->memory, plugin->data, plugin->data_size);
|
||||
}
|
||||
else if ((plugin->publics == NULL) && !strcmp(nameptr, ".publics"))
|
||||
{
|
||||
sp_file_publics_t *publics;
|
||||
m_plugin.pcode = base + secptr->dataoffs + cod->code;
|
||||
m_plugin.pcode_size = cod->codesize;
|
||||
m_plugin.flags = cod->flags;
|
||||
m_plugin.pcode_version = cod->codeversion;
|
||||
if (!IsPointerCellAligned(m_plugin.pcode)) {
|
||||
// The JIT requires that pcode is cell-aligned, so if it's not, we
|
||||
// remap the code segment to a new address.
|
||||
alt_pcode_ = new uint8_t[m_plugin.pcode_size];
|
||||
memcpy(alt_pcode_, m_plugin.pcode, m_plugin.pcode_size);
|
||||
assert(IsPointerCellAligned(alt_pcode_));
|
||||
|
||||
publics = (sp_file_publics_t *)(base + secptr->dataoffs);
|
||||
plugin->num_publics = secptr->size / sizeof(sp_file_publics_t);
|
||||
m_plugin.pcode = alt_pcode_;
|
||||
}
|
||||
} else if (!(m_plugin.data) && !strcmp(nameptr, ".data")) {
|
||||
sp_file_data_t *dat = (sp_file_data_t *)(base + secptr->dataoffs);
|
||||
m_plugin.data = base + secptr->dataoffs + dat->data;
|
||||
m_plugin.data_size = dat->datasize;
|
||||
m_plugin.mem_size = dat->memsize;
|
||||
m_plugin.memory = new uint8_t[m_plugin.mem_size];
|
||||
memcpy(m_plugin.memory, m_plugin.data, m_plugin.data_size);
|
||||
} else if ((m_plugin.publics == NULL) && !strcmp(nameptr, ".publics")) {
|
||||
sp_file_publics_t *publics;
|
||||
|
||||
if (plugin->num_publics > 0)
|
||||
{
|
||||
plugin->publics = new sp_public_t[plugin->num_publics];
|
||||
publics = (sp_file_publics_t *)(base + secptr->dataoffs);
|
||||
m_plugin.num_publics = secptr->size / sizeof(sp_file_publics_t);
|
||||
|
||||
for (uint32_t i = 0; i < plugin->num_publics; i++)
|
||||
{
|
||||
plugin->publics[i].code_offs = publics[i].address;
|
||||
plugin->publics[i].funcid = (i << 1) | 1;
|
||||
plugin->publics[i].name = plugin->stringbase + publics[i].name;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ((plugin->pubvars == NULL) && !strcmp(nameptr, ".pubvars"))
|
||||
{
|
||||
sp_file_pubvars_t *pubvars;
|
||||
if (m_plugin.num_publics > 0) {
|
||||
m_plugin.publics = new sp_public_t[m_plugin.num_publics];
|
||||
|
||||
pubvars = (sp_file_pubvars_t *)(base + secptr->dataoffs);
|
||||
plugin->num_pubvars = secptr->size / sizeof(sp_file_pubvars_t);
|
||||
for (uint32_t i = 0; i < m_plugin.num_publics; i++) {
|
||||
m_plugin.publics[i].code_offs = publics[i].address;
|
||||
m_plugin.publics[i].funcid = (i << 1) | 1;
|
||||
m_plugin.publics[i].name = m_plugin.stringbase + publics[i].name;
|
||||
}
|
||||
}
|
||||
} else if ((m_plugin.pubvars == NULL) && !strcmp(nameptr, ".pubvars")) {
|
||||
sp_file_pubvars_t *pubvars;
|
||||
|
||||
if (plugin->num_pubvars > 0)
|
||||
{
|
||||
plugin->pubvars = new sp_pubvar_t[plugin->num_pubvars];
|
||||
pubvars = (sp_file_pubvars_t *)(base + secptr->dataoffs);
|
||||
m_plugin.num_pubvars = secptr->size / sizeof(sp_file_pubvars_t);
|
||||
|
||||
for (uint32_t i = 0; i < plugin->num_pubvars; i++)
|
||||
{
|
||||
plugin->pubvars[i].name = plugin->stringbase + pubvars[i].name;
|
||||
plugin->pubvars[i].offs = (cell_t *)(plugin->memory + pubvars[i].address);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ((plugin->natives == NULL) && !strcmp(nameptr, ".natives"))
|
||||
{
|
||||
sp_file_natives_t *natives;
|
||||
if (m_plugin.num_pubvars > 0) {
|
||||
m_plugin.pubvars = new sp_pubvar_t[m_plugin.num_pubvars];
|
||||
|
||||
natives = (sp_file_natives_t *)(base + secptr->dataoffs);
|
||||
plugin->num_natives = secptr->size / sizeof(sp_file_natives_t);
|
||||
for (uint32_t i = 0; i < m_plugin.num_pubvars; i++) {
|
||||
m_plugin.pubvars[i].name = m_plugin.stringbase + pubvars[i].name;
|
||||
m_plugin.pubvars[i].offs = (cell_t *)(m_plugin.memory + pubvars[i].address);
|
||||
}
|
||||
}
|
||||
} else if ((m_plugin.natives == NULL) && !strcmp(nameptr, ".natives")) {
|
||||
sp_file_natives_t *natives;
|
||||
|
||||
if (plugin->num_natives > 0)
|
||||
{
|
||||
plugin->natives = new sp_native_t[plugin->num_natives];
|
||||
natives = (sp_file_natives_t *)(base + secptr->dataoffs);
|
||||
m_plugin.num_natives = secptr->size / sizeof(sp_file_natives_t);
|
||||
|
||||
for (uint32_t i = 0; i < plugin->num_natives; i++)
|
||||
{
|
||||
plugin->natives[i].flags = 0;
|
||||
plugin->natives[i].pfn = InvalidNative;
|
||||
plugin->natives[i].status = SP_NATIVE_UNBOUND;
|
||||
plugin->natives[i].user = NULL;
|
||||
plugin->natives[i].name = plugin->stringbase + natives[i].name;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!(plugin->debug.files) && !strcmp(nameptr, ".dbg.files"))
|
||||
{
|
||||
plugin->debug.files = (sp_fdbg_file_t *)(base + secptr->dataoffs);
|
||||
}
|
||||
else if (!(plugin->debug.lines) && !strcmp(nameptr, ".dbg.lines"))
|
||||
{
|
||||
plugin->debug.lines = (sp_fdbg_line_t *)(base + secptr->dataoffs);
|
||||
}
|
||||
else if (!(plugin->debug.symbols) && !strcmp(nameptr, ".dbg.symbols"))
|
||||
{
|
||||
plugin->debug.symbols = (sp_fdbg_symbol_t *)(base + secptr->dataoffs);
|
||||
}
|
||||
else if (!(plugin->debug.lines_num) && !strcmp(nameptr, ".dbg.info"))
|
||||
{
|
||||
sp_fdbg_info_t *inf = (sp_fdbg_info_t *)(base + secptr->dataoffs);
|
||||
plugin->debug.files_num = inf->num_files;
|
||||
plugin->debug.lines_num = inf->num_lines;
|
||||
plugin->debug.syms_num = inf->num_syms;
|
||||
}
|
||||
else if (!(plugin->debug.stringbase) && !strcmp(nameptr, ".dbg.strings"))
|
||||
{
|
||||
plugin->debug.stringbase = (const char *)(base + secptr->dataoffs);
|
||||
}
|
||||
else if (strcmp(nameptr, ".dbg.natives") == 0)
|
||||
{
|
||||
plugin->debug.unpacked = false;
|
||||
}
|
||||
if (m_plugin.num_natives > 0) {
|
||||
m_plugin.natives = new sp_native_t[m_plugin.num_natives];
|
||||
|
||||
secptr++;
|
||||
sectnum++;
|
||||
}
|
||||
for (uint32_t i = 0; i < m_plugin.num_natives; i++) {
|
||||
m_plugin.natives[i].flags = 0;
|
||||
m_plugin.natives[i].pfn = InvalidNative;
|
||||
m_plugin.natives[i].status = SP_NATIVE_UNBOUND;
|
||||
m_plugin.natives[i].user = NULL;
|
||||
m_plugin.natives[i].name = m_plugin.stringbase + natives[i].name;
|
||||
}
|
||||
}
|
||||
} else if (!(m_plugin.debug.files) && !strcmp(nameptr, ".dbg.files")) {
|
||||
m_plugin.debug.files = (sp_fdbg_file_t *)(base + secptr->dataoffs);
|
||||
} else if (!(m_plugin.debug.lines) && !strcmp(nameptr, ".dbg.lines")) {
|
||||
m_plugin.debug.lines = (sp_fdbg_line_t *)(base + secptr->dataoffs);
|
||||
} else if (!(m_plugin.debug.symbols) && !strcmp(nameptr, ".dbg.symbols")) {
|
||||
m_plugin.debug.symbols = (sp_fdbg_symbol_t *)(base + secptr->dataoffs);
|
||||
} else if (!(m_plugin.debug.lines_num) && !strcmp(nameptr, ".dbg.info")) {
|
||||
sp_fdbg_info_t *inf = (sp_fdbg_info_t *)(base + secptr->dataoffs);
|
||||
m_plugin.debug.files_num = inf->num_files;
|
||||
m_plugin.debug.lines_num = inf->num_lines;
|
||||
m_plugin.debug.syms_num = inf->num_syms;
|
||||
} else if (!(m_plugin.debug.stringbase) && !strcmp(nameptr, ".dbg.strings")) {
|
||||
m_plugin.debug.stringbase = (const char *)(base + secptr->dataoffs);
|
||||
} else if (strcmp(nameptr, ".dbg.natives") == 0) {
|
||||
m_plugin.debug.unpacked = false;
|
||||
}
|
||||
|
||||
if (plugin->pcode == NULL || plugin->data == NULL)
|
||||
{
|
||||
return SP_ERROR_FILE_FORMAT;
|
||||
}
|
||||
secptr++;
|
||||
sectnum++;
|
||||
}
|
||||
|
||||
if ((plugin->flags & SP_FLAG_DEBUG) && (
|
||||
!(plugin->debug.files) ||
|
||||
!(plugin->debug.lines) ||
|
||||
!(plugin->debug.symbols) ||
|
||||
!(plugin->debug.stringbase) ))
|
||||
{
|
||||
return SP_ERROR_FILE_FORMAT;
|
||||
}
|
||||
if (m_plugin.pcode == NULL || m_plugin.data == NULL)
|
||||
return SP_ERROR_FILE_FORMAT;
|
||||
|
||||
if (m_pPlugin->num_publics > 0)
|
||||
{
|
||||
m_PubFuncs = new CFunction *[m_pPlugin->num_publics];
|
||||
memset(m_PubFuncs, 0, sizeof(CFunction *) * m_pPlugin->num_publics);
|
||||
m_PubJitFuncs = new JitFunction *[m_pPlugin->num_publics];
|
||||
memset(m_PubJitFuncs, 0, sizeof(JitFunction *) * m_pPlugin->num_publics);
|
||||
}
|
||||
if ((m_plugin.flags & SP_FLAG_DEBUG) && (
|
||||
!(m_plugin.debug.files) ||
|
||||
!(m_plugin.debug.lines) ||
|
||||
!(m_plugin.debug.symbols) ||
|
||||
!(m_plugin.debug.stringbase) ))
|
||||
{
|
||||
return SP_ERROR_FILE_FORMAT;
|
||||
}
|
||||
|
||||
MD5 md5_pcode;
|
||||
md5_pcode.update(plugin->pcode, plugin->pcode_size);
|
||||
md5_pcode.finalize();
|
||||
md5_pcode.raw_digest(m_CodeHash);
|
||||
|
||||
MD5 md5_data;
|
||||
md5_data.update(plugin->data, plugin->data_size);
|
||||
md5_data.finalize();
|
||||
md5_data.raw_digest(m_DataHash);
|
||||
if (m_plugin.num_publics > 0) {
|
||||
m_PubFuncs = new CFunction *[m_plugin.num_publics];
|
||||
memset(m_PubFuncs, 0, sizeof(CFunction *) * m_plugin.num_publics);
|
||||
m_PubJitFuncs = new JitFunction *[m_plugin.num_publics];
|
||||
memset(m_PubJitFuncs, 0, sizeof(JitFunction *) * m_plugin.num_publics);
|
||||
}
|
||||
|
||||
m_pPlugin->profiler = g_engine2.GetProfiler();
|
||||
m_pCtx = new BaseContext(this);
|
||||
m_pCo = g_Jit.StartCompilation(this);
|
||||
MD5 md5_pcode;
|
||||
md5_pcode.update(m_plugin.pcode, m_plugin.pcode_size);
|
||||
md5_pcode.finalize();
|
||||
md5_pcode.raw_digest(m_CodeHash);
|
||||
|
||||
MD5 md5_data;
|
||||
md5_data.update(m_plugin.data, m_plugin.data_size);
|
||||
md5_data.finalize();
|
||||
md5_data.raw_digest(m_DataHash);
|
||||
|
||||
return SP_ERROR_NONE;
|
||||
m_plugin.profiler = g_engine2.GetProfiler();
|
||||
m_pCtx = new BaseContext(this);
|
||||
co_ = g_Jit.StartCompilation(this);
|
||||
|
||||
SetupFloatNativeRemapping();
|
||||
function_map_size_ = m_plugin.pcode_size / sizeof(cell_t) + 1;
|
||||
function_map_ = new JitFunction *[function_map_size_];
|
||||
memset(function_map_, 0, function_map_size_ * sizeof(JitFunction *));
|
||||
|
||||
return SP_ERROR_NONE;
|
||||
}
|
||||
|
||||
int BaseRuntime::FindNativeByName(const char *name, uint32_t *index)
|
||||
void
|
||||
BaseRuntime::AddJittedFunction(JitFunction *fn)
|
||||
{
|
||||
int high;
|
||||
m_JitFunctions.append(fn);
|
||||
|
||||
high = m_pPlugin->num_natives - 1;
|
||||
cell_t pcode_offset = fn->GetPCodeAddress();
|
||||
assert(pcode_offset % 4 == 0);
|
||||
|
||||
for (uint32_t i=0; i<m_pPlugin->num_natives; i++)
|
||||
{
|
||||
if (strcmp(m_pPlugin->natives[i].name, name) == 0)
|
||||
{
|
||||
if (index)
|
||||
{
|
||||
*index = i;
|
||||
}
|
||||
return SP_ERROR_NONE;
|
||||
}
|
||||
}
|
||||
uint32_t pcode_index = pcode_offset / 4;
|
||||
assert(pcode_index < function_map_size_);
|
||||
|
||||
return SP_ERROR_NOT_FOUND;
|
||||
function_map_[pcode_index] = fn;
|
||||
}
|
||||
|
||||
int BaseRuntime::GetNativeByIndex(uint32_t index, sp_native_t **native)
|
||||
JitFunction *
|
||||
BaseRuntime::GetJittedFunctionByOffset(cell_t pcode_offset)
|
||||
{
|
||||
if (index >= m_pPlugin->num_natives)
|
||||
{
|
||||
return SP_ERROR_INDEX;
|
||||
}
|
||||
assert(pcode_offset % 4 == 0);
|
||||
|
||||
if (native)
|
||||
{
|
||||
*native = &(m_pPlugin->natives[index]);
|
||||
}
|
||||
uint32_t pcode_index = pcode_offset / 4;
|
||||
assert(pcode_index < function_map_size_);
|
||||
|
||||
return SP_ERROR_NONE;
|
||||
return function_map_[pcode_index];
|
||||
}
|
||||
|
||||
int
|
||||
BaseRuntime::FindNativeByName(const char *name, uint32_t *index)
|
||||
{
|
||||
for (uint32_t i=0; i<m_plugin.num_natives; i++) {
|
||||
if (strcmp(m_plugin.natives[i].name, name) == 0) {
|
||||
if (index)
|
||||
*index = i;
|
||||
return SP_ERROR_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
return SP_ERROR_NOT_FOUND;
|
||||
}
|
||||
|
||||
int
|
||||
BaseRuntime::GetNativeByIndex(uint32_t index, sp_native_t **native)
|
||||
{
|
||||
if (index >= m_plugin.num_natives)
|
||||
return SP_ERROR_INDEX;
|
||||
|
||||
if (native)
|
||||
*native = &(m_plugin.natives[index]);
|
||||
|
||||
return SP_ERROR_NONE;
|
||||
}
|
||||
|
||||
|
||||
uint32_t BaseRuntime::GetNativesNum()
|
||||
uint32_t
|
||||
BaseRuntime::GetNativesNum()
|
||||
{
|
||||
return m_pPlugin->num_natives;
|
||||
return m_plugin.num_natives;
|
||||
}
|
||||
|
||||
int BaseRuntime::FindPublicByName(const char *name, uint32_t *index)
|
||||
int
|
||||
BaseRuntime::FindPublicByName(const char *name, uint32_t *index)
|
||||
{
|
||||
int diff, high, low;
|
||||
uint32_t mid;
|
||||
int diff, high, low;
|
||||
uint32_t mid;
|
||||
|
||||
high = m_pPlugin->num_publics - 1;
|
||||
low = 0;
|
||||
high = m_plugin.num_publics - 1;
|
||||
low = 0;
|
||||
|
||||
while (low <= high)
|
||||
{
|
||||
mid = (low + high) / 2;
|
||||
diff = strcmp(m_pPlugin->publics[mid].name, name);
|
||||
if (diff == 0)
|
||||
{
|
||||
if (index)
|
||||
{
|
||||
*index = mid;
|
||||
}
|
||||
return SP_ERROR_NONE;
|
||||
} else if (diff < 0) {
|
||||
low = mid + 1;
|
||||
} else {
|
||||
high = mid - 1;
|
||||
}
|
||||
}
|
||||
while (low <= high) {
|
||||
mid = (low + high) / 2;
|
||||
diff = strcmp(m_plugin.publics[mid].name, name);
|
||||
if (diff == 0) {
|
||||
if (index)
|
||||
*index = mid;
|
||||
return SP_ERROR_NONE;
|
||||
} else if (diff < 0) {
|
||||
low = mid + 1;
|
||||
} else {
|
||||
high = mid - 1;
|
||||
}
|
||||
}
|
||||
|
||||
return SP_ERROR_NOT_FOUND;
|
||||
return SP_ERROR_NOT_FOUND;
|
||||
}
|
||||
|
||||
int BaseRuntime::GetPublicByIndex(uint32_t index, sp_public_t **pblic)
|
||||
int
|
||||
BaseRuntime::GetPublicByIndex(uint32_t index, sp_public_t **pblic)
|
||||
{
|
||||
if (index >= m_pPlugin->num_publics)
|
||||
{
|
||||
return SP_ERROR_INDEX;
|
||||
}
|
||||
if (index >= m_plugin.num_publics)
|
||||
return SP_ERROR_INDEX;
|
||||
|
||||
if (pblic)
|
||||
{
|
||||
*pblic = &(m_pPlugin->publics[index]);
|
||||
}
|
||||
if (pblic)
|
||||
*pblic = &(m_plugin.publics[index]);
|
||||
|
||||
return SP_ERROR_NONE;
|
||||
return SP_ERROR_NONE;
|
||||
}
|
||||
|
||||
uint32_t BaseRuntime::GetPublicsNum()
|
||||
uint32_t
|
||||
BaseRuntime::GetPublicsNum()
|
||||
{
|
||||
return m_pPlugin->num_publics;
|
||||
return m_plugin.num_publics;
|
||||
}
|
||||
|
||||
int BaseRuntime::GetPubvarByIndex(uint32_t index, sp_pubvar_t **pubvar)
|
||||
int
|
||||
BaseRuntime::GetPubvarByIndex(uint32_t index, sp_pubvar_t **pubvar)
|
||||
{
|
||||
if (index >= m_pPlugin->num_pubvars)
|
||||
{
|
||||
return SP_ERROR_INDEX;
|
||||
}
|
||||
if (index >= m_plugin.num_pubvars)
|
||||
return SP_ERROR_INDEX;
|
||||
|
||||
if (pubvar)
|
||||
{
|
||||
*pubvar = &(m_pPlugin->pubvars[index]);
|
||||
}
|
||||
if (pubvar)
|
||||
*pubvar = &(m_plugin.pubvars[index]);
|
||||
|
||||
return SP_ERROR_NONE;
|
||||
return SP_ERROR_NONE;
|
||||
}
|
||||
|
||||
int BaseRuntime::FindPubvarByName(const char *name, uint32_t *index)
|
||||
int
|
||||
BaseRuntime::FindPubvarByName(const char *name, uint32_t *index)
|
||||
{
|
||||
int diff, high, low;
|
||||
uint32_t mid;
|
||||
int diff, high, low;
|
||||
uint32_t mid;
|
||||
|
||||
high = m_pPlugin->num_pubvars - 1;
|
||||
low = 0;
|
||||
high = m_plugin.num_pubvars - 1;
|
||||
low = 0;
|
||||
|
||||
while (low <= high)
|
||||
{
|
||||
mid = (low + high) / 2;
|
||||
diff = strcmp(m_pPlugin->pubvars[mid].name, name);
|
||||
if (diff == 0)
|
||||
{
|
||||
if (index)
|
||||
{
|
||||
*index = mid;
|
||||
}
|
||||
return SP_ERROR_NONE;
|
||||
}
|
||||
else if (diff < 0)
|
||||
{
|
||||
low = mid + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
high = mid - 1;
|
||||
}
|
||||
}
|
||||
while (low <= high) {
|
||||
mid = (low + high) / 2;
|
||||
diff = strcmp(m_plugin.pubvars[mid].name, name);
|
||||
if (diff == 0) {
|
||||
if (index)
|
||||
*index = mid;
|
||||
return SP_ERROR_NONE;
|
||||
} else if (diff < 0) {
|
||||
low = mid + 1;
|
||||
} else {
|
||||
high = mid - 1;
|
||||
}
|
||||
}
|
||||
|
||||
return SP_ERROR_NOT_FOUND;
|
||||
return SP_ERROR_NOT_FOUND;
|
||||
}
|
||||
|
||||
int BaseRuntime::GetPubvarAddrs(uint32_t index, cell_t *local_addr, cell_t **phys_addr)
|
||||
int
|
||||
BaseRuntime::GetPubvarAddrs(uint32_t index, cell_t *local_addr, cell_t **phys_addr)
|
||||
{
|
||||
if (index >= m_pPlugin->num_pubvars)
|
||||
{
|
||||
return SP_ERROR_INDEX;
|
||||
}
|
||||
if (index >= m_plugin.num_pubvars)
|
||||
return SP_ERROR_INDEX;
|
||||
|
||||
*local_addr = (uint8_t *)m_pPlugin->pubvars[index].offs - m_pPlugin->memory;
|
||||
*phys_addr = m_pPlugin->pubvars[index].offs;
|
||||
*local_addr = (uint8_t *)m_plugin.pubvars[index].offs - m_plugin.memory;
|
||||
*phys_addr = m_plugin.pubvars[index].offs;
|
||||
|
||||
return SP_ERROR_NONE;
|
||||
return SP_ERROR_NONE;
|
||||
}
|
||||
|
||||
uint32_t BaseRuntime::GetPubVarsNum()
|
||||
uint32_t
|
||||
BaseRuntime::GetPubVarsNum()
|
||||
{
|
||||
return m_pPlugin->num_pubvars;
|
||||
return m_plugin.num_pubvars;
|
||||
}
|
||||
|
||||
IPluginContext *BaseRuntime::GetDefaultContext()
|
||||
IPluginContext *
|
||||
BaseRuntime::GetDefaultContext()
|
||||
{
|
||||
return m_pCtx;
|
||||
return m_pCtx;
|
||||
}
|
||||
|
||||
IPluginDebugInfo *BaseRuntime::GetDebugInfo()
|
||||
IPluginDebugInfo *
|
||||
BaseRuntime::GetDebugInfo()
|
||||
{
|
||||
return &m_Debug;
|
||||
return &m_Debug;
|
||||
}
|
||||
|
||||
IPluginFunction *BaseRuntime::GetFunctionById(funcid_t func_id)
|
||||
IPluginFunction *
|
||||
BaseRuntime::GetFunctionById(funcid_t func_id)
|
||||
{
|
||||
CFunction *pFunc = NULL;
|
||||
CFunction *pFunc = NULL;
|
||||
|
||||
if (func_id & 1)
|
||||
{
|
||||
func_id >>= 1;
|
||||
if (func_id >= m_pPlugin->num_publics)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
pFunc = m_PubFuncs[func_id];
|
||||
if (!pFunc)
|
||||
{
|
||||
m_PubFuncs[func_id] = new CFunction(this,
|
||||
(func_id << 1) | 1,
|
||||
func_id);
|
||||
pFunc = m_PubFuncs[func_id];
|
||||
}
|
||||
}
|
||||
if (func_id & 1) {
|
||||
func_id >>= 1;
|
||||
if (func_id >= m_plugin.num_publics)
|
||||
return NULL;
|
||||
pFunc = m_PubFuncs[func_id];
|
||||
if (!pFunc) {
|
||||
m_PubFuncs[func_id] = new CFunction(this,
|
||||
(func_id << 1) | 1,
|
||||
func_id);
|
||||
pFunc = m_PubFuncs[func_id];
|
||||
}
|
||||
}
|
||||
|
||||
return pFunc;
|
||||
return pFunc;
|
||||
}
|
||||
|
||||
IPluginFunction *BaseRuntime::GetFunctionByName(const char *public_name)
|
||||
IPluginFunction *
|
||||
BaseRuntime::GetFunctionByName(const char *public_name)
|
||||
{
|
||||
uint32_t index;
|
||||
uint32_t index;
|
||||
|
||||
if (FindPublicByName(public_name, &index) != SP_ERROR_NONE)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
if (FindPublicByName(public_name, &index) != SP_ERROR_NONE)
|
||||
return NULL;
|
||||
|
||||
CFunction *pFunc = m_PubFuncs[index];
|
||||
if (!pFunc)
|
||||
{
|
||||
sp_public_t *pub = NULL;
|
||||
GetPublicByIndex(index, &pub);
|
||||
if (pub)
|
||||
{
|
||||
m_PubFuncs[index] = new CFunction(this, (index << 1) | 1, index);
|
||||
}
|
||||
pFunc = m_PubFuncs[index];
|
||||
}
|
||||
CFunction *pFunc = m_PubFuncs[index];
|
||||
if (!pFunc) {
|
||||
sp_public_t *pub = NULL;
|
||||
GetPublicByIndex(index, &pub);
|
||||
if (pub)
|
||||
m_PubFuncs[index] = new CFunction(this, (index << 1) | 1, index);
|
||||
pFunc = m_PubFuncs[index];
|
||||
}
|
||||
|
||||
return pFunc;
|
||||
return pFunc;
|
||||
}
|
||||
|
||||
bool BaseRuntime::IsDebugging()
|
||||
{
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void BaseRuntime::SetPauseState(bool paused)
|
||||
{
|
||||
if (paused)
|
||||
{
|
||||
m_pPlugin->run_flags |= SPFLAG_PLUGIN_PAUSED;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pPlugin->run_flags &= ~SPFLAG_PLUGIN_PAUSED;
|
||||
}
|
||||
if (paused)
|
||||
{
|
||||
m_plugin.run_flags |= SPFLAG_PLUGIN_PAUSED;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_plugin.run_flags &= ~SPFLAG_PLUGIN_PAUSED;
|
||||
}
|
||||
}
|
||||
|
||||
bool BaseRuntime::IsPaused()
|
||||
{
|
||||
return ((m_pPlugin->run_flags & SPFLAG_PLUGIN_PAUSED) == SPFLAG_PLUGIN_PAUSED);
|
||||
return ((m_plugin.run_flags & SPFLAG_PLUGIN_PAUSED) == SPFLAG_PLUGIN_PAUSED);
|
||||
}
|
||||
|
||||
size_t BaseRuntime::GetMemUsage()
|
||||
{
|
||||
size_t mem = 0;
|
||||
size_t mem = 0;
|
||||
|
||||
mem += sizeof(this);
|
||||
mem += sizeof(sp_plugin_t);
|
||||
mem += sizeof(BaseContext);
|
||||
mem += m_pPlugin->base_size;
|
||||
mem += sizeof(this);
|
||||
mem += sizeof(sp_plugin_t);
|
||||
mem += sizeof(BaseContext);
|
||||
mem += m_plugin.base_size;
|
||||
|
||||
return mem;
|
||||
return mem;
|
||||
}
|
||||
|
||||
unsigned char *BaseRuntime::GetCodeHash()
|
||||
{
|
||||
return m_CodeHash;
|
||||
return m_CodeHash;
|
||||
}
|
||||
|
||||
unsigned char *BaseRuntime::GetDataHash()
|
||||
{
|
||||
return m_DataHash;
|
||||
return m_DataHash;
|
||||
}
|
||||
|
||||
BaseContext *BaseRuntime::GetBaseContext()
|
||||
{
|
||||
return m_pCtx;
|
||||
return m_pCtx;
|
||||
}
|
||||
|
||||
int BaseRuntime::ApplyCompilationOptions(ICompilation *co)
|
||||
int
|
||||
BaseRuntime::ApplyCompilationOptions(ICompilation *co)
|
||||
{
|
||||
if (co == NULL)
|
||||
{
|
||||
return SP_ERROR_NONE;
|
||||
}
|
||||
if (co == NULL)
|
||||
return SP_ERROR_NONE;
|
||||
|
||||
m_pCo = g_Jit.ApplyOptions(m_pCo, co);
|
||||
m_pPlugin->prof_flags = ((CompData *)m_pCo)->profile;
|
||||
co_ = g_Jit.ApplyOptions(co_, co);
|
||||
m_plugin.prof_flags = ((CompData *)co_)->profile;
|
||||
|
||||
return SP_ERROR_NONE;
|
||||
return SP_ERROR_NONE;
|
||||
}
|
||||
|
||||
JitFunction *BaseRuntime::GetJittedFunction(uint32_t idx)
|
||||
int
|
||||
BaseRuntime::CreateBlank(uint32_t heastk)
|
||||
{
|
||||
assert(idx <= m_NumFuncs);
|
||||
memset(&m_plugin, 0, sizeof(m_plugin));
|
||||
|
||||
if (idx == 0 || idx > m_NumFuncs)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
/* Align to cell_t bytes */
|
||||
heastk += sizeof(cell_t);
|
||||
heastk -= heastk % sizeof(cell_t);
|
||||
|
||||
return m_FuncCache[idx - 1];
|
||||
}
|
||||
|
||||
uint32_t BaseRuntime::AddJittedFunction(JitFunction *fn)
|
||||
{
|
||||
if (m_NumFuncs + 1 > m_MaxFuncs)
|
||||
{
|
||||
if (m_MaxFuncs == 0)
|
||||
{
|
||||
m_MaxFuncs = 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_MaxFuncs *= 2;
|
||||
}
|
||||
|
||||
m_FuncCache = (JitFunction **)realloc(
|
||||
m_FuncCache,
|
||||
sizeof(JitFunction *) * m_MaxFuncs);
|
||||
}
|
||||
|
||||
m_FuncCache[m_NumFuncs++] = fn;
|
||||
|
||||
return m_NumFuncs;
|
||||
}
|
||||
|
||||
int BaseRuntime::CreateBlank(uint32_t heastk)
|
||||
{
|
||||
memset(m_pPlugin, 0, sizeof(sp_plugin_t));
|
||||
|
||||
/* Align to cell_t bytes */
|
||||
heastk += sizeof(cell_t);
|
||||
heastk -= heastk % sizeof(cell_t);
|
||||
|
||||
m_pPlugin->mem_size = heastk;
|
||||
m_pPlugin->memory = new uint8_t[heastk];
|
||||
|
||||
m_pPlugin->profiler = g_engine2.GetProfiler();
|
||||
m_pCtx = new BaseContext(this);
|
||||
m_pCo = g_Jit.StartCompilation(this);
|
||||
|
||||
return SP_ERROR_NONE;
|
||||
m_plugin.mem_size = heastk;
|
||||
m_plugin.memory = new uint8_t[heastk];
|
||||
|
||||
m_plugin.profiler = g_engine2.GetProfiler();
|
||||
m_pCtx = new BaseContext(this);
|
||||
co_ = g_Jit.StartCompilation(this);
|
||||
|
||||
return SP_ERROR_NONE;
|
||||
}
|
||||
|
@ -1,7 +1,9 @@
|
||||
// vim: set ts=8 sw=2 sts=2 tw=99 et:
|
||||
#ifndef _INCLUDE_SOURCEPAWN_JIT_RUNTIME_H_
|
||||
#define _INCLUDE_SOURCEPAWN_JIT_RUNTIME_H_
|
||||
|
||||
#include <sp_vm_api.h>
|
||||
#include <ke_vector.h>
|
||||
#include "jit_shared.h"
|
||||
#include "sp_vm_function.h"
|
||||
|
||||
@ -11,65 +13,93 @@ class JitFunction;
|
||||
class DebugInfo : public IPluginDebugInfo
|
||||
{
|
||||
public:
|
||||
DebugInfo(sp_plugin_t *plugin);
|
||||
DebugInfo(sp_plugin_t *plugin);
|
||||
public:
|
||||
int LookupFile(ucell_t addr, const char **filename);
|
||||
int LookupFunction(ucell_t addr, const char **name);
|
||||
int LookupLine(ucell_t addr, uint32_t *line);
|
||||
int LookupFile(ucell_t addr, const char **filename);
|
||||
int LookupFunction(ucell_t addr, const char **name);
|
||||
int LookupLine(ucell_t addr, uint32_t *line);
|
||||
private:
|
||||
sp_plugin_t *m_pPlugin;
|
||||
sp_plugin_t *m_pPlugin;
|
||||
};
|
||||
|
||||
struct floattbl_t
|
||||
{
|
||||
floattbl_t() {
|
||||
found = false;
|
||||
index = 0;
|
||||
}
|
||||
bool found;
|
||||
unsigned int index;
|
||||
};
|
||||
|
||||
/* Jit wants fast access to this so we expose things as public */
|
||||
class BaseRuntime : public SourcePawn::IPluginRuntime
|
||||
{
|
||||
public:
|
||||
BaseRuntime();
|
||||
~BaseRuntime();
|
||||
public:
|
||||
virtual int CreateBlank(uint32_t heastk);
|
||||
virtual int CreateFromMemory(sp_file_hdr_t *hdr, uint8_t *base);
|
||||
virtual bool IsDebugging();
|
||||
virtual IPluginDebugInfo *GetDebugInfo();
|
||||
virtual int FindNativeByName(const char *name, uint32_t *index);
|
||||
virtual int GetNativeByIndex(uint32_t index, sp_native_t **native);
|
||||
virtual uint32_t GetNativesNum();
|
||||
virtual int FindPublicByName(const char *name, uint32_t *index);
|
||||
virtual int GetPublicByIndex(uint32_t index, sp_public_t **publicptr);
|
||||
virtual uint32_t GetPublicsNum();
|
||||
virtual int GetPubvarByIndex(uint32_t index, sp_pubvar_t **pubvar);
|
||||
virtual int FindPubvarByName(const char *name, uint32_t *index);
|
||||
virtual int GetPubvarAddrs(uint32_t index, cell_t *local_addr, cell_t **phys_addr);
|
||||
virtual uint32_t GetPubVarsNum();
|
||||
virtual IPluginFunction *GetFunctionByName(const char *public_name);
|
||||
virtual IPluginFunction *GetFunctionById(funcid_t func_id);
|
||||
virtual IPluginContext *GetDefaultContext();
|
||||
virtual int ApplyCompilationOptions(ICompilation *co);
|
||||
virtual void SetPauseState(bool paused);
|
||||
virtual bool IsPaused();
|
||||
virtual size_t GetMemUsage();
|
||||
virtual unsigned char *GetCodeHash();
|
||||
virtual unsigned char *GetDataHash();
|
||||
JitFunction *GetJittedFunction(uint32_t idx);
|
||||
uint32_t AddJittedFunction(JitFunction *fn);
|
||||
public:
|
||||
BaseContext *GetBaseContext();
|
||||
private:
|
||||
sp_plugin_t m_plugin;
|
||||
unsigned int m_NumFuncs;
|
||||
unsigned int m_MaxFuncs;
|
||||
JitFunction **m_FuncCache;
|
||||
public:
|
||||
DebugInfo m_Debug;
|
||||
sp_plugin_t *m_pPlugin;
|
||||
BaseContext *m_pCtx;
|
||||
CFunction **m_PubFuncs;
|
||||
JitFunction **m_PubJitFuncs;
|
||||
ICompilation *m_pCo;
|
||||
unsigned int m_CompSerial;
|
||||
|
||||
unsigned char m_CodeHash[16];
|
||||
unsigned char m_DataHash[16];
|
||||
public:
|
||||
BaseRuntime();
|
||||
~BaseRuntime();
|
||||
|
||||
public:
|
||||
virtual int CreateBlank(uint32_t heastk);
|
||||
virtual int CreateFromMemory(sp_file_hdr_t *hdr, uint8_t *base);
|
||||
virtual bool IsDebugging();
|
||||
virtual IPluginDebugInfo *GetDebugInfo();
|
||||
virtual int FindNativeByName(const char *name, uint32_t *index);
|
||||
virtual int GetNativeByIndex(uint32_t index, sp_native_t **native);
|
||||
virtual uint32_t GetNativesNum();
|
||||
virtual int FindPublicByName(const char *name, uint32_t *index);
|
||||
virtual int GetPublicByIndex(uint32_t index, sp_public_t **publicptr);
|
||||
virtual uint32_t GetPublicsNum();
|
||||
virtual int GetPubvarByIndex(uint32_t index, sp_pubvar_t **pubvar);
|
||||
virtual int FindPubvarByName(const char *name, uint32_t *index);
|
||||
virtual int GetPubvarAddrs(uint32_t index, cell_t *local_addr, cell_t **phys_addr);
|
||||
virtual uint32_t GetPubVarsNum();
|
||||
virtual IPluginFunction *GetFunctionByName(const char *public_name);
|
||||
virtual IPluginFunction *GetFunctionById(funcid_t func_id);
|
||||
virtual IPluginContext *GetDefaultContext();
|
||||
virtual int ApplyCompilationOptions(ICompilation *co);
|
||||
virtual void SetPauseState(bool paused);
|
||||
virtual bool IsPaused();
|
||||
virtual size_t GetMemUsage();
|
||||
virtual unsigned char *GetCodeHash();
|
||||
virtual unsigned char *GetDataHash();
|
||||
JitFunction *GetJittedFunctionByOffset(cell_t pcode_offset);
|
||||
void AddJittedFunction(JitFunction *fn);
|
||||
void SetName(const char *name);
|
||||
unsigned GetNativeReplacement(size_t index);
|
||||
|
||||
BaseContext *GetBaseContext();
|
||||
const sp_plugin_t *plugin() const {
|
||||
return &m_plugin;
|
||||
}
|
||||
|
||||
private:
|
||||
void SetupFloatNativeRemapping();
|
||||
|
||||
private:
|
||||
sp_plugin_t m_plugin;
|
||||
uint8_t *alt_pcode_;
|
||||
unsigned int m_NumFuncs;
|
||||
unsigned int m_MaxFuncs;
|
||||
floattbl_t *float_table_;
|
||||
JitFunction **function_map_;
|
||||
size_t function_map_size_;
|
||||
ke::Vector<JitFunction *> m_JitFunctions;
|
||||
|
||||
public:
|
||||
DebugInfo m_Debug;
|
||||
BaseContext *m_pCtx;
|
||||
CFunction **m_PubFuncs;
|
||||
JitFunction **m_PubJitFuncs;
|
||||
|
||||
private:
|
||||
ICompilation *co_;
|
||||
|
||||
public:
|
||||
unsigned int m_CompSerial;
|
||||
|
||||
unsigned char m_CodeHash[16];
|
||||
unsigned char m_DataHash[16];
|
||||
};
|
||||
|
||||
#endif //_INCLUDE_SOURCEPAWN_JIT_RUNTIME_H_
|
||||
|
@ -12,12 +12,12 @@ PROJECT = sourcepawn.jit.x86
|
||||
|
||||
OBJECTS = dll_exports.cpp \
|
||||
x86/jit_x86.cpp \
|
||||
x86/opcode_helpers.cpp \
|
||||
sp_vm_basecontext.cpp \
|
||||
sp_vm_engine.cpp \
|
||||
sp_vm_function.cpp \
|
||||
engine2.cpp \
|
||||
BaseRuntime.cpp \
|
||||
opcodes.cpp \
|
||||
jit_function.cpp \
|
||||
md5/md5.cpp \
|
||||
zlib/adler32.c \
|
||||
|
111
sourcepawn/jit/Makefile.shell
Normal file
111
sourcepawn/jit/Makefile.shell
Normal file
@ -0,0 +1,111 @@
|
||||
# (C)2004-2008 SourceMod Development Team
|
||||
# Makefile written by David "BAILOPAN" Anderson
|
||||
|
||||
SMSDK = ../..
|
||||
MMSOURCE17 = ../../../mmsource-1.7
|
||||
|
||||
#####################################
|
||||
### EDIT BELOW FOR OTHER PROJECTS ###
|
||||
#####################################
|
||||
|
||||
PROJECT = spshell
|
||||
|
||||
OBJECTS = dll_exports.cpp \
|
||||
x86/jit_x86.cpp \
|
||||
sp_vm_basecontext.cpp \
|
||||
sp_vm_engine.cpp \
|
||||
sp_vm_function.cpp \
|
||||
engine2.cpp \
|
||||
BaseRuntime.cpp \
|
||||
jit_function.cpp \
|
||||
opcodes.cpp \
|
||||
md5/md5.cpp \
|
||||
zlib/adler32.c \
|
||||
zlib/compress.c \
|
||||
zlib/crc32.c \
|
||||
zlib/deflate.c \
|
||||
zlib/gzio.c \
|
||||
zlib/infback.c \
|
||||
zlib/inffast.c \
|
||||
zlib/inflate.c \
|
||||
zlib/inftrees.c \
|
||||
zlib/trees.c \
|
||||
zlib/uncompr.c \
|
||||
zlib/zutil.c \
|
||||
|
||||
OBJECTS += ../../knight/shared/KeCodeAllocator.cpp
|
||||
|
||||
##############################################
|
||||
### CONFIGURE ANY OTHER FLAGS/OPTIONS HERE ###
|
||||
##############################################
|
||||
|
||||
C_OPT_FLAGS = -DNDEBUG -O3 -funroll-loops -pipe -fno-strict-aliasing
|
||||
C_DEBUG_FLAGS = -D_DEBUG -DDEBUG -g -ggdb3
|
||||
C_GCC4_FLAGS = -fvisibility=hidden
|
||||
CXX_GCC4_FLAGS = -fvisibility-inlines-hidden
|
||||
CXX = c++
|
||||
CC = cc
|
||||
|
||||
LINK = -m32 -lm
|
||||
|
||||
INCLUDE = -I. -I.. -I$(SMSDK)/public -I$(SMSDK)/public/jit -I$(SMSDK)/public/jit/x86 \
|
||||
-I$(SMSDK)/public/sourcepawn -I$(MMSOURCE17)/core/sourcehook -I$(SMSDK)/knight/shared -Ix86
|
||||
|
||||
CFLAGS += -D_LINUX -Dstricmp=strcasecmp -D_stricmp=strcasecmp -D_strnicmp=strncasecmp -Dstrnicmp=strncasecmp \
|
||||
-D_snprintf=snprintf -D_vsnprintf=vsnprintf -D_alloca=alloca -Dstrcmpi=strcasecmp -Wall -DHAVE_STDINT_H \
|
||||
-m32 -Wno-uninitialized -Werror -DSPSHELL -ggdb3 -Wno-unused
|
||||
CXXFLAGS += -Wno-non-virtual-dtor -fno-exceptions -fno-rtti -Wno-delete-non-virtual-dtor
|
||||
|
||||
################################################
|
||||
### DO NOT EDIT BELOW HERE FOR MOST PROJECTS ###
|
||||
################################################
|
||||
|
||||
ifeq "$(DEBUG)" "true"
|
||||
BIN_DIR = Debug.shell
|
||||
CFLAGS += $(C_DEBUG_FLAGS)
|
||||
else
|
||||
BIN_DIR = Release.shell
|
||||
CFLAGS += $(C_OPT_FLAGS)
|
||||
endif
|
||||
|
||||
GCC_VERSION := $(shell $(CXX) -dumpversion >&1 | cut -b1)
|
||||
ifeq "$(GCC_VERSION)" "4"
|
||||
CFLAGS += $(C_GCC4_FLAGS)
|
||||
CXXFLAGS += $(CXX_GCC4_FLAGS)
|
||||
endif
|
||||
|
||||
OBJ_LINUX := $(OBJECTS:../../knight/shared/%.cpp=$(BIN_DIR)/knight/%.o)
|
||||
OBJ_LINUX := $(OBJ_LINUX:%.cpp=$(BIN_DIR)/%.o)
|
||||
OBJ_LINUX := $(OBJ_LINUX:%.c=$(BIN_DIR)/%.o)
|
||||
|
||||
default: all
|
||||
|
||||
$(BIN_DIR)/%.o: %.c
|
||||
$(CC) $(INCLUDE) $(CFLAGS) -o $@ -c $<
|
||||
|
||||
$(BIN_DIR)/%.o: %.cpp
|
||||
$(CXX) $(INCLUDE) $(CFLAGS) $(CXXFLAGS) -o $@ -c $<
|
||||
|
||||
$(BIN_DIR)/knight/%.o: ../../knight/shared/%.cpp
|
||||
$(CXX) $(INCLUDE) $(CFLAGS) $(CXXFLAGS) -o $@ -c $<
|
||||
|
||||
all:
|
||||
mkdir -p $(BIN_DIR)/x86
|
||||
mkdir -p $(BIN_DIR)/md5
|
||||
mkdir -p $(BIN_DIR)/zlib
|
||||
mkdir -p $(BIN_DIR)/knight
|
||||
$(MAKE) -f Makefile.shell jit
|
||||
|
||||
jit: $(OBJ_LINUX)
|
||||
$(CXX) $(INCLUDE) $(OBJ_LINUX) $(LINK) -o $(BIN_DIR)/$(PROJECT)
|
||||
|
||||
debug:
|
||||
$(MAKE) -f Makefile.shell all DEBUG=true
|
||||
|
||||
clean:
|
||||
rm -f $(BIN_DIR)/x86/*.o
|
||||
# rm -rf $(BIN_DIR)/zlib/*.o
|
||||
# rm -rf $(BIN_DIR)/knight/*.o
|
||||
rm -f $(BIN_DIR)/*.o
|
||||
rm -f $(BIN_DIR)/$(PROJECT)
|
||||
|
@ -1,76 +1,263 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#include <sp_vm_api.h>
|
||||
#include <stdlib.h>
|
||||
#include "x86/jit_x86.h"
|
||||
#include "dll_exports.h"
|
||||
#include "sp_vm_engine.h"
|
||||
#include "engine2.h"
|
||||
|
||||
SourcePawnEngine2 g_engine2;
|
||||
|
||||
EXPORTFUNC ISourcePawnEngine *GetSourcePawnEngine1()
|
||||
{
|
||||
return &g_engine1;
|
||||
}
|
||||
|
||||
EXPORTFUNC ISourcePawnEngine2 *GetSourcePawnEngine2()
|
||||
{
|
||||
return &g_engine2;
|
||||
}
|
||||
|
||||
#if defined __linux__ || defined __APPLE__
|
||||
extern "C" void __cxa_pure_virtual(void)
|
||||
{
|
||||
}
|
||||
|
||||
void *operator new(size_t size)
|
||||
{
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
void *operator new[](size_t size)
|
||||
{
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
void operator delete(void *ptr)
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
void operator delete[](void * ptr)
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* vim: set ts=4 sts=4 sw=4 tw=99 noet:
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#include <sp_vm_api.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include "x86/jit_x86.h"
|
||||
#include "dll_exports.h"
|
||||
#include "sp_vm_engine.h"
|
||||
#include "engine2.h"
|
||||
|
||||
using namespace SourcePawn;
|
||||
|
||||
SourcePawnEngine2 g_engine2;
|
||||
|
||||
#ifdef SPSHELL
|
||||
template <typename T> class AutoT
|
||||
{
|
||||
public:
|
||||
AutoT(T *t)
|
||||
: t_(t)
|
||||
{
|
||||
}
|
||||
~AutoT()
|
||||
{
|
||||
delete t_;
|
||||
}
|
||||
|
||||
operator T *() const {
|
||||
return t_;
|
||||
}
|
||||
bool operator !() const {
|
||||
return !t_;
|
||||
}
|
||||
T * operator ->() const {
|
||||
return t_;
|
||||
}
|
||||
private:
|
||||
T *t_;
|
||||
};
|
||||
|
||||
class ShellDebugListener : public IDebugListener
|
||||
{
|
||||
public:
|
||||
void OnContextExecuteError(IPluginContext *ctx, IContextTrace *error) {
|
||||
int n_err = error->GetErrorCode();
|
||||
|
||||
if (n_err != SP_ERROR_NATIVE)
|
||||
{
|
||||
fprintf(stderr, "plugin error: %s\n", error->GetErrorString());
|
||||
}
|
||||
|
||||
if (const char *lastname = error->GetLastNative(NULL))
|
||||
{
|
||||
if (const char *custerr = error->GetCustomErrorString())
|
||||
{
|
||||
fprintf(stderr, "Native \"%s\" reported: %s", lastname, custerr);
|
||||
} else {
|
||||
fprintf(stderr, "Native \"%s\" encountered a generic error.", lastname);
|
||||
}
|
||||
}
|
||||
|
||||
if (!error->DebugInfoAvailable())
|
||||
{
|
||||
fprintf(stderr, "Debug info not available!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
CallStackInfo stk_info;
|
||||
int i = 0;
|
||||
fprintf(stderr, "Displaying call stack trace:\n");
|
||||
while (error->GetTraceInfo(&stk_info))
|
||||
{
|
||||
fprintf(stderr,
|
||||
" [%d] Line %d, %s::%s()",
|
||||
i++,
|
||||
stk_info.line,
|
||||
stk_info.filename,
|
||||
stk_info.function);
|
||||
}
|
||||
}
|
||||
|
||||
void OnDebugSpew(const char *msg, ...) {
|
||||
#if !defined(NDEBUG) && defined(DEBUG)
|
||||
va_list ap;
|
||||
va_start(ap, msg);
|
||||
vfprintf(stderr, msg, ap);
|
||||
va_end(ap);
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
static cell_t Print(IPluginContext *cx, const cell_t *params)
|
||||
{
|
||||
char *p;
|
||||
cx->LocalToString(params[1], &p);
|
||||
|
||||
return printf("%s", p);
|
||||
}
|
||||
|
||||
static cell_t PrintNum(IPluginContext *cx, const cell_t *params)
|
||||
{
|
||||
return printf("%d\n", params[1]);
|
||||
}
|
||||
|
||||
static cell_t PrintNums(IPluginContext *cx, const cell_t *params)
|
||||
{
|
||||
for (size_t i = 1; i <= size_t(params[0]); i++) {
|
||||
int err;
|
||||
cell_t *addr;
|
||||
if ((err = cx->LocalToPhysAddr(params[i], &addr)) != SP_ERROR_NONE)
|
||||
return cx->ThrowNativeErrorEx(err, "Could not read argument");
|
||||
fprintf(stdout, "%d", *addr);
|
||||
if (i != size_t(params[0]))
|
||||
fprintf(stdout, ", ");
|
||||
}
|
||||
fprintf(stdout, "\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void BindNative(IPluginRuntime *rt, const char *name, SPVM_NATIVE_FUNC fn)
|
||||
{
|
||||
int err;
|
||||
uint32_t index;
|
||||
if ((err = rt->FindNativeByName(name, &index)) != SP_ERROR_NONE)
|
||||
return;
|
||||
|
||||
sp_native_t *native;
|
||||
if (rt->GetNativeByIndex(index, &native) != SP_ERROR_NONE)
|
||||
return;
|
||||
|
||||
native->pfn = fn;
|
||||
native->status = SP_NATIVE_BOUND;
|
||||
}
|
||||
|
||||
static cell_t PrintFloat(IPluginContext *cx, const cell_t *params)
|
||||
{
|
||||
return printf("%f\n", sp_ctof(params[1]));
|
||||
}
|
||||
|
||||
static int Execute(const char *file)
|
||||
{
|
||||
ICompilation *co = g_engine2.StartCompilation();
|
||||
if (!co) {
|
||||
fprintf(stderr, "Could not create a compilation context\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int err;
|
||||
AutoT<IPluginRuntime> rt(g_engine2.LoadPlugin(co, file, &err));
|
||||
if (!rt) {
|
||||
fprintf(stderr, "Could not load plugin: %s\n", g_engine1.GetErrorString(err));
|
||||
return 1;
|
||||
}
|
||||
|
||||
BindNative(rt, "print", Print);
|
||||
BindNative(rt, "printnum", PrintNum);
|
||||
BindNative(rt, "printnums", PrintNums);
|
||||
BindNative(rt, "printfloat", PrintFloat);
|
||||
|
||||
IPluginFunction *fun = rt->GetFunctionByName("main");
|
||||
if (!fun)
|
||||
return 0;
|
||||
|
||||
IPluginContext *cx = rt->GetDefaultContext();
|
||||
|
||||
int result = fun->Execute2(cx, &err);
|
||||
if (err != SP_ERROR_NONE) {
|
||||
fprintf(stderr, "Error executing main(): %s\n", g_engine1.GetErrorString(err));
|
||||
return 1;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "Usage: <file>\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!g_engine2.Initialize()) {
|
||||
fprintf(stderr, "Could not initialize ISourcePawnEngine2\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
ShellDebugListener debug;
|
||||
g_engine1.SetDebugListener(&debug);
|
||||
|
||||
int errcode = Execute(argv[1]);
|
||||
|
||||
g_engine1.SetDebugListener(NULL);
|
||||
g_engine2.Shutdown();
|
||||
return errcode;
|
||||
}
|
||||
|
||||
#else
|
||||
EXPORTFUNC ISourcePawnEngine *GetSourcePawnEngine1()
|
||||
{
|
||||
return &g_engine1;
|
||||
}
|
||||
|
||||
EXPORTFUNC ISourcePawnEngine2 *GetSourcePawnEngine2()
|
||||
{
|
||||
return &g_engine2;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined __linux__ || defined __APPLE__
|
||||
extern "C" void __cxa_pure_virtual(void)
|
||||
{
|
||||
}
|
||||
|
||||
void *operator new(size_t size)
|
||||
{
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
void *operator new[](size_t size)
|
||||
{
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
void operator delete(void *ptr)
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
void operator delete[](void * ptr)
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -106,19 +106,19 @@ IPluginRuntime *SourcePawnEngine2::LoadPlugin(ICompilation *co, const char *file
|
||||
#endif
|
||||
)
|
||||
{
|
||||
pRuntime->m_pPlugin->name = strdup(&file[i+1]);
|
||||
pRuntime->SetName(&file[i+1]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (pRuntime->m_pPlugin->name == NULL)
|
||||
if (!pRuntime->plugin()->name)
|
||||
{
|
||||
pRuntime->m_pPlugin->name = strdup(file);
|
||||
pRuntime->SetName(file);
|
||||
}
|
||||
|
||||
pRuntime->ApplyCompilationOptions(co);
|
||||
|
||||
fclose(fp);
|
||||
fclose(fp);
|
||||
|
||||
return pRuntime;
|
||||
|
||||
@ -204,7 +204,7 @@ IPluginRuntime *SourcePawnEngine2::CreateEmptyRuntime(const char *name, uint32_t
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rt->m_pPlugin->name = strdup(name != NULL ? name : "<anonymous>");
|
||||
rt->SetName(name != NULL ? name : "<anonymous>");
|
||||
|
||||
rt->ApplyCompilationOptions(NULL);
|
||||
|
||||
|
137
sourcepawn/jit/opcodes.cpp
Normal file
137
sourcepawn/jit/opcodes.cpp
Normal file
@ -0,0 +1,137 @@
|
||||
/**
|
||||
* vim: set ts=8 sw=2 tw=99 sts=2 et:
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright _(C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License), version 3.0), as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful), but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not), see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception), AlliedModders LLC gives you permission to link the
|
||||
* code of this program _(as well as its derivative works) to "Half-Life 2)," the
|
||||
* "Source Engine)," the "SourcePawn JIT)," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally), AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions), found in LICENSE.txt _(as of this writing), version JULY-31-2007)),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
#include "opcodes.h"
|
||||
#include "jit_shared.h"
|
||||
|
||||
using namespace SourcePawn;
|
||||
|
||||
const char *OpcodeNames[] = {
|
||||
#define _(op, text) text,
|
||||
OPCODE_LIST(_)
|
||||
#undef _
|
||||
NULL
|
||||
};
|
||||
|
||||
void
|
||||
SourcePawn::SpewOpcode(const sp_plugin_t *plugin, cell_t *start, cell_t *cip)
|
||||
{
|
||||
fprintf(stdout, " [%05d:%04d]", cip - (cell_t *)plugin->pcode, cip - start);
|
||||
|
||||
if (*cip >= OPCODES_TOTAL) {
|
||||
fprintf(stdout, " unknown-opcode\n");
|
||||
return;
|
||||
}
|
||||
|
||||
OPCODE op = (OPCODE)*cip;
|
||||
fprintf(stdout, " %s ", OpcodeNames[op]);
|
||||
|
||||
switch (op) {
|
||||
case OP_PUSH_C:
|
||||
case OP_PUSH_ADR:
|
||||
case OP_SHL_C_PRI:
|
||||
case OP_SHL_C_ALT:
|
||||
case OP_SHR_C_PRI:
|
||||
case OP_SHR_C_ALT:
|
||||
case OP_ADD_C:
|
||||
case OP_SMUL_C:
|
||||
case OP_EQ_C_PRI:
|
||||
case OP_EQ_C_ALT:
|
||||
case OP_TRACKER_PUSH_C:
|
||||
case OP_STACK:
|
||||
case OP_PUSH_S:
|
||||
case OP_HEAP:
|
||||
case OP_GENARRAY:
|
||||
case OP_GENARRAY_Z:
|
||||
fprintf(stdout, "%d", cip[1]);
|
||||
break;
|
||||
|
||||
case OP_JUMP:
|
||||
case OP_JZER:
|
||||
case OP_JNZ:
|
||||
case OP_JEQ:
|
||||
case OP_JNEQ:
|
||||
case OP_JSLESS:
|
||||
case OP_JSGRTR:
|
||||
case OP_JSGEQ:
|
||||
case OP_JSLEQ:
|
||||
fprintf(stdout, "%05d:%04d",
|
||||
cip[1] / 4,
|
||||
((cell_t *)plugin->pcode + cip[1] / 4) - start);
|
||||
break;
|
||||
|
||||
case OP_SYSREQ_C:
|
||||
case OP_SYSREQ_N:
|
||||
{
|
||||
uint32_t index = cip[1];
|
||||
if (index < plugin->num_natives)
|
||||
fprintf(stdout, "%s", plugin->natives[index].name);
|
||||
if (op == OP_SYSREQ_N)
|
||||
fprintf(stdout, " ; (%d args, index %d)", cip[2], index);
|
||||
else
|
||||
fprintf(stdout, " ; (index %d)", index);
|
||||
break;
|
||||
}
|
||||
|
||||
case OP_PUSH2_C:
|
||||
case OP_PUSH2:
|
||||
case OP_PUSH2_S:
|
||||
case OP_PUSH2_ADR:
|
||||
fprintf(stdout, "%d, %d", cip[1], cip[2]);
|
||||
break;
|
||||
|
||||
case OP_PUSH3_C:
|
||||
case OP_PUSH3:
|
||||
case OP_PUSH3_S:
|
||||
case OP_PUSH3_ADR:
|
||||
fprintf(stdout, "%d, %d, %d", cip[1], cip[2], cip[3]);
|
||||
break;
|
||||
|
||||
case OP_PUSH4_C:
|
||||
case OP_PUSH4:
|
||||
case OP_PUSH4_S:
|
||||
case OP_PUSH4_ADR:
|
||||
fprintf(stdout, "%d, %d, %d, %d", cip[1], cip[2], cip[3], cip[4]);
|
||||
break;
|
||||
|
||||
case OP_PUSH5_C:
|
||||
case OP_PUSH5:
|
||||
case OP_PUSH5_S:
|
||||
case OP_PUSH5_ADR:
|
||||
fprintf(stdout, "%d, %d, %d, %d, %d", cip[1], cip[2], cip[3], cip[4], cip[5]);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
fprintf(stdout, "\n");
|
||||
}
|
||||
|
262
sourcepawn/jit/opcodes.h
Normal file
262
sourcepawn/jit/opcodes.h
Normal file
@ -0,0 +1,262 @@
|
||||
/**
|
||||
* vim: set ts=8 sw=2 tw=99 sts=2 et:
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License), version 3.0), as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful), but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not), see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception), AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2)," the
|
||||
* "Source Engine)," the "SourcePawn JIT)," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally), AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions), found in LICENSE.txt (as of this writing), version JULY-31-2007)),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_SOURCEPAWN_JIT_X86_OPCODES_H_
|
||||
#define _INCLUDE_SOURCEPAWN_JIT_X86_OPCODES_H_
|
||||
|
||||
#include <sp_vm_api.h>
|
||||
|
||||
// Opcodes labelled "UNGEN" cannot be generated by the compiler. Quite a few,
|
||||
// if they could, make little sense in the context of a JIT and could not
|
||||
// work anyway. Opcodes technically present in sc4.c/sc7.c (respectively,
|
||||
// the code emitter and peephole optimizer) are not necessarily ever generated.
|
||||
// For example, lref.pri and lref.alt would be used if a reference could be
|
||||
// stored in the global scope; but they can't, so they are unreachable.
|
||||
//
|
||||
// Most opcodes have been manually verified. A few have not, as they are only
|
||||
// produced by the peephole optimizer, or not produced at all, or eliminated
|
||||
// during optimization. We generate them anyway, just in case, but they have
|
||||
// not been tested.
|
||||
// lref.s.alt (phopt only)
|
||||
// stor.alt (never)
|
||||
// stor.s.alt (never)
|
||||
// sref.s.alt (never)
|
||||
// lidx.b (phopt only, probably impossible)
|
||||
// idxaddr.b (phopt only, looks difficult)
|
||||
// move.pri (eliminated in phopt)
|
||||
// shl.c.pri (eliminated in phopt)
|
||||
// shl.c.alt (eliminated in phopt)
|
||||
// shr.c.pri (eliminated in phopt)
|
||||
// shr.c.alt (eliminated in phopt)
|
||||
// eq.c.alt (never)
|
||||
// inc.alt (never)
|
||||
// dec.alt (never)
|
||||
// sdiv (never)
|
||||
// nop (never in function bodies)
|
||||
//
|
||||
// Additionally, some opcodes which were supported in the earlier JIT are no
|
||||
// longer supported because of the above:
|
||||
// lref.pri/alt
|
||||
// sref.pri/alt
|
||||
// sign.pri/alt
|
||||
|
||||
#define OPCODE_LIST(_) \
|
||||
_(NONE, "none") \
|
||||
_(LOAD_PRI, "load.pri") \
|
||||
_(LOAD_ALT, "load.alt") \
|
||||
_(LOAD_S_PRI, "load.s.pri") \
|
||||
_(LOAD_S_ALT, "load.s.alt") \
|
||||
_(UNGEN_LREF_PRI, "lref.pri") \
|
||||
_(UNGEN_LREF_ALT, "lref.alt") \
|
||||
_(LREF_S_PRI, "lref.s.pri") \
|
||||
_(LREF_S_ALT, "lref.s.alt") \
|
||||
_(LOAD_I, "load.i") \
|
||||
_(LODB_I, "lodb.i") \
|
||||
_(CONST_PRI, "const.pri") \
|
||||
_(CONST_ALT, "const.alt") \
|
||||
_(ADDR_PRI, "addr.pri") \
|
||||
_(ADDR_ALT, "addr.alt") \
|
||||
_(STOR_PRI, "stor.pri") \
|
||||
_(STOR_ALT, "stor.alt") \
|
||||
_(STOR_S_PRI, "stor.s.pri") \
|
||||
_(STOR_S_ALT, "stor.s.alt") \
|
||||
_(UNGEN_SREF_PRI, "sref.pri") \
|
||||
_(UNGEN_SREF_ALT, "sref.alt") \
|
||||
_(SREF_S_PRI, "sref.s.pri") \
|
||||
_(SREF_S_ALT, "sref.s.alt") \
|
||||
_(STOR_I, "stor.i") \
|
||||
_(STRB_I, "strb.i") \
|
||||
_(LIDX, "lidx") \
|
||||
_(LIDX_B, "lidx.b") \
|
||||
_(IDXADDR, "idxaddr") \
|
||||
_(IDXADDR_B, "idxaddr.b") \
|
||||
_(UNGEN_ALIGN_PRI,"align.pri") \
|
||||
_(UNGEN_ALIGN_ALT,"align.alt") \
|
||||
_(UNGEN_LCTRL, "lctrl") \
|
||||
_(UNGEN_SCTRL, "sctrl") \
|
||||
_(MOVE_PRI, "move.pri") \
|
||||
_(MOVE_ALT, "move.alt") \
|
||||
_(XCHG, "xchg") \
|
||||
_(PUSH_PRI, "push.pri") \
|
||||
_(PUSH_ALT, "push.alt") \
|
||||
_(UNGEN_PUSH_R, "push.r") \
|
||||
_(PUSH_C, "push.c") \
|
||||
_(PUSH, "push") \
|
||||
_(PUSH_S, "push.s") \
|
||||
_(POP_PRI, "pop.pri") \
|
||||
_(POP_ALT, "pop.alt") \
|
||||
_(STACK, "stack") \
|
||||
_(HEAP, "heap") \
|
||||
_(PROC, "proc") \
|
||||
_(UNGEN_RET, "ret") \
|
||||
_(RETN, "retn") \
|
||||
_(CALL, "call") \
|
||||
_(UNGEN_CALL_PRI, "call.pri") \
|
||||
_(JUMP, "jump") \
|
||||
_(UNGEN_JREL, "jrel") \
|
||||
_(JZER, "jzer") \
|
||||
_(JNZ, "jnz") \
|
||||
_(JEQ, "jeq") \
|
||||
_(JNEQ, "jneq") \
|
||||
_(UNGEN_JLESS, "jsless") \
|
||||
_(UNGEN_JLEQ, "jleq") \
|
||||
_(UNGEN_JGRTR, "jgrtr") \
|
||||
_(UNGEN_JGEQ, "jgeq") \
|
||||
_(JSLESS, "jsless") \
|
||||
_(JSLEQ, "jsleq") \
|
||||
_(JSGRTR, "jsgrtr") \
|
||||
_(JSGEQ, "jsgeq") \
|
||||
_(SHL, "shl") \
|
||||
_(SHR, "shr") \
|
||||
_(SSHR, "sshr") \
|
||||
_(SHL_C_PRI, "shl.c.pri") \
|
||||
_(SHL_C_ALT, "shl.c.alt") \
|
||||
_(SHR_C_PRI, "shr.c.pri") \
|
||||
_(SHR_C_ALT, "shr.c.alt") \
|
||||
_(SMUL, "smul") \
|
||||
_(SDIV, "sdiv") \
|
||||
_(SDIV_ALT, "sdiv.alt") \
|
||||
_(UNGEN_UMUL, "umul") \
|
||||
_(UNGEN_UDIV, "udiv") \
|
||||
_(UNGEN_UDIV_ALT, "udiv.alt") \
|
||||
_(ADD, "add") \
|
||||
_(SUB, "sub") \
|
||||
_(SUB_ALT, "sub.alt") \
|
||||
_(AND, "and") \
|
||||
_(OR, "or") \
|
||||
_(XOR, "xor") \
|
||||
_(NOT, "not") \
|
||||
_(NEG, "neg") \
|
||||
_(INVERT, "invert") \
|
||||
_(ADD_C, "add.c") \
|
||||
_(SMUL_C, "smul.c") \
|
||||
_(ZERO_PRI, "zero.pri") \
|
||||
_(ZERO_ALT, "zero.alt") \
|
||||
_(ZERO, "zero") \
|
||||
_(ZERO_S, "zero.s") \
|
||||
_(UNGEN_SIGN_PRI, "sign.pri") \
|
||||
_(UNGEN_SIGN_ALT, "sign.alt") \
|
||||
_(EQ, "eq") \
|
||||
_(NEQ, "neq") \
|
||||
_(UNGEN_LESS, "less") \
|
||||
_(UNGEN_LEQ, "leq") \
|
||||
_(UNGEN_GRTR, "grtr") \
|
||||
_(UNGEN_GEQ, "geq") \
|
||||
_(SLESS, "sless") \
|
||||
_(SLEQ, "sleq") \
|
||||
_(SGRTR, "sgrtr") \
|
||||
_(SGEQ, "sgeq") \
|
||||
_(EQ_C_PRI, "eq.c.pri") \
|
||||
_(EQ_C_ALT, "eq.c.alt") \
|
||||
_(INC_PRI, "inc.pri") \
|
||||
_(INC_ALT, "inc.alt") \
|
||||
_(INC, "inc") \
|
||||
_(INC_S, "inc.s") \
|
||||
_(INC_I, "inc.i") \
|
||||
_(DEC_PRI, "dec.pri") \
|
||||
_(DEC_ALT, "dec.alt") \
|
||||
_(DEC, "dec") \
|
||||
_(DEC_S, "dec.s") \
|
||||
_(DEC_I, "dec.i") \
|
||||
_(MOVS, "movs") \
|
||||
_(UNGEN_CMPS, "cmps") \
|
||||
_(FILL, "fill") \
|
||||
_(HALT, "halt") \
|
||||
_(BOUNDS, "bounds") \
|
||||
_(UNGEN_SYSREQ_PRI,"sysreq.pri") \
|
||||
_(SYSREQ_C, "sysreq.c") \
|
||||
_(UNGEN_FILE, "file") \
|
||||
_(UNGEN_LINE, "line") \
|
||||
_(UNGEN_SYMBOL, "symbol") \
|
||||
_(UNGEN_SRANGE, "srange") \
|
||||
_(UNGEN_JUMP_PRI, "jump.pri") \
|
||||
_(SWITCH, "switch") \
|
||||
_(CASETBL, "casetbl") \
|
||||
_(SWAP_PRI, "swap.pri") \
|
||||
_(SWAP_ALT, "swap.alt") \
|
||||
_(PUSH_ADR, "push.adr") \
|
||||
_(NOP, "nop") \
|
||||
_(SYSREQ_N, "sysreq.n") \
|
||||
_(UNGEN_SYMTAG, "symtag") \
|
||||
_(BREAK, "break") \
|
||||
_(PUSH2_C, "push2.c") \
|
||||
_(PUSH2, "push2") \
|
||||
_(PUSH2_S, "push2.s") \
|
||||
_(PUSH2_ADR, "push2.adr") \
|
||||
_(PUSH3_C, "push3.c") \
|
||||
_(PUSH3, "push3") \
|
||||
_(PUSH3_S, "push3.s") \
|
||||
_(PUSH3_ADR, "push3.adr") \
|
||||
_(PUSH4_C, "push4.c") \
|
||||
_(PUSH4, "push4") \
|
||||
_(PUSH4_S, "push4.s") \
|
||||
_(PUSH4_ADR, "push4.adr") \
|
||||
_(PUSH5_C, "push5.c") \
|
||||
_(PUSH5, "push5") \
|
||||
_(PUSH5_S, "push5.s") \
|
||||
_(PUSH5_ADR, "push5.adr") \
|
||||
_(LOAD_BOTH, "load.both") \
|
||||
_(LOAD_S_BOTH, "load.s.both") \
|
||||
_(CONST, "const") \
|
||||
_(CONST_S, "const.s") \
|
||||
_(UNGEN_SYSREQ_D, "sysreq.d") \
|
||||
_(UNGEB_SYSREQ_ND,"sysreq.nd") \
|
||||
_(TRACKER_PUSH_C, "trk.push.c") \
|
||||
_(TRACKER_POP_SETHEAP,"trk.pop") \
|
||||
_(GENARRAY, "genarray") \
|
||||
_(GENARRAY_Z, "genarray.z") \
|
||||
_(STRADJUST_PRI, "stradjust.pri") \
|
||||
_(UNGEN_STKADJUST,"stackadjust") \
|
||||
_(ENDPROC, "endproc") \
|
||||
_(FABS, "fabs") \
|
||||
_(FLOAT, "float") \
|
||||
_(FLOATADD, "floatadd") \
|
||||
_(FLOATSUB, "floatsub") \
|
||||
_(FLOATMUL, "floatmul") \
|
||||
_(FLOATDIV, "floatdiv") \
|
||||
_(RND_TO_NEAREST, "round") \
|
||||
_(RND_TO_FLOOR, "floor") \
|
||||
_(RND_TO_CEIL, "ceil") \
|
||||
_(RND_TO_ZERO, "rndtozero") \
|
||||
_(FLOATCMP, "floatcmp")
|
||||
|
||||
enum OPCODE {
|
||||
#define _(op, text) OP_##op,
|
||||
OPCODE_LIST(_)
|
||||
#undef _
|
||||
OPCODES_TOTAL
|
||||
};
|
||||
|
||||
namespace SourcePawn {
|
||||
void SpewOpcode(const sp_plugin_t *plugin, cell_t *start, cell_t *cip);
|
||||
}
|
||||
|
||||
#endif //_INCLUDE_SOURCEPAWN_JIT_X86_OPCODES_H_
|
@ -1,5 +1,5 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* vim: set ts=4 sw=4 tw=99 noet:
|
||||
* =============================================================================
|
||||
* SourcePawn
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
@ -46,7 +46,6 @@ using namespace SourcePawn;
|
||||
BaseContext::BaseContext(BaseRuntime *pRuntime)
|
||||
{
|
||||
m_pRuntime = pRuntime;
|
||||
m_pPlugin = m_pRuntime->m_pPlugin;
|
||||
|
||||
m_InExec = false;
|
||||
m_CustomMsg = false;
|
||||
@ -75,8 +74,8 @@ BaseContext::BaseContext(BaseRuntime *pRuntime)
|
||||
m_pNullString = NULL;
|
||||
}
|
||||
|
||||
m_ctx.hp = m_pPlugin->data_size;
|
||||
m_ctx.sp = m_pPlugin->mem_size - sizeof(cell_t);
|
||||
m_ctx.hp = m_pRuntime->plugin()->data_size;
|
||||
m_ctx.sp = m_pRuntime->plugin()->mem_size - sizeof(cell_t);
|
||||
m_ctx.frm = m_ctx.sp;
|
||||
m_ctx.n_err = SP_ERROR_NONE;
|
||||
m_ctx.n_idx = SP_ERROR_NONE;
|
||||
@ -204,7 +203,7 @@ int BaseContext::HeapAlloc(unsigned int cells, cell_t *local_addr, cell_t **phys
|
||||
return SP_ERROR_HEAPLOW;
|
||||
}
|
||||
|
||||
addr = (cell_t *)(m_pPlugin->memory + m_ctx.hp);
|
||||
addr = (cell_t *)(m_pRuntime->plugin()->memory + m_ctx.hp);
|
||||
/* store size of allocation in cells */
|
||||
*addr = (cell_t)cells;
|
||||
addr++;
|
||||
@ -229,12 +228,12 @@ int BaseContext::HeapPop(cell_t local_addr)
|
||||
|
||||
/* check the bounds of this address */
|
||||
local_addr -= sizeof(cell_t);
|
||||
if (local_addr < (cell_t)m_pPlugin->data_size || local_addr >= m_ctx.sp)
|
||||
if (local_addr < (cell_t)m_pRuntime->plugin()->data_size || local_addr >= m_ctx.sp)
|
||||
{
|
||||
return SP_ERROR_INVALID_ADDRESS;
|
||||
}
|
||||
|
||||
addr = (cell_t *)(m_pPlugin->memory + local_addr);
|
||||
addr = (cell_t *)(m_pRuntime->plugin()->memory + local_addr);
|
||||
cellcount = (*addr) * sizeof(cell_t);
|
||||
/* check if this memory count looks valid */
|
||||
if ((signed)(m_ctx.hp - cellcount - sizeof(cell_t)) != local_addr)
|
||||
@ -250,7 +249,7 @@ int BaseContext::HeapPop(cell_t local_addr)
|
||||
|
||||
int BaseContext::HeapRelease(cell_t local_addr)
|
||||
{
|
||||
if (local_addr < (cell_t)m_pPlugin->data_size)
|
||||
if (local_addr < (cell_t)m_pRuntime->plugin()->data_size)
|
||||
{
|
||||
return SP_ERROR_INVALID_ADDRESS;
|
||||
}
|
||||
@ -334,14 +333,14 @@ int BaseContext::BindNativeToAny(SPVM_NATIVE_FUNC native)
|
||||
int BaseContext::LocalToPhysAddr(cell_t local_addr, cell_t **phys_addr)
|
||||
{
|
||||
if (((local_addr >= m_ctx.hp) && (local_addr < m_ctx.sp))
|
||||
|| (local_addr < 0) || ((ucell_t)local_addr >= m_pPlugin->mem_size))
|
||||
|| (local_addr < 0) || ((ucell_t)local_addr >= m_pRuntime->plugin()->mem_size))
|
||||
{
|
||||
return SP_ERROR_INVALID_ADDRESS;
|
||||
}
|
||||
|
||||
if (phys_addr)
|
||||
{
|
||||
*phys_addr = (cell_t *)(m_pPlugin->memory + local_addr);
|
||||
*phys_addr = (cell_t *)(m_pRuntime->plugin()->memory + local_addr);
|
||||
}
|
||||
|
||||
return SP_ERROR_NONE;
|
||||
@ -365,11 +364,11 @@ int BaseContext::PushCellArray(cell_t *local_addr, cell_t **phys_addr, cell_t ar
|
||||
int BaseContext::LocalToString(cell_t local_addr, char **addr)
|
||||
{
|
||||
if (((local_addr >= m_ctx.hp) && (local_addr < m_ctx.sp))
|
||||
|| (local_addr < 0) || ((ucell_t)local_addr >= m_pPlugin->mem_size))
|
||||
|| (local_addr < 0) || ((ucell_t)local_addr >= m_pRuntime->plugin()->mem_size))
|
||||
{
|
||||
return SP_ERROR_INVALID_ADDRESS;
|
||||
}
|
||||
*addr = (char *)(m_pPlugin->memory + local_addr);
|
||||
*addr = (char *)(m_pRuntime->plugin()->memory + local_addr);
|
||||
|
||||
return SP_ERROR_NONE;
|
||||
}
|
||||
@ -385,7 +384,7 @@ int BaseContext::StringToLocal(cell_t local_addr, size_t bytes, const char *sour
|
||||
size_t len;
|
||||
|
||||
if (((local_addr >= m_ctx.hp) && (local_addr < m_ctx.sp))
|
||||
|| (local_addr < 0) || ((ucell_t)local_addr >= m_pPlugin->mem_size))
|
||||
|| (local_addr < 0) || ((ucell_t)local_addr >= m_pRuntime->plugin()->mem_size))
|
||||
{
|
||||
return SP_ERROR_INVALID_ADDRESS;
|
||||
}
|
||||
@ -396,7 +395,7 @@ int BaseContext::StringToLocal(cell_t local_addr, size_t bytes, const char *sour
|
||||
}
|
||||
|
||||
len = strlen(source);
|
||||
dest = (char *)(m_pPlugin->memory + local_addr);
|
||||
dest = (char *)(m_pRuntime->plugin()->memory + local_addr);
|
||||
|
||||
if (len >= bytes)
|
||||
{
|
||||
@ -455,7 +454,7 @@ int BaseContext::StringToLocalUTF8(cell_t local_addr, size_t maxbytes, const cha
|
||||
|
||||
if (((local_addr >= m_ctx.hp) && (local_addr < m_ctx.sp))
|
||||
|| (local_addr < 0)
|
||||
|| ((ucell_t)local_addr >= m_pPlugin->mem_size))
|
||||
|| ((ucell_t)local_addr >= m_pRuntime->plugin()->mem_size))
|
||||
{
|
||||
return SP_ERROR_INVALID_ADDRESS;
|
||||
}
|
||||
@ -466,7 +465,7 @@ int BaseContext::StringToLocalUTF8(cell_t local_addr, size_t maxbytes, const cha
|
||||
}
|
||||
|
||||
len = strlen(source);
|
||||
dest = (char *)(m_pPlugin->memory + local_addr);
|
||||
dest = (char *)(m_pRuntime->plugin()->memory + local_addr);
|
||||
|
||||
if ((size_t)len >= maxbytes)
|
||||
{
|
||||
@ -586,21 +585,18 @@ int BaseContext::Execute2(IPluginFunction *function, const cell_t *params, unsig
|
||||
|
||||
/* We got this far. It's time to start profiling. */
|
||||
|
||||
if ((m_pPlugin->prof_flags & SP_PROF_CALLBACKS) == SP_PROF_CALLBACKS)
|
||||
if ((m_pRuntime->plugin()->prof_flags & SP_PROF_CALLBACKS) == SP_PROF_CALLBACKS)
|
||||
{
|
||||
serial = m_pPlugin->profiler->OnCallbackBegin(this, pubfunc);
|
||||
serial = m_pRuntime->plugin()->profiler->OnCallbackBegin(this, pubfunc);
|
||||
}
|
||||
|
||||
/* See if we have to compile the callee. */
|
||||
if ((fn = m_pRuntime->m_PubJitFuncs[public_id]) == NULL)
|
||||
{
|
||||
uint32_t func_idx;
|
||||
|
||||
/* We might not have to - check pcode offset. */
|
||||
if ((func_idx = FuncLookup((CompData *)m_pRuntime->m_pCo, pubfunc->code_offs)) != 0)
|
||||
fn = m_pRuntime->GetJittedFunctionByOffset(pubfunc->code_offs);
|
||||
if (fn)
|
||||
{
|
||||
fn = m_pRuntime->GetJittedFunction(func_idx);
|
||||
assert(fn != NULL);
|
||||
m_pRuntime->m_PubJitFuncs[public_id] = fn;
|
||||
}
|
||||
else
|
||||
@ -629,7 +625,7 @@ int BaseContext::Execute2(IPluginFunction *function, const cell_t *params, unsig
|
||||
/* Push parameters */
|
||||
|
||||
m_ctx.sp -= sizeof(cell_t) * (num_params + 1);
|
||||
sp = (cell_t *)(m_pPlugin->memory + m_ctx.sp);
|
||||
sp = (cell_t *)(m_pRuntime->plugin()->memory + m_ctx.sp);
|
||||
|
||||
sp[0] = num_params;
|
||||
for (unsigned int i = 0; i < num_params; i++)
|
||||
@ -687,9 +683,9 @@ int BaseContext::Execute2(IPluginFunction *function, const cell_t *params, unsig
|
||||
m_ctx.hp = save_hp;
|
||||
m_ctx.rp = save_rp;
|
||||
|
||||
if ((m_pPlugin->prof_flags & SP_PROF_CALLBACKS) == SP_PROF_CALLBACKS)
|
||||
if ((m_pRuntime->plugin()->prof_flags & SP_PROF_CALLBACKS) == SP_PROF_CALLBACKS)
|
||||
{
|
||||
m_pPlugin->profiler->OnCallbackEnd(serial);
|
||||
m_pRuntime->plugin()->profiler->OnCallbackEnd(serial);
|
||||
}
|
||||
|
||||
m_ctx.err_cip = save_cip;
|
||||
@ -746,7 +742,6 @@ int DebugInfo::LookupFunction(ucell_t addr, const char **name)
|
||||
{
|
||||
uint32_t max, iter;
|
||||
sp_fdbg_symbol_t *sym;
|
||||
sp_fdbg_arraydim_t *arr;
|
||||
uint8_t *cursor = (uint8_t *)(m_pPlugin->debug.symbols);
|
||||
|
||||
max = m_pPlugin->debug.syms_num;
|
||||
@ -765,7 +760,6 @@ int DebugInfo::LookupFunction(ucell_t addr, const char **name)
|
||||
if (sym->dimcount > 0)
|
||||
{
|
||||
cursor += sizeof(sp_fdbg_symbol_t);
|
||||
arr = (sp_fdbg_arraydim_t *)cursor;
|
||||
cursor += sizeof(sp_fdbg_arraydim_t) * sym->dimcount;
|
||||
continue;
|
||||
}
|
||||
@ -779,7 +773,6 @@ int DebugInfo::LookupFunction(ucell_t addr, const char **name)
|
||||
{
|
||||
uint32_t max, iter;
|
||||
sp_u_fdbg_symbol_t *sym;
|
||||
sp_u_fdbg_arraydim_t *arr;
|
||||
uint8_t *cursor = (uint8_t *)(m_pPlugin->debug.symbols);
|
||||
|
||||
max = m_pPlugin->debug.syms_num;
|
||||
@ -798,7 +791,6 @@ int DebugInfo::LookupFunction(ucell_t addr, const char **name)
|
||||
if (sym->dimcount > 0)
|
||||
{
|
||||
cursor += sizeof(sp_u_fdbg_symbol_t);
|
||||
arr = (sp_u_fdbg_arraydim_t *)cursor;
|
||||
cursor += sizeof(sp_u_fdbg_arraydim_t) * sym->dimcount;
|
||||
continue;
|
||||
}
|
||||
@ -848,7 +840,7 @@ int BaseContext::GetLastNativeError()
|
||||
|
||||
cell_t *BaseContext::GetLocalParams()
|
||||
{
|
||||
return (cell_t *)(m_pPlugin->memory + m_ctx.frm + (2 * sizeof(cell_t)));
|
||||
return (cell_t *)(m_pRuntime->plugin()->memory + m_ctx.frm + (2 * sizeof(cell_t)));
|
||||
}
|
||||
|
||||
void BaseContext::SetKey(int k, void *value)
|
||||
|
@ -100,7 +100,6 @@ private:
|
||||
void SetErrorMessage(const char *msg, va_list ap);
|
||||
void _SetErrorMessage(const char *msg, ...);
|
||||
private:
|
||||
sp_plugin_t *m_pPlugin;
|
||||
cell_t *m_pNullVec;
|
||||
cell_t *m_pNullString;
|
||||
char m_MsgCache[1024];
|
||||
|
@ -58,7 +58,7 @@ SourcePawnEngine g_engine1;
|
||||
|
||||
using namespace SourcePawn;
|
||||
|
||||
#define ERROR_MESSAGE_MAX 25
|
||||
#define ERROR_MESSAGE_MAX 29
|
||||
static const char *g_ErrorMsgTable[] =
|
||||
{
|
||||
NULL,
|
||||
@ -89,6 +89,8 @@ static const char *g_ErrorMsgTable[] =
|
||||
"Call was aborted",
|
||||
"Plugin format is too old",
|
||||
"Plugin format is too new",
|
||||
"Out of memory",
|
||||
"Integer overflow"
|
||||
};
|
||||
|
||||
const char *SourcePawnEngine::GetErrorString(int error)
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,5 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* vim: set ts=4 sw=4 tw=99 et:
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
@ -35,164 +35,180 @@
|
||||
#include <sp_vm_types.h>
|
||||
#include <sp_vm_api.h>
|
||||
#include <KeCodeAllocator.h>
|
||||
#include "jit_helpers.h"
|
||||
#include <assembler-x86.h>
|
||||
#include <ke_vector.h>
|
||||
#include "jit_shared.h"
|
||||
#include "BaseRuntime.h"
|
||||
#include "jit_function.h"
|
||||
#include "opcodes.h"
|
||||
|
||||
using namespace SourcePawn;
|
||||
|
||||
#define JIT_INLINE_ERRORCHECKS (1<<0)
|
||||
#define JIT_INLINE_NATIVES (1<<1)
|
||||
#define STACK_MARGIN 64 //8 parameters of safety, I guess
|
||||
#define JIT_FUNCMAGIC 0x214D4148 //magic function offset
|
||||
#define JIT_INLINE_ERRORCHECKS (1<<0)
|
||||
#define JIT_INLINE_NATIVES (1<<1)
|
||||
#define STACK_MARGIN 64 //8 parameters of safety, I guess
|
||||
#define JIT_FUNCMAGIC 0x214D4148 //magic function offset
|
||||
|
||||
#define JITVARS_TRACKER 0 //important: don't change this to avoid trouble
|
||||
#define JITVARS_BASECTX 1 //important: don't change this aWOAWOGJQG I LIKE HAM
|
||||
#define JITVARS_PROFILER 2 //profiler
|
||||
#define JITVARS_PLUGIN 3 //sp_plugin_t
|
||||
#define JITVARS_TRACKER 0 //important: don't change this to avoid trouble
|
||||
#define JITVARS_BASECTX 1 //important: don't change this aWOAWOGJQG I LIKE HAM
|
||||
#define JITVARS_PROFILER 2 //profiler
|
||||
#define JITVARS_PLUGIN 3 //sp_plugin_t
|
||||
|
||||
#define sDIMEN_MAX 5 //this must mirror what the compiler has.
|
||||
#define sDIMEN_MAX 5 //this must mirror what the compiler has.
|
||||
|
||||
#define GET_CONTEXT(c) ((IPluginContext *)c->vm[JITVARS_BASECTX])
|
||||
|
||||
typedef struct tracker_s
|
||||
{
|
||||
size_t size;
|
||||
ucell_t *pBase;
|
||||
ucell_t *pCur;
|
||||
size_t size;
|
||||
ucell_t *pBase;
|
||||
ucell_t *pCur;
|
||||
} tracker_t;
|
||||
|
||||
typedef struct funcinfo_s
|
||||
{
|
||||
unsigned int magic;
|
||||
unsigned int index;
|
||||
unsigned int magic;
|
||||
unsigned int index;
|
||||
} funcinfo_t;
|
||||
|
||||
typedef struct functracker_s
|
||||
{
|
||||
unsigned int num_functions;
|
||||
unsigned int code_size;
|
||||
unsigned int num_functions;
|
||||
unsigned int code_size;
|
||||
} functracker_t;
|
||||
|
||||
struct floattbl_t
|
||||
struct CallThunk
|
||||
{
|
||||
floattbl_t()
|
||||
{
|
||||
found = false;
|
||||
index = 0;
|
||||
}
|
||||
bool found;
|
||||
unsigned int index;
|
||||
};
|
||||
Label call;
|
||||
cell_t pcode_offset;
|
||||
|
||||
struct call_thunk_t
|
||||
{
|
||||
jitoffs_t patch_addr;
|
||||
cell_t pcode_offs;
|
||||
jitoffs_t thunk_addr;
|
||||
CallThunk(cell_t pcode_offset)
|
||||
: pcode_offset(pcode_offset)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class CompData : public ICompilation
|
||||
{
|
||||
public:
|
||||
CompData()
|
||||
: runtime(NULL),
|
||||
plugin(NULL),
|
||||
rebase(NULL),
|
||||
jit_float_table(NULL),
|
||||
profile(0),
|
||||
inline_level(0),
|
||||
error_set(SP_ERROR_NONE),
|
||||
num_thunks(0),
|
||||
max_thunks(0),
|
||||
thunks(NULL)
|
||||
{
|
||||
};
|
||||
bool SetOption(const char *key, const char *val);
|
||||
void SetRuntime(BaseRuntime *runtime);
|
||||
void Abort();
|
||||
CompData()
|
||||
: profile(0),
|
||||
inline_level(0)
|
||||
{
|
||||
};
|
||||
bool SetOption(const char *key, const char *val);
|
||||
void Abort();
|
||||
public:
|
||||
BaseRuntime *runtime; /* runtime handle */
|
||||
sp_plugin_t *plugin; /* plugin handle */
|
||||
uint8_t *rebase; /* relocation map */
|
||||
floattbl_t *jit_float_table;
|
||||
cell_t cur_func; /* current func pcode offset */
|
||||
/* Options */
|
||||
int profile; /* profiling flags */
|
||||
int inline_level; /* inline optimization level */
|
||||
/* Per-compilation properties */
|
||||
int error_set; /* error code to halt process */
|
||||
unsigned int func_idx; /* current function index */
|
||||
jitoffs_t jit_error_bounds;
|
||||
jitoffs_t jit_error_divzero;
|
||||
jitoffs_t jit_error_stacklow;
|
||||
jitoffs_t jit_error_stackmin;
|
||||
jitoffs_t jit_error_memaccess;
|
||||
jitoffs_t jit_error_heaplow;
|
||||
jitoffs_t jit_error_heapmin;
|
||||
jitoffs_t jit_extern_error; /* returning generic error */
|
||||
jitoffs_t jit_sysreq_c; /* old version! */
|
||||
uint32_t num_thunks; /* number of thunks needed */
|
||||
uint32_t max_thunks; /* maximum number of thunks */
|
||||
call_thunk_t *thunks; /* thunk array */
|
||||
cell_t cur_func; /* current func pcode offset */
|
||||
/* Options */
|
||||
int profile; /* profiling flags */
|
||||
int inline_level; /* inline optimization level */
|
||||
/* Per-compilation properties */
|
||||
unsigned int func_idx; /* current function index */
|
||||
};
|
||||
|
||||
class Compiler
|
||||
{
|
||||
public:
|
||||
Compiler(BaseRuntime *rt, cell_t pcode_offs);
|
||||
~Compiler();
|
||||
|
||||
JitFunction *emit(int *errp);
|
||||
|
||||
private:
|
||||
bool setup(cell_t pcode_offs);
|
||||
bool emitOp(OPCODE op);
|
||||
cell_t readCell();
|
||||
|
||||
private:
|
||||
Label *labelAt(size_t offset);
|
||||
bool emitCall();
|
||||
bool emitNativeCall(OPCODE op);
|
||||
bool emitSwitch();
|
||||
void emitGenArray(bool autozero);
|
||||
void emitCallThunks();
|
||||
void emitCheckAddress(Register reg);
|
||||
void emitErrorPath(Label *dest, int code);
|
||||
void emitErrorPaths();
|
||||
|
||||
private:
|
||||
AssemblerX86 masm;
|
||||
BaseRuntime *rt_;
|
||||
const sp_plugin_t *plugin_;
|
||||
int error_;
|
||||
uint32_t pcode_start_;
|
||||
cell_t *code_start_;
|
||||
cell_t *cip_;
|
||||
cell_t *code_end_;
|
||||
Label *jump_map_;
|
||||
|
||||
// Errors
|
||||
Label error_bounds_;
|
||||
Label error_heap_low_;
|
||||
Label error_heap_min_;
|
||||
Label error_stack_low_;
|
||||
Label error_stack_min_;
|
||||
Label error_divide_by_zero_;
|
||||
Label error_memaccess_;
|
||||
Label error_integer_overflow_;
|
||||
Label extern_error_;
|
||||
|
||||
ke::Vector<CallThunk *> thunks_; //:TODO: free
|
||||
};
|
||||
|
||||
class JITX86
|
||||
{
|
||||
public:
|
||||
JITX86();
|
||||
public:
|
||||
bool InitializeJIT();
|
||||
void ShutdownJIT();
|
||||
ICompilation *StartCompilation(BaseRuntime *runtime);
|
||||
ICompilation *StartCompilation();
|
||||
void SetupContextVars(BaseRuntime *runtime, BaseContext *pCtx, sp_context_t *ctx);
|
||||
void FreeContextVars(sp_context_t *ctx);
|
||||
SPVM_NATIVE_FUNC CreateFakeNative(SPVM_FAKENATIVE_FUNC callback, void *pData);
|
||||
void DestroyFakeNative(SPVM_NATIVE_FUNC func);
|
||||
JitFunction *CompileFunction(BaseRuntime *runtime, cell_t pcode_offs, int *err);
|
||||
ICompilation *ApplyOptions(ICompilation *_IN, ICompilation *_OUT);
|
||||
int InvokeFunction(BaseRuntime *runtime, JitFunction *fn, cell_t *result);
|
||||
public:
|
||||
void *GetGenArrayIntrinsic();
|
||||
void *GetReturnPoint();
|
||||
void *GetRoundingTable();
|
||||
void *AllocCode(size_t size);
|
||||
void FreeCode(void *code);
|
||||
private:
|
||||
void *m_pJitEntry; /* Entry function */
|
||||
void *m_pJitReturn; /* Return point for errors */
|
||||
int m_RoundTable[3]; /* [-1, 0, 1] rounding table */
|
||||
void *m_pJitGenArray; /* Generates an array */
|
||||
public:
|
||||
JITX86();
|
||||
|
||||
public:
|
||||
bool InitializeJIT();
|
||||
void ShutdownJIT();
|
||||
ICompilation *StartCompilation(BaseRuntime *runtime);
|
||||
ICompilation *StartCompilation();
|
||||
void SetupContextVars(BaseRuntime *runtime, BaseContext *pCtx, sp_context_t *ctx);
|
||||
void FreeContextVars(sp_context_t *ctx);
|
||||
SPVM_NATIVE_FUNC CreateFakeNative(SPVM_FAKENATIVE_FUNC callback, void *pData);
|
||||
void DestroyFakeNative(SPVM_NATIVE_FUNC func);
|
||||
JitFunction *CompileFunction(BaseRuntime *runtime, cell_t pcode_offs, int *err);
|
||||
ICompilation *ApplyOptions(ICompilation *_IN, ICompilation *_OUT);
|
||||
int InvokeFunction(BaseRuntime *runtime, JitFunction *fn, cell_t *result);
|
||||
|
||||
public:
|
||||
ExternalAddress GetGenArrayIntrinsic() {
|
||||
return ExternalAddress(m_pJitGenArray);
|
||||
}
|
||||
ExternalAddress GetUniversalReturn() {
|
||||
return ExternalAddress(m_pJitReturn);
|
||||
}
|
||||
void *AllocCode(size_t size);
|
||||
void FreeCode(void *code);
|
||||
|
||||
private:
|
||||
void *m_pJitEntry; /* Entry function */
|
||||
void *m_pJitReturn; /* Universal return address */
|
||||
void *m_pJitGenArray; /* Generates an array */
|
||||
};
|
||||
|
||||
cell_t NativeCallback(sp_context_t *ctx, ucell_t native_idx, cell_t *params);
|
||||
cell_t NativeCallback_Profile(sp_context_t *ctx, ucell_t native_idx, cell_t *params);
|
||||
uint32_t FuncLookup(CompData *data, cell_t pcode_offs);
|
||||
jitoffs_t RelocLookup(JitWriter *jit, cell_t pcode_offs, bool relative=false);
|
||||
void *CompileThunk(BaseRuntime *runtime, cell_t pcode_ffs, void *jmploc_addr);
|
||||
const Register pri = eax;
|
||||
const Register alt = edx;
|
||||
const Register stk = edi;
|
||||
const Register dat = ebp;
|
||||
const Register tmp = ecx;
|
||||
const Register info = esi;
|
||||
const Register frm = ebx;
|
||||
|
||||
#define AMX_REG_PRI REG_EAX
|
||||
#define AMX_REG_ALT REG_EDX
|
||||
#define AMX_REG_STK REG_EDI
|
||||
#define AMX_REG_DAT REG_EBP
|
||||
#define AMX_REG_TMP REG_ECX
|
||||
#define AMX_REG_INFO REG_ESI
|
||||
#define AMX_REG_FRM REG_EBX
|
||||
#define AMX_NUM_INFO_VARS 9
|
||||
|
||||
#define AMX_NUM_INFO_VARS 9
|
||||
|
||||
#define AMX_INFO_FRM AMX_REG_INFO //not relocated
|
||||
#define AMX_INFO_FRAME 0 //(same thing as above)
|
||||
#define AMX_INFO_HEAP 4 //not relocated
|
||||
#define AMX_INFO_RETVAL 8 //physical
|
||||
#define AMX_INFO_CONTEXT 12 //physical
|
||||
#define AMX_INFO_STACKTOP 16 //relocated
|
||||
#define AMX_INFO_CIP 20 //pcode CIP
|
||||
#define AMX_INFO_DATASIZE 24 //plugin->data_size
|
||||
#define AMX_INFO_MEMORY 28 //plugin->memory
|
||||
#define AMX_INFO_NSTACK 32 //native stack
|
||||
#define AMX_INFO_FRAME 0 //(same thing as above)
|
||||
#define AMX_INFO_HEAP 4 //not relocated
|
||||
#define AMX_INFO_RETVAL 8 //physical
|
||||
#define AMX_INFO_CONTEXT 12 //physical
|
||||
#define AMX_INFO_STACKTOP 16 //relocated
|
||||
#define AMX_INFO_CIP 20 //pcode CIP
|
||||
#define AMX_INFO_DATASIZE 24 //plugin->data_size
|
||||
#define AMX_INFO_MEMORY 28 //plugin->memory
|
||||
#define AMX_INFO_NSTACK 32 //native stack
|
||||
|
||||
extern Knight::KeCodeCache *g_pCodeCache;
|
||||
extern JITX86 g_Jit;
|
||||
|
@ -1,706 +0,0 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "jit_x86.h"
|
||||
#include "opcode_helpers.h"
|
||||
#include "x86_macros.h"
|
||||
|
||||
jitoffs_t Write_Execute_Function(JitWriter *jit)
|
||||
{
|
||||
/**
|
||||
* The variables we're passed in:
|
||||
* void *vars[], void *entry_func
|
||||
*/
|
||||
|
||||
/**
|
||||
* !NOTE!
|
||||
* Currently, we do not accept ctx->frm as the new frame pointer.
|
||||
* Instead, we copy the frame from the stack pointer.
|
||||
* This is because we do not support resuming or sleeping!
|
||||
*/
|
||||
|
||||
//push ebp
|
||||
//mov ebp, esp
|
||||
IA32_Push_Reg(jit, REG_EBP);
|
||||
IA32_Mov_Reg_Rm(jit, REG_EBP, REG_ESP, MOD_REG);
|
||||
|
||||
//push esi
|
||||
//push edi
|
||||
//push ebx
|
||||
IA32_Push_Reg(jit, REG_ESI);
|
||||
IA32_Push_Reg(jit, REG_EDI);
|
||||
IA32_Push_Reg(jit, REG_EBX);
|
||||
|
||||
/* Prep us for doing the real work */
|
||||
//mov esi, [ebp+param0] ;get vars
|
||||
//mov ecx, [ebp+param1] ;get entry addr
|
||||
//mov eax, [esi+MEMORY] ;get memory base
|
||||
//mov edx, [esi+CONTEXT] ;get context
|
||||
IA32_Mov_Reg_Rm_Disp8(jit, REG_ESI, REG_EBP, 8 + 4*0);
|
||||
IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, REG_EBP, 8 + 4*1);
|
||||
IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, REG_ESI, AMX_INFO_MEMORY);
|
||||
IA32_Mov_Reg_Rm_Disp8(jit, REG_EDX, REG_ESI, AMX_INFO_CONTEXT);
|
||||
|
||||
/* Set up run-time registers */
|
||||
//mov edi, [edx+SP] ;non-reloc SP
|
||||
//add edi, eax ;reloc SP
|
||||
//mov ebp, eax ;DAT
|
||||
//mov ebx, edi ;reloc FRM
|
||||
//mov [esi+NSTACK], esp ;save ESP
|
||||
IA32_Mov_Reg_Rm_Disp8(jit, REG_EDI, REG_EDX, offsetof(sp_context_t, sp));
|
||||
IA32_Add_Rm_Reg(jit, REG_EDI, REG_EAX, MOD_REG);
|
||||
IA32_Mov_Reg_Rm(jit, REG_EBP, REG_EAX, MOD_REG);
|
||||
IA32_Mov_Reg_Rm(jit, REG_EBX, REG_EDI, MOD_REG);
|
||||
IA32_Mov_Rm_Reg_Disp8(jit, REG_ESI, REG_ESP, AMX_INFO_NSTACK);
|
||||
|
||||
/* by now, everything is set up, so we can call into the plugin */
|
||||
//call ecx
|
||||
IA32_Call_Reg(jit, REG_ECX);
|
||||
|
||||
/* if the code flow gets to here, there was a normal return */
|
||||
//mov ecx, [esi+RETVAL] ;get retval pointer
|
||||
//mov [ecx], eax ;store retval from PRI
|
||||
//mov eax, SP_ERROR_NONE ;set no error
|
||||
IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, AMX_REG_INFO, AMX_INFO_RETVAL);
|
||||
IA32_Mov_Rm_Reg(jit, REG_ECX, AMX_REG_PRI, MOD_MEM_REG);
|
||||
IA32_Mov_Reg_Imm32(jit, REG_EAX, SP_ERROR_NONE);
|
||||
|
||||
/* save where error checking/halting functions should go to */
|
||||
jitoffs_t offs_return = jit->get_outputpos();
|
||||
//mov esp, [esi+NSTACK] ;restore stack pointer
|
||||
IA32_Mov_Reg_Rm_Disp8(jit, REG_ESP, REG_ESI, AMX_INFO_NSTACK);
|
||||
|
||||
/* Restore SP */
|
||||
//mov ecx, [esi+CONTEXT]
|
||||
//sub edi, ebp
|
||||
//mov [ecx+SP], edi
|
||||
IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, REG_ESI, AMX_INFO_CONTEXT);
|
||||
IA32_Sub_Reg_Rm(jit, REG_EDI, REG_EBP, MOD_REG);
|
||||
IA32_Mov_Rm_Reg_Disp8(jit, REG_ECX, REG_EDI, offsetof(sp_context_t, sp));
|
||||
|
||||
//pop ebx
|
||||
//pop edi
|
||||
//pop esi
|
||||
//pop ebp
|
||||
//ret
|
||||
IA32_Pop_Reg(jit, REG_EBX);
|
||||
IA32_Pop_Reg(jit, REG_EDI);
|
||||
IA32_Pop_Reg(jit, REG_ESI);
|
||||
IA32_Pop_Reg(jit, REG_EBP);
|
||||
IA32_Return(jit);
|
||||
|
||||
return offs_return;
|
||||
}
|
||||
|
||||
void Write_GetError(JitWriter *jit)
|
||||
{
|
||||
//mov eax, [esi+info.context]
|
||||
//mov eax, [eax+ctx.error]
|
||||
//jmp [jit_return]
|
||||
IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_CONTEXT);
|
||||
IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, REG_EAX, offsetof(sp_context_t, n_err));
|
||||
IA32_Jump_Imm32_Abs(jit, g_Jit.GetReturnPoint());
|
||||
}
|
||||
|
||||
void Write_SetError(JitWriter *jit, int error)
|
||||
{
|
||||
//mov eax, <error>
|
||||
//jmp [jit_return]
|
||||
IA32_Mov_Reg_Imm32(jit, REG_EAX, error);
|
||||
IA32_Jump_Imm32_Abs(jit, g_Jit.GetReturnPoint());
|
||||
}
|
||||
|
||||
void Write_Check_DivZero(JitWriter *jit, jit_uint8_t reg)
|
||||
{
|
||||
//test reg, reg
|
||||
//jz :error
|
||||
IA32_Test_Rm_Reg(jit, reg, reg, MOD_REG);
|
||||
IA32_Jump_Cond_Imm32_Rel(jit, CC_Z, ((CompData *)jit->data)->jit_error_divzero);
|
||||
}
|
||||
|
||||
void Write_CheckHeap_Min(JitWriter *jit)
|
||||
{
|
||||
/* Check if the stack went beyond the heap low.
|
||||
* This usually means there was a compiler error.
|
||||
* NOTE: Special optimization here.
|
||||
* The heap low is always known ahead of time! :)
|
||||
*/
|
||||
CompData *data = (CompData *)jit->data;
|
||||
//cmp [esi+info.heap], <heaplow>
|
||||
//jb :error
|
||||
IA32_Cmp_Rm_Imm32_Disp8(jit, AMX_REG_INFO, AMX_INFO_HEAP, data->plugin->data_size);
|
||||
IA32_Jump_Cond_Imm32_Rel(jit, CC_B, data->jit_error_heapmin);
|
||||
}
|
||||
|
||||
void Write_CheckHeap_Low(JitWriter *jit)
|
||||
{
|
||||
/* Check if the heap is trying to grow beyond the stack.
|
||||
*/
|
||||
//mov ecx, [esi+info.heap]
|
||||
//lea ecx, [ebp+ecx+STACK_MARGIN]
|
||||
//cmp ecx, edi
|
||||
//ja :error ; I think this is right
|
||||
IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAP);
|
||||
IA32_Lea_Reg_DispRegMultImm8(jit, AMX_REG_TMP, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, STACK_MARGIN);
|
||||
IA32_Cmp_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_STK, MOD_REG);
|
||||
IA32_Jump_Cond_Imm32_Rel(jit, CC_A, ((CompData *)jit->data)->jit_error_heaplow);
|
||||
}
|
||||
|
||||
void Write_CheckStack_Min(JitWriter *jit)
|
||||
{
|
||||
/* Check if the stack went beyond the stack top
|
||||
* This usually means there was a compiler error.
|
||||
*/
|
||||
//cmp edi, [esi+info.stacktop]
|
||||
//jae :error
|
||||
IA32_Cmp_Reg_Rm_Disp8(jit, AMX_REG_STK, AMX_REG_INFO, AMX_INFO_STACKTOP);
|
||||
IA32_Jump_Cond_Imm32_Rel(jit, CC_AE, ((CompData *)jit->data)->jit_error_stackmin);
|
||||
}
|
||||
|
||||
void Write_CheckStack_Low(JitWriter *jit)
|
||||
{
|
||||
/* Check if the stack went beyond the heap boundary.
|
||||
* Unfortunately this one isn't as quick as the other check.
|
||||
* The stack margin check is important for sysreq.n having space.
|
||||
*/
|
||||
//mov ecx, [esi+info.heap]
|
||||
//lea ecx, [ebp+ecx+STACK_MARGIN]
|
||||
//cmp edi, ecx
|
||||
//jb :error ; I think this is right
|
||||
IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAP);
|
||||
IA32_Lea_Reg_DispRegMultImm8(jit, AMX_REG_TMP, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, STACK_MARGIN);
|
||||
IA32_Cmp_Reg_Rm(jit, AMX_REG_STK, AMX_REG_TMP, MOD_REG);
|
||||
IA32_Jump_Cond_Imm32_Rel(jit, CC_B, ((CompData *)jit->data)->jit_error_stacklow);
|
||||
}
|
||||
|
||||
void Write_Check_VerifyAddr(JitWriter *jit, jit_uint8_t reg)
|
||||
{
|
||||
/* :TODO: Should this be checking for below heaplow?
|
||||
* The old JIT did not.
|
||||
*/
|
||||
|
||||
/**
|
||||
* :TODO: If we can't find a nicer way of doing this,
|
||||
* then scrap it on high optimizations. The second portion is not needed at all!
|
||||
*/
|
||||
|
||||
/* Part 1: Check if we're in the memory bounds */
|
||||
//cmp <reg>, <stpu>
|
||||
//jae :error
|
||||
IA32_Cmp_Rm_Imm32(jit, MOD_REG, reg, ((CompData *)jit->data)->plugin->mem_size);
|
||||
IA32_Jump_Cond_Imm32_Rel(jit, CC_AE, ((CompData *)jit->data)->jit_error_memaccess);
|
||||
|
||||
/* Part 2: Check if we're in the invalid region between HP and SP */
|
||||
jitoffs_t jmp;
|
||||
//cmp <reg>, [esi+info.heap]
|
||||
//jb :continue
|
||||
//lea ecx, [ebp+<reg>]
|
||||
//cmp edi, ecx
|
||||
//jb :error
|
||||
//:continue
|
||||
IA32_Cmp_Reg_Rm_Disp8(jit, reg, AMX_REG_INFO, AMX_INFO_HEAP);
|
||||
jmp = IA32_Jump_Cond_Imm8(jit, CC_B, 0);
|
||||
IA32_Lea_Reg_DispRegMultImm8(jit, AMX_REG_TMP, AMX_REG_DAT, reg, NOSCALE, 0);
|
||||
IA32_Cmp_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_STK, MOD_REG);
|
||||
IA32_Jump_Cond_Imm32_Rel(jit, CC_B, ((CompData *)jit->data)->jit_error_memaccess);
|
||||
IA32_Send_Jump8_Here(jit, jmp);
|
||||
}
|
||||
|
||||
void Macro_PushN_Addr(JitWriter *jit, int i)
|
||||
{
|
||||
//push eax
|
||||
//mov eax, [esi+frm]
|
||||
//loop i times:
|
||||
// lea ecx, [eax+<val>]
|
||||
// mov [edi-4*i], ecx
|
||||
//sub edi, 4*N
|
||||
//pop eax
|
||||
|
||||
cell_t val;
|
||||
int n = 1;
|
||||
IA32_Push_Reg(jit, AMX_REG_PRI);
|
||||
IA32_Mov_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_INFO, MOD_MEM_REG);
|
||||
do
|
||||
{
|
||||
val = jit->read_cell();
|
||||
if (val <= SCHAR_MAX && val >= SCHAR_MIN)
|
||||
IA32_Lea_DispRegImm8(jit, AMX_REG_TMP, AMX_REG_PRI, (jit_int8_t)val);
|
||||
else
|
||||
IA32_Lea_DispRegImm32(jit, AMX_REG_TMP, AMX_REG_PRI, val);
|
||||
IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_STK, AMX_REG_TMP, -4*n);
|
||||
} while (n++ < i);
|
||||
IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4*i, MOD_REG);
|
||||
IA32_Pop_Reg(jit, AMX_REG_PRI);
|
||||
}
|
||||
|
||||
void Macro_PushN_S(JitWriter *jit, int i)
|
||||
{
|
||||
//loop i times:
|
||||
// mov ecx, [ebx+<val>]
|
||||
// mov [edi-4*i], ecx
|
||||
//sub edi, 4*N
|
||||
|
||||
cell_t val;
|
||||
int n = 1;
|
||||
do
|
||||
{
|
||||
val = jit->read_cell();
|
||||
if (val <= SCHAR_MAX && val >= SCHAR_MIN)
|
||||
IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_FRM, (jit_int8_t)val);
|
||||
else
|
||||
IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_TMP, AMX_REG_FRM, val);
|
||||
IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_STK, AMX_REG_TMP, -4*n);
|
||||
} while (n++ < i);
|
||||
IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4*i, MOD_REG);
|
||||
}
|
||||
|
||||
void Macro_PushN_C(JitWriter *jit, int i)
|
||||
{
|
||||
//loop i times:
|
||||
// mov [edi-4*i], <val>
|
||||
//sub edi, 4*N
|
||||
|
||||
int n = 1;
|
||||
do
|
||||
{
|
||||
IA32_Mov_Rm_Imm32_Disp8(jit, AMX_REG_STK, jit->read_cell(), -4*n);
|
||||
} while (n++ < i);
|
||||
IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4*i, MOD_REG);
|
||||
}
|
||||
|
||||
void Macro_PushN(JitWriter *jit, int i)
|
||||
{
|
||||
//loop i times:
|
||||
// mov ecx, [ebp+<val>]
|
||||
// mov [edi-4*i], ecx
|
||||
//sub edi, 4*N
|
||||
|
||||
cell_t val;
|
||||
int n = 1;
|
||||
do
|
||||
{
|
||||
val = jit->read_cell();
|
||||
if (val <= SCHAR_MAX && val >= SCHAR_MIN)
|
||||
IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_DAT, (jit_int8_t)val);
|
||||
else
|
||||
IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_TMP, AMX_REG_DAT, val);
|
||||
IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_STK, AMX_REG_TMP, -4*n);
|
||||
} while (n++ < i);
|
||||
IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4*i, MOD_REG);
|
||||
}
|
||||
|
||||
void WriteOp_Sysreq_C_Function(JitWriter *jit)
|
||||
{
|
||||
/* The small daddy of the big daddy of opcodes.
|
||||
* ecx - native index
|
||||
*/
|
||||
CompData *data = (CompData *)jit->data;
|
||||
|
||||
/* save registers we will need */
|
||||
//push edx
|
||||
IA32_Push_Reg(jit, AMX_REG_ALT);
|
||||
|
||||
/* Align the stack to 16 bytes */
|
||||
//push ebx
|
||||
//mov ebx, esp
|
||||
//and esp, 0xFFFFFF0
|
||||
//sub esp, 4
|
||||
IA32_Push_Reg(jit, REG_EBX);
|
||||
IA32_Mov_Reg_Rm(jit, REG_EBX, REG_ESP, MOD_REG);
|
||||
IA32_And_Rm_Imm8(jit, REG_ESP, MOD_REG, -16);
|
||||
IA32_Sub_Rm_Imm8(jit, REG_ESP, 4, MOD_REG);
|
||||
|
||||
/* push some callback stuff */
|
||||
//push edi ; stack
|
||||
//push ecx ; native index
|
||||
IA32_Push_Reg(jit, AMX_REG_STK);
|
||||
IA32_Push_Reg(jit, REG_ECX);
|
||||
|
||||
/* Relocate stack, heap, frm information, then store back */
|
||||
//mov eax, [esi+context]
|
||||
//mov ecx, [esi+hea]
|
||||
//sub edi, ebp
|
||||
//mov [eax+hp], ecx
|
||||
//mov ecx, [esi]
|
||||
//mov [eax+sp], edi
|
||||
//mov [eax+frm], ecx
|
||||
IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_CONTEXT);
|
||||
IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAP);
|
||||
IA32_Sub_Reg_Rm(jit, AMX_REG_STK, AMX_REG_DAT, MOD_REG);
|
||||
IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_TMP, offsetof(sp_context_t, hp));
|
||||
IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_INFO_FRM, MOD_MEM_REG);
|
||||
IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_STK, offsetof(sp_context_t, sp));
|
||||
IA32_Mov_Rm_Reg_Disp8(jit, REG_EAX, AMX_REG_TMP, offsetof(sp_context_t, frm));
|
||||
|
||||
/* finally, push the last parameter and make the call */
|
||||
//push eax ; context
|
||||
//call NativeCallback
|
||||
IA32_Push_Reg(jit, REG_EAX);
|
||||
jitoffs_t call = IA32_Call_Imm32(jit, 0);
|
||||
IA32_Write_Jump32_Abs(jit, call, (void *)NativeCallback);
|
||||
|
||||
/* Test for error */
|
||||
//mov ecx, [esi+context]
|
||||
//cmp [ecx+err], 0
|
||||
//jnz :error
|
||||
IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_CONTEXT);
|
||||
IA32_Cmp_Rm_Disp8_Imm8(jit, AMX_REG_TMP, offsetof(sp_context_t, n_err), 0);
|
||||
IA32_Jump_Cond_Imm32_Rel(jit, CC_NZ, data->jit_extern_error);
|
||||
|
||||
/* restore what we damaged */
|
||||
//mov esp, ebx
|
||||
//pop ebx
|
||||
//add edi, ebp
|
||||
//pop edx
|
||||
IA32_Mov_Reg_Rm(jit, REG_ESP, REG_EBX, MOD_REG);
|
||||
IA32_Pop_Reg(jit, REG_EBX);
|
||||
IA32_Add_Reg_Rm(jit, AMX_REG_STK, AMX_REG_DAT, MOD_REG);
|
||||
IA32_Pop_Reg(jit, AMX_REG_ALT);
|
||||
|
||||
//ret
|
||||
IA32_Return(jit);
|
||||
}
|
||||
|
||||
typedef struct array_creation_s
|
||||
{
|
||||
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 */
|
||||
} array_creation_t;
|
||||
|
||||
cell_t _GenerateArrayIndirectionVectors(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 = _GenerateArrayIndirectionVectors(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;
|
||||
}
|
||||
|
||||
void 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);
|
||||
|
||||
_GenerateArrayIndirectionVectors(&ar, 0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* A few notes about this function.
|
||||
* I was more concerned about efficient use of registers here, rather than
|
||||
* fine-tuned optimization. The reason is that the code is already complicated,
|
||||
* and it is very easy to mess up.
|
||||
*/
|
||||
void WriteIntrinsic_GenArray(JitWriter *jit)
|
||||
{
|
||||
jitoffs_t err1, err2;
|
||||
|
||||
/**
|
||||
* save important values
|
||||
*/
|
||||
//push ebx
|
||||
//push eax
|
||||
//push edx
|
||||
//push ecx ;value is referenced on stack
|
||||
IA32_Push_Reg(jit, REG_EBX);
|
||||
IA32_Push_Reg(jit, REG_EAX);
|
||||
IA32_Push_Reg(jit, REG_EDX);
|
||||
IA32_Push_Reg(jit, REG_ECX);
|
||||
|
||||
/**
|
||||
* Calculate how many cells will be needed.
|
||||
*/
|
||||
//mov edx, [edi] ;get last dimension's count
|
||||
//mov eax, 1 ;position at second to last dimension
|
||||
//:loop
|
||||
//cmp eax, [esp] ;compare to # of params
|
||||
//jae :done ;end loop if done
|
||||
//mov ecx, [edi+eax*4] ;get dimension size
|
||||
//imul edx, ecx ;multiply by size
|
||||
//add eax, 1 ;increment
|
||||
//add edx, ecx ;add size (indirection vector)
|
||||
//jmp :loop ;jump back
|
||||
//:done
|
||||
IA32_Mov_Reg_Rm(jit, REG_EDX, AMX_REG_STK, MOD_MEM_REG);
|
||||
IA32_Mov_Reg_Imm32(jit, REG_EAX, 1);
|
||||
jitoffs_t loop1 = jit->get_outputpos();
|
||||
IA32_Cmp_Reg_Rm_ESP(jit, REG_EAX);
|
||||
jitoffs_t done1 = IA32_Jump_Cond_Imm8(jit, CC_AE, 0);
|
||||
IA32_Mov_Reg_Rm_Disp_Reg(jit, REG_ECX, AMX_REG_STK, REG_EAX, SCALE4);
|
||||
IA32_IMul_Reg_Rm(jit, REG_EDX, REG_ECX, MOD_REG);
|
||||
IA32_Add_Rm_Imm8(jit, REG_EAX, 1, MOD_REG);
|
||||
IA32_Add_Reg_Rm(jit, REG_EDX, REG_ECX, MOD_REG);
|
||||
IA32_Write_Jump8(jit, IA32_Jump_Imm8(jit, loop1), loop1);
|
||||
IA32_Send_Jump8_Here(jit, done1);
|
||||
|
||||
/* Test if we have heap space for this */
|
||||
//mov eax, [esi+info.heap] ;get heap pointer
|
||||
//lea eax, [eax+edx*4] ;new heap pointer
|
||||
//cmp eax, [esi+info.datasz] ;compare to heap low
|
||||
//jbe :error ;die if we hit this (it should always be >)
|
||||
//add eax, ebp ;relocate to stack
|
||||
//cmp eax, edi ;die if above the stack pointer
|
||||
//jae :error
|
||||
IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_HEAP);
|
||||
IA32_Lea_Reg_DispRegMult(jit, REG_EAX, REG_EAX, REG_EDX, SCALE4);
|
||||
IA32_Cmp_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_DATASIZE);
|
||||
err1 = IA32_Jump_Cond_Imm32(jit, CC_BE, 0);
|
||||
IA32_Add_Reg_Rm(jit, REG_EAX, AMX_REG_DAT, MOD_REG);
|
||||
IA32_Cmp_Reg_Rm(jit, REG_EAX, AMX_REG_STK, MOD_REG);
|
||||
err2 = IA32_Jump_Cond_Imm32(jit, CC_AE, 0);
|
||||
|
||||
/* Prepare for indirection iteration */
|
||||
//mov eax, [esi+info.heap] ;get heap pointer
|
||||
//lea ebx, [eax+edx*4] ;new heap pointer
|
||||
//mov [esi+info.heap], ebx ;store back
|
||||
//push eax ;save heap pointer - we need it
|
||||
IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_HEAP);
|
||||
IA32_Lea_Reg_DispRegMult(jit, REG_EBX, REG_EAX, REG_EDX, SCALE4);
|
||||
IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, REG_EBX, AMX_INFO_HEAP);
|
||||
IA32_Push_Reg(jit, REG_EAX);
|
||||
|
||||
WriteOp_Tracker_Push_Reg(jit, REG_EDX);
|
||||
|
||||
/* This part is too messy to do in straight assembly.
|
||||
* I'm letting the compiler handle it and thus it's in C.
|
||||
*/
|
||||
//lea ebx, [ebp+eax] ;get base pointer
|
||||
//push dword [esp-8] ;push autozero
|
||||
//push dword [esp-8] ;push dimension count
|
||||
//push edi ;push dim array
|
||||
//push ebx
|
||||
//call GenerateArrayIndirectionVectors
|
||||
//add esp, 4*4
|
||||
IA32_Lea_Reg_DispRegMult(jit, REG_EBX, REG_EAX, REG_EBP, NOSCALE);
|
||||
IA32_Push_Rm_Disp8_ESP(jit, 8);
|
||||
IA32_Push_Rm_Disp8_ESP(jit, 8);
|
||||
IA32_Push_Reg(jit, REG_EDI);
|
||||
IA32_Push_Reg(jit, REG_EBX);
|
||||
IA32_Write_Jump32_Abs(jit, IA32_Call_Imm32(jit, 0), (void *)&GenerateArrayIndirectionVectors);
|
||||
IA32_Add_Rm_Imm8(jit, REG_ESP, 4*4, MOD_REG);
|
||||
|
||||
/* Store the heap pointer back into the stack */
|
||||
//pop eax ;restore heap pointer
|
||||
//pop ecx ;restore param count
|
||||
//lea edi, [edi+ecx*4-4] ;pop params-4 off the stack
|
||||
//mov [edi], eax ;store back the heap pointer
|
||||
IA32_Pop_Reg(jit, REG_EAX);
|
||||
IA32_Pop_Reg(jit, REG_ECX);
|
||||
IA32_Lea_Reg_DispRegMultImm8(jit, AMX_REG_STK, AMX_REG_STK, REG_ECX, SCALE4, -4);
|
||||
IA32_Mov_Rm_Reg(jit, AMX_REG_STK, REG_EAX, MOD_MEM_REG);
|
||||
|
||||
/* Return to caller */
|
||||
//pop edx
|
||||
//pop eax
|
||||
//pop ebx
|
||||
//ret
|
||||
IA32_Pop_Reg(jit, REG_ECX);
|
||||
IA32_Pop_Reg(jit, REG_EAX);
|
||||
IA32_Pop_Reg(jit, REG_EBX);
|
||||
IA32_Return(jit);
|
||||
|
||||
//:error
|
||||
IA32_Send_Jump32_Here(jit, err1);
|
||||
IA32_Send_Jump32_Here(jit, err2);
|
||||
Write_SetError(jit, SP_ERROR_ARRAY_TOO_BIG);
|
||||
}
|
||||
|
||||
void WriteOp_Tracker_Push_Reg(JitWriter *jit, uint8_t reg)
|
||||
{
|
||||
/* Save registers that may be damaged by the call */
|
||||
//push eax
|
||||
//push ecx
|
||||
//push edi
|
||||
//lea edi, [<reg>*4] ; we want the count in bytes not in cells
|
||||
IA32_Push_Reg(jit, AMX_REG_PRI);
|
||||
if (reg == REG_ECX)
|
||||
{
|
||||
IA32_Push_Reg(jit, AMX_REG_TMP);
|
||||
}
|
||||
IA32_Push_Reg(jit, AMX_REG_STK);
|
||||
IA32_Lea_Reg_RegMultImm32(jit, REG_EDI, reg, SCALE4, 0);
|
||||
|
||||
/* Get the context ptr, push it and call the check */
|
||||
//mov eax, [esi+context]
|
||||
//push eax
|
||||
//call JIT_VerifyOrAllocateTracker
|
||||
IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_CONTEXT);
|
||||
IA32_Push_Reg(jit, REG_EAX);
|
||||
jitoffs_t call = IA32_Call_Imm32(jit, 0);
|
||||
IA32_Write_Jump32_Abs(jit, call, (void *)JIT_VerifyOrAllocateTracker);
|
||||
|
||||
/* Check for errors */
|
||||
//cmp eax, 0
|
||||
//jnz :error
|
||||
IA32_Cmp_Rm_Imm8(jit, MOD_REG, REG_EAX, 0);
|
||||
IA32_Jump_Cond_Imm32_Abs(jit, CC_NZ, g_Jit.GetReturnPoint());
|
||||
|
||||
/* Restore */
|
||||
//pop eax
|
||||
IA32_Pop_Reg(jit, REG_EAX);
|
||||
|
||||
/* Push the register into the stack and increment pCur */
|
||||
//mov edx, [eax+vm[]]
|
||||
//mov eax, [edx+pcur]
|
||||
//add [edx+pcur], 4
|
||||
//mov [eax], edi
|
||||
IA32_Mov_Reg_Rm_Disp8(jit, REG_EDX, REG_EAX, offsetof(sp_context_t, vm[JITVARS_TRACKER]));
|
||||
IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, REG_EDX, offsetof(tracker_t, pCur));
|
||||
IA32_Add_Rm_Imm8_Disp8(jit, REG_EDX, 4, offsetof(tracker_t, pCur));
|
||||
IA32_Mov_Rm_Reg(jit, REG_EAX, REG_EDI, MOD_MEM_REG);
|
||||
|
||||
/* Restore PRI, ALT and STK */
|
||||
//pop edi
|
||||
//pop ecx
|
||||
//pop eax
|
||||
IA32_Pop_Reg(jit, AMX_REG_STK);
|
||||
if (reg == REG_ECX)
|
||||
{
|
||||
IA32_Pop_Reg(jit, AMX_REG_TMP);
|
||||
}
|
||||
IA32_Pop_Reg(jit, AMX_REG_PRI);
|
||||
}
|
||||
|
||||
int JIT_VerifyOrAllocateTracker(sp_context_t *ctx)
|
||||
{
|
||||
tracker_t *trk = (tracker_t *)(ctx->vm[JITVARS_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;
|
||||
}
|
||||
|
||||
return SP_ERROR_NONE;
|
||||
}
|
||||
|
||||
int JIT_VerifyLowBoundTracker(sp_context_t *ctx)
|
||||
{
|
||||
tracker_t *trk = (tracker_t *)(ctx->vm[JITVARS_TRACKER]);
|
||||
|
||||
if (trk->pCur <= trk->pBase)
|
||||
{
|
||||
return SP_ERROR_TRACKER_BOUNDS;
|
||||
}
|
||||
|
||||
return SP_ERROR_NONE;
|
||||
}
|
||||
|
||||
void AlignMe(JitWriter *jit)
|
||||
{
|
||||
jitoffs_t cur_offs = jit->get_outputpos();
|
||||
jitoffs_t offset = ((cur_offs & 0xFFFFFFF0) + 16) - cur_offs;
|
||||
|
||||
if (offset)
|
||||
{
|
||||
for (jit_uint32_t i=0; i<offset; i++)
|
||||
{
|
||||
jit->write_ubyte(IA32_INT3);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,317 +0,0 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_SOURCEPAWN_JIT_X86_OPCODE_INFO_H_
|
||||
#define _INCLUDE_SOURCEPAWN_JIT_X86_OPCODE_INFO_H_
|
||||
|
||||
#include "../jit_helpers.h"
|
||||
|
||||
/**
|
||||
* This outputs the execution function for a plugin.
|
||||
* It also returns the 'return' offset, which is used for
|
||||
* breaking out of the JIT during runtime.
|
||||
*/
|
||||
jitoffs_t Write_Execute_Function(JitWriter *jit);
|
||||
|
||||
/**
|
||||
* Writes the Sysreq.* opcodes as a function call.
|
||||
*/
|
||||
void WriteOp_Sysreq_C_Function(JitWriter *jit);
|
||||
|
||||
/**
|
||||
* Write the GENARRAY intrinsic function.
|
||||
*/
|
||||
void WriteIntrinsic_GenArray(JitWriter *jit);
|
||||
|
||||
void Write_Check_VerifyAddr(JitWriter *jit, jit_uint8_t reg);
|
||||
|
||||
/**
|
||||
* Generates code to set an error state in the VM and return.
|
||||
* This is used for generating the error set points in the VM.
|
||||
* GetError writes the error from the context. SetError hardcodes.
|
||||
*/
|
||||
void Write_GetError(JitWriter *jit);
|
||||
void Write_SetError(JitWriter *jit, int error);
|
||||
|
||||
/**
|
||||
* Checks the stacks for min and low errors.
|
||||
* :TODO: Should a variation of this go in the pushN opcodes?
|
||||
*/
|
||||
void Write_CheckStack_Min(JitWriter *jit);
|
||||
void Write_CheckStack_Low(JitWriter *jit);
|
||||
|
||||
/**
|
||||
* Checks the heap for min and low errors.
|
||||
*/
|
||||
void Write_CheckHeap_Min(JitWriter *jit);
|
||||
void Write_CheckHeap_Low(JitWriter *jit);
|
||||
|
||||
/**
|
||||
* Checks for division by zero.
|
||||
*/
|
||||
void Write_Check_DivZero(JitWriter *jit, jit_uint8_t reg);
|
||||
|
||||
/**
|
||||
* Writes the break debug function.
|
||||
*/
|
||||
void Write_BreakDebug(JitWriter *jit);
|
||||
|
||||
/**
|
||||
* These are for writing the PushN opcodes.
|
||||
*/
|
||||
void Macro_PushN_Addr(JitWriter *jit, int i);
|
||||
void Macro_PushN_S(JitWriter *jit, int i);
|
||||
void Macro_PushN_C(JitWriter *jit, int i);
|
||||
void Macro_PushN(JitWriter *jit, int i);
|
||||
|
||||
/**
|
||||
* Bound checking for the tracker stack,
|
||||
*/
|
||||
int JIT_VerifyLowBoundTracker(sp_context_t *ctx);
|
||||
int JIT_VerifyOrAllocateTracker(sp_context_t *ctx);
|
||||
|
||||
/**
|
||||
* Writes the push into tracker function.
|
||||
*/
|
||||
void WriteOp_Tracker_Push_Reg(JitWriter *jit, uint8_t reg);
|
||||
|
||||
/**
|
||||
* Writes the rounding table for the float compare opcode.
|
||||
*/
|
||||
void Write_RoundingTable(JitWriter *jit);
|
||||
|
||||
/**
|
||||
* Aligns the current code position to 16 bytes.
|
||||
*/
|
||||
void AlignMe(JitWriter *jit);
|
||||
|
||||
/**
|
||||
* Legend for Statuses:
|
||||
* ****** *** ********
|
||||
* DONE -> code generation is done
|
||||
* !GEN -> code generation is deliberate skipped because:
|
||||
* (default): compiler does not generate
|
||||
* DEPRECATED: this feature no longer exists/supported
|
||||
* UNSUPPORTED: this opcode is not supported
|
||||
* TODO: done in case needed
|
||||
* VERIFIED -> code generation is checked as run-time working. prefixes:
|
||||
* ! errors are not checked yet.
|
||||
* - non-inline errors are not checked yet.
|
||||
* ~ assumed checked because of related variation, but not actually checked
|
||||
*/
|
||||
|
||||
typedef enum
|
||||
{
|
||||
OP_NONE, /* invalid opcode */
|
||||
OP_LOAD_PRI, //!VERIFIED
|
||||
OP_LOAD_ALT, //~!VERIFIED (load.pri)
|
||||
OP_LOAD_S_PRI, //VERIFIED
|
||||
OP_LOAD_S_ALT, //VERIFIED
|
||||
OP_LREF_PRI, //VERIFIED
|
||||
OP_LREF_ALT, //~VERIFIED
|
||||
OP_LREF_S_PRI, //VERIFIED
|
||||
OP_LREF_S_ALT, //~VERIFIED (lref.s.pri)
|
||||
OP_LOAD_I, //VERIFIED
|
||||
OP_LODB_I, //VERIFIED
|
||||
OP_CONST_PRI, //VERIFIED
|
||||
OP_CONST_ALT, //~VERIFIED (const.pri)
|
||||
OP_ADDR_PRI, //VERIFIED
|
||||
OP_ADDR_ALT, //VERIFIED
|
||||
OP_STOR_PRI, //VERIFIED
|
||||
OP_STOR_ALT, //~VERIFIED (stor.pri)
|
||||
OP_STOR_S_PRI, //VERIFIED
|
||||
OP_STOR_S_ALT, //~VERIFIED (stor.s.pri)
|
||||
OP_SREF_PRI, //VERIFIED
|
||||
OP_SREF_ALT, //~VERIFIED
|
||||
OP_SREF_S_PRI, //VERIFIED
|
||||
OP_SREF_S_ALT, //~VERIFIED (stor.s.alt)
|
||||
OP_STOR_I, //VERIFIED
|
||||
OP_STRB_I, //VERIFIED
|
||||
OP_LIDX, //VERIFIED
|
||||
OP_LIDX_B, //DONE
|
||||
OP_IDXADDR, //VERIFIED
|
||||
OP_IDXADDR_B, //DONE
|
||||
OP_ALIGN_PRI, // !GEN :TODO: - only used for pack access, drop support in compiler first
|
||||
OP_ALIGN_ALT, // !GEN :TODO: - only used for pack access, drop support in compiler first
|
||||
OP_LCTRL, // !GEN
|
||||
OP_SCTRL, // !GEN
|
||||
OP_MOVE_PRI, //~VERIFIED (move.alt)
|
||||
OP_MOVE_ALT, //VERIFIED
|
||||
OP_XCHG, //DONE
|
||||
OP_PUSH_PRI, //DONE
|
||||
OP_PUSH_ALT, //DONE
|
||||
OP_PUSH_R, // !GEN DEPRECATED
|
||||
OP_PUSH_C, //VERIFIED
|
||||
OP_PUSH, //DONE
|
||||
OP_PUSH_S, //VERIFIED
|
||||
OP_POP_PRI, //VERIFIED
|
||||
OP_POP_ALT, //VERIFIED
|
||||
OP_STACK, //VERIFIED
|
||||
OP_HEAP, //VERIFIED
|
||||
OP_PROC, //VERIFIED
|
||||
OP_RET, // !GEN
|
||||
OP_RETN, //VERIFIED
|
||||
OP_CALL, //VERIFIED
|
||||
OP_CALL_PRI, // !GEN
|
||||
OP_JUMP, //VERIFIED
|
||||
OP_JREL, // !GEN
|
||||
OP_JZER, //VERIFIED
|
||||
OP_JNZ, //DONE
|
||||
OP_JEQ, //VERIFIED
|
||||
OP_JNEQ, //VERIFIED
|
||||
OP_JLESS, // !GEN
|
||||
OP_JLEQ, // !GEN
|
||||
OP_JGRTR, // !GEN
|
||||
OP_JGEQ, // !GEN
|
||||
OP_JSLESS, //VERIFIED
|
||||
OP_JSLEQ, //VERIFIED
|
||||
OP_JSGRTR, //VERIFIED
|
||||
OP_JSGEQ, //VERIFIED
|
||||
OP_SHL, //VERIFIED
|
||||
OP_SHR, //VERIFIED (Note: operator >>>)
|
||||
OP_SSHR, //VERIFIED (Note: operator >>)
|
||||
OP_SHL_C_PRI, //DONE
|
||||
OP_SHL_C_ALT, //DONE
|
||||
OP_SHR_C_PRI, //DONE
|
||||
OP_SHR_C_ALT, //DONE
|
||||
OP_SMUL, //VERIFIED
|
||||
OP_SDIV, //DONE
|
||||
OP_SDIV_ALT, //VERIFIED
|
||||
OP_UMUL, // !GEN
|
||||
OP_UDIV, // !GEN
|
||||
OP_UDIV_ALT, // !GEN
|
||||
OP_ADD, //VERIFIED
|
||||
OP_SUB, //DONE
|
||||
OP_SUB_ALT, //VERIFIED
|
||||
OP_AND, //VERIFIED
|
||||
OP_OR, //VERIFIED
|
||||
OP_XOR, //VERIFIED
|
||||
OP_NOT, //VERIFIED
|
||||
OP_NEG, //VERIFIED
|
||||
OP_INVERT, //VERIFIED
|
||||
OP_ADD_C, //VERIFIED
|
||||
OP_SMUL_C, //VERIFIED
|
||||
OP_ZERO_PRI, //VERIFIED
|
||||
OP_ZERO_ALT, //~VERIFIED
|
||||
OP_ZERO, //VERIFIED
|
||||
OP_ZERO_S, //VERIFIED
|
||||
OP_SIGN_PRI, //DONE
|
||||
OP_SIGN_ALT, //DONE
|
||||
OP_EQ, //VERIFIED
|
||||
OP_NEQ, //VERIFIED
|
||||
OP_LESS, // !GEN
|
||||
OP_LEQ, // !GEN
|
||||
OP_GRTR, // !GEN
|
||||
OP_GEQ, // !GEN
|
||||
OP_SLESS, //VERIFIED
|
||||
OP_SLEQ, //VERIFIED
|
||||
OP_SGRTR, //VERIFIED
|
||||
OP_SGEQ, //VERIFIED
|
||||
OP_EQ_C_PRI, //DONE
|
||||
OP_EQ_C_ALT, //DONE
|
||||
OP_INC_PRI, //VERIFIED
|
||||
OP_INC_ALT, //~VERIFIED (inc.pri)
|
||||
OP_INC, //VERIFIED
|
||||
OP_INC_S, //VERIFIED
|
||||
OP_INC_I, //VERIFIED
|
||||
OP_DEC_PRI, //VERIFIED
|
||||
OP_DEC_ALT, //~VERIFIED (dec.pri)
|
||||
OP_DEC, //VERIFIED
|
||||
OP_DEC_S, //VERIFIED
|
||||
OP_DEC_I, //VERIFIED
|
||||
OP_MOVS, //VERIFIED
|
||||
OP_CMPS, // !GEN
|
||||
OP_FILL, //VERIFIED
|
||||
OP_HALT, //DONE
|
||||
OP_BOUNDS, //VERIFIED
|
||||
OP_SYSREQ_PRI, // !GEN
|
||||
OP_SYSREQ_C, //VERIFIED
|
||||
OP_FILE, // !GEN DEPRECATED
|
||||
OP_LINE, // !GEN DEPRECATED
|
||||
OP_SYMBOL, // !GEN DEPRECATED
|
||||
OP_SRANGE, // !GEN DEPRECATED
|
||||
OP_JUMP_PRI, // !GEN
|
||||
OP_SWITCH, //VERIFIED
|
||||
OP_CASETBL, //VERIFIED
|
||||
OP_SWAP_PRI, //VERIFIED
|
||||
OP_SWAP_ALT, //~VERIFIED (swap.alt)
|
||||
OP_PUSH_ADR, //VERIFIED
|
||||
OP_NOP, //VERIFIED (lol)
|
||||
OP_SYSREQ_N, //VERIFIED
|
||||
OP_SYMTAG, // !GEN DEPRECATED
|
||||
OP_BREAK, //DONE
|
||||
OP_PUSH2_C, //~VERIFIED (push3.c)
|
||||
OP_PUSH2, //VERIFIED
|
||||
OP_PUSH2_S, //VERIFIED
|
||||
OP_PUSH2_ADR, //VERIFIED
|
||||
OP_PUSH3_C, //VERIFIED
|
||||
OP_PUSH3, //~VERIFIED (push2)
|
||||
OP_PUSH3_S, //~VERIFIED (push2.s)
|
||||
OP_PUSH3_ADR, //~VERIFIED (push2.adr)
|
||||
OP_PUSH4_C, //~VERIFIED (push3.c)
|
||||
OP_PUSH4, //~VERIFIED (push2)
|
||||
OP_PUSH4_S, //~VERIFIED (push2.s)
|
||||
OP_PUSH4_ADR, //~VERIFIED (push2.adr)
|
||||
OP_PUSH5_C, //~VERIFIED (push3.c)
|
||||
OP_PUSH5, //~VERIFIED (push2)
|
||||
OP_PUSH5_S, //~VERIFIED (push2.s)
|
||||
OP_PUSH5_ADR, //~VERIFIED (push2.adr)
|
||||
OP_LOAD_BOTH, //VERIFIED
|
||||
OP_LOAD_S_BOTH, //VERIFIED
|
||||
OP_CONST, //VERIFIED
|
||||
OP_CONST_S, //DONE
|
||||
/* ----- */
|
||||
OP_SYSREQ_D, // !GEN UNSUPPORT
|
||||
OP_SYSREQ_ND, // !GEN UNSUPPORT
|
||||
/* ----- */
|
||||
OP_TRACKER_PUSH_C, //DONE
|
||||
OP_TRACKER_POP_SETHEAP, //VERIFIED
|
||||
OP_GENARRAY, //VERIFIED
|
||||
OP_GENARRAY_Z, //-VERIFIED (not tested for 1D arrays)
|
||||
OP_STRADJUST_PRI, //VERIFIED
|
||||
OP_STACKADJUST, //:TODO: VERIFY
|
||||
OP_ENDPROC, //VERIFIED
|
||||
OP_FABS, //VERIFIED
|
||||
OP_FLOAT, //VERIFIED
|
||||
OP_FLOATADD, //VERIFIED
|
||||
OP_FLOATSUB, //VERIFIED
|
||||
OP_FLOATMUL, //VERIFIED
|
||||
OP_FLOATDIV, //VERIFIED
|
||||
OP_RND_TO_NEAREST, //VERIFIED
|
||||
OP_RND_TO_FLOOR, //VERIFIED
|
||||
OP_RND_TO_CEIL, //VERIFIED
|
||||
OP_RND_TO_ZERO, //VERIFIED
|
||||
OP_FLOATCMP, //VERIFIED
|
||||
/* ----- */
|
||||
OP_NUM_OPCODES
|
||||
} OPCODE;
|
||||
|
||||
#endif //_INCLUDE_SOURCEPAWN_JIT_X86_OPCODE_INFO_H_
|
@ -1,779 +0,0 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
case OP_MOVE_PRI:
|
||||
{
|
||||
WriteOp_Move_Pri(jit);
|
||||
break;
|
||||
}
|
||||
case OP_MOVE_ALT:
|
||||
{
|
||||
WriteOp_Move_Alt(jit);
|
||||
break;
|
||||
}
|
||||
case OP_XCHG:
|
||||
{
|
||||
WriteOp_Xchg(jit);
|
||||
break;
|
||||
}
|
||||
case OP_PUSH:
|
||||
{
|
||||
WriteOp_Push(jit);
|
||||
break;
|
||||
}
|
||||
case OP_PUSH_S:
|
||||
{
|
||||
WriteOp_Push_S(jit);
|
||||
break;
|
||||
}
|
||||
case OP_PUSH2_C:
|
||||
{
|
||||
WriteOp_Push2_C(jit);
|
||||
break;
|
||||
}
|
||||
case OP_PUSH3_C:
|
||||
{
|
||||
WriteOp_Push3_C(jit);
|
||||
break;
|
||||
}
|
||||
case OP_PUSH4_C:
|
||||
{
|
||||
WriteOp_Push4_C(jit);
|
||||
break;
|
||||
}
|
||||
case OP_PUSH5_C:
|
||||
{
|
||||
WriteOp_Push5_C(jit);
|
||||
break;
|
||||
}
|
||||
case OP_PUSH2_ADR:
|
||||
{
|
||||
WriteOp_Push2_Adr(jit);
|
||||
break;
|
||||
}
|
||||
case OP_PUSH3_ADR:
|
||||
{
|
||||
WriteOp_Push3_Adr(jit);
|
||||
break;
|
||||
}
|
||||
case OP_PUSH4_ADR:
|
||||
{
|
||||
WriteOp_Push4_Adr(jit);
|
||||
break;
|
||||
}
|
||||
case OP_PUSH5_ADR:
|
||||
{
|
||||
WriteOp_Push5_Adr(jit);
|
||||
break;
|
||||
}
|
||||
case OP_PUSH2_S:
|
||||
{
|
||||
WriteOp_Push2_S(jit);
|
||||
break;
|
||||
}
|
||||
case OP_PUSH3_S:
|
||||
{
|
||||
WriteOp_Push3_S(jit);
|
||||
break;
|
||||
}
|
||||
case OP_PUSH4_S:
|
||||
{
|
||||
WriteOp_Push4_S(jit);
|
||||
break;
|
||||
}
|
||||
case OP_PUSH5_S:
|
||||
{
|
||||
WriteOp_Push5_S(jit);
|
||||
break;
|
||||
}
|
||||
case OP_PUSH5:
|
||||
{
|
||||
WriteOp_Push5(jit);
|
||||
break;
|
||||
}
|
||||
case OP_PUSH4:
|
||||
{
|
||||
WriteOp_Push4(jit);
|
||||
break;
|
||||
}
|
||||
case OP_PUSH3:
|
||||
{
|
||||
WriteOp_Push3(jit);
|
||||
break;
|
||||
}
|
||||
case OP_PUSH2:
|
||||
{
|
||||
WriteOp_Push2(jit);
|
||||
break;
|
||||
}
|
||||
case OP_ZERO_PRI:
|
||||
{
|
||||
WriteOp_Zero_Pri(jit);
|
||||
break;
|
||||
}
|
||||
case OP_ZERO_ALT:
|
||||
{
|
||||
WriteOp_Zero_Alt(jit);
|
||||
break;
|
||||
}
|
||||
case OP_PROC:
|
||||
{
|
||||
WriteOp_Proc(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SHL:
|
||||
{
|
||||
WriteOp_Shl(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SHR:
|
||||
{
|
||||
WriteOp_Shr(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SSHR:
|
||||
{
|
||||
WriteOp_Sshr(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SHL_C_PRI:
|
||||
{
|
||||
WriteOp_Shl_C_Pri(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SHL_C_ALT:
|
||||
{
|
||||
WriteOp_Shl_C_Alt(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SHR_C_PRI:
|
||||
{
|
||||
WriteOp_Shr_C_Pri(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SHR_C_ALT:
|
||||
{
|
||||
WriteOp_Shr_C_Alt(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SMUL:
|
||||
{
|
||||
WriteOp_SMul(jit);
|
||||
break;
|
||||
}
|
||||
case OP_ADD:
|
||||
{
|
||||
WriteOp_Add(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SUB:
|
||||
{
|
||||
WriteOp_Sub(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SUB_ALT:
|
||||
{
|
||||
WriteOp_Sub_Alt(jit);
|
||||
break;
|
||||
}
|
||||
case OP_NOP:
|
||||
{
|
||||
/* do nothing */
|
||||
break;
|
||||
}
|
||||
case OP_NOT:
|
||||
{
|
||||
WriteOp_Not(jit);
|
||||
break;
|
||||
}
|
||||
case OP_NEG:
|
||||
{
|
||||
WriteOp_Neg(jit);
|
||||
break;
|
||||
}
|
||||
case OP_XOR:
|
||||
{
|
||||
WriteOp_Xor(jit);
|
||||
break;
|
||||
}
|
||||
case OP_OR:
|
||||
{
|
||||
WriteOp_Or(jit);
|
||||
break;
|
||||
}
|
||||
case OP_AND:
|
||||
{
|
||||
WriteOp_And(jit);
|
||||
break;
|
||||
}
|
||||
case OP_INVERT:
|
||||
{
|
||||
WriteOp_Invert(jit);
|
||||
break;
|
||||
}
|
||||
case OP_ADD_C:
|
||||
{
|
||||
WriteOp_Add_C(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SMUL_C:
|
||||
{
|
||||
WriteOp_SMul_C(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SIGN_PRI:
|
||||
{
|
||||
WriteOp_Sign_Pri(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SIGN_ALT:
|
||||
{
|
||||
WriteOp_Sign_Alt(jit);
|
||||
break;
|
||||
}
|
||||
case OP_EQ:
|
||||
{
|
||||
WriteOp_Eq(jit);
|
||||
break;
|
||||
}
|
||||
case OP_NEQ:
|
||||
{
|
||||
WriteOp_Neq(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SLESS:
|
||||
{
|
||||
WriteOp_Sless(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SLEQ:
|
||||
{
|
||||
WriteOp_Sleq(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SGRTR:
|
||||
{
|
||||
WriteOp_Sgrtr(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SGEQ:
|
||||
{
|
||||
WriteOp_Sgeq(jit);
|
||||
break;
|
||||
}
|
||||
case OP_EQ_C_PRI:
|
||||
{
|
||||
WriteOp_Eq_C_Pri(jit);
|
||||
break;
|
||||
}
|
||||
case OP_EQ_C_ALT:
|
||||
{
|
||||
WriteOp_Eq_C_Alt(jit);
|
||||
break;
|
||||
}
|
||||
case OP_INC_PRI:
|
||||
{
|
||||
WriteOp_Inc_Pri(jit);
|
||||
break;
|
||||
}
|
||||
case OP_INC_ALT:
|
||||
{
|
||||
WriteOp_Inc_Alt(jit);
|
||||
break;
|
||||
}
|
||||
case OP_INC:
|
||||
{
|
||||
WriteOp_Inc(jit);
|
||||
break;
|
||||
}
|
||||
case OP_INC_S:
|
||||
{
|
||||
WriteOp_Inc_S(jit);
|
||||
break;
|
||||
}
|
||||
case OP_INC_I:
|
||||
{
|
||||
WriteOp_Inc_I(jit);
|
||||
break;
|
||||
}
|
||||
case OP_DEC_PRI:
|
||||
{
|
||||
WriteOp_Dec_Pri(jit);
|
||||
break;
|
||||
}
|
||||
case OP_DEC_ALT:
|
||||
{
|
||||
WriteOp_Dec_Alt(jit);
|
||||
break;
|
||||
}
|
||||
case OP_DEC:
|
||||
{
|
||||
WriteOp_Dec(jit);
|
||||
break;
|
||||
}
|
||||
case OP_DEC_S:
|
||||
{
|
||||
WriteOp_Dec_S(jit);
|
||||
break;
|
||||
}
|
||||
case OP_DEC_I:
|
||||
{
|
||||
WriteOp_Dec_I(jit);
|
||||
break;
|
||||
}
|
||||
case OP_LOAD_PRI:
|
||||
{
|
||||
WriteOp_Load_Pri(jit);
|
||||
break;
|
||||
}
|
||||
case OP_LOAD_ALT:
|
||||
{
|
||||
WriteOp_Load_Alt(jit);
|
||||
break;
|
||||
}
|
||||
case OP_LOAD_S_PRI:
|
||||
{
|
||||
WriteOp_Load_S_Pri(jit);
|
||||
break;
|
||||
}
|
||||
case OP_LOAD_S_ALT:
|
||||
{
|
||||
WriteOp_Load_S_Alt(jit);
|
||||
break;
|
||||
}
|
||||
case OP_LREF_PRI:
|
||||
{
|
||||
WriteOp_Lref_Pri(jit);
|
||||
break;
|
||||
}
|
||||
case OP_LREF_ALT:
|
||||
{
|
||||
WriteOp_Lref_Alt(jit);
|
||||
break;
|
||||
}
|
||||
case OP_LREF_S_PRI:
|
||||
{
|
||||
WriteOp_Lref_S_Pri(jit);
|
||||
break;
|
||||
}
|
||||
case OP_LREF_S_ALT:
|
||||
{
|
||||
WriteOp_Lref_S_Alt(jit);
|
||||
break;
|
||||
}
|
||||
case OP_CONST_PRI:
|
||||
{
|
||||
WriteOp_Const_Pri(jit);
|
||||
break;
|
||||
}
|
||||
case OP_CONST_ALT:
|
||||
{
|
||||
WriteOp_Const_Alt(jit);
|
||||
break;
|
||||
}
|
||||
case OP_ADDR_PRI:
|
||||
{
|
||||
WriteOp_Addr_Pri(jit);
|
||||
break;
|
||||
}
|
||||
case OP_ADDR_ALT:
|
||||
{
|
||||
WriteOp_Addr_Alt(jit);
|
||||
break;
|
||||
}
|
||||
case OP_STOR_PRI:
|
||||
{
|
||||
WriteOp_Stor_Pri(jit);
|
||||
break;
|
||||
}
|
||||
case OP_STOR_ALT:
|
||||
{
|
||||
WriteOp_Stor_Alt(jit);
|
||||
break;
|
||||
}
|
||||
case OP_STOR_S_PRI:
|
||||
{
|
||||
WriteOp_Stor_S_Pri(jit);
|
||||
break;
|
||||
}
|
||||
case OP_STOR_S_ALT:
|
||||
{
|
||||
WriteOp_Stor_S_Alt(jit);
|
||||
break;
|
||||
}
|
||||
case OP_IDXADDR:
|
||||
{
|
||||
WriteOp_Idxaddr(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SREF_PRI:
|
||||
{
|
||||
WriteOp_Sref_Pri(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SREF_ALT:
|
||||
{
|
||||
WriteOp_Sref_Alt(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SREF_S_PRI:
|
||||
{
|
||||
WriteOp_Sref_S_Pri(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SREF_S_ALT:
|
||||
{
|
||||
WriteOp_Sref_S_Alt(jit);
|
||||
break;
|
||||
}
|
||||
case OP_POP_PRI:
|
||||
{
|
||||
WriteOp_Pop_Pri(jit);
|
||||
break;
|
||||
}
|
||||
case OP_POP_ALT:
|
||||
{
|
||||
WriteOp_Pop_Alt(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SWAP_PRI:
|
||||
{
|
||||
WriteOp_Swap_Pri(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SWAP_ALT:
|
||||
{
|
||||
WriteOp_Swap_Alt(jit);
|
||||
break;
|
||||
}
|
||||
case OP_PUSH_ADR:
|
||||
{
|
||||
WriteOp_PushAddr(jit);
|
||||
break;
|
||||
}
|
||||
case OP_MOVS:
|
||||
{
|
||||
WriteOp_Movs(jit);
|
||||
break;
|
||||
}
|
||||
case OP_FILL:
|
||||
{
|
||||
WriteOp_Fill(jit);
|
||||
break;
|
||||
}
|
||||
case OP_PUSH_C:
|
||||
{
|
||||
WriteOp_Push_C(jit);
|
||||
break;
|
||||
}
|
||||
case OP_ZERO:
|
||||
{
|
||||
WriteOp_Zero(jit);
|
||||
break;
|
||||
}
|
||||
case OP_ZERO_S:
|
||||
{
|
||||
WriteOp_Zero_S(jit);
|
||||
break;
|
||||
}
|
||||
case OP_PUSH_PRI:
|
||||
{
|
||||
WriteOp_Push_Pri(jit);
|
||||
break;
|
||||
}
|
||||
case OP_PUSH_ALT:
|
||||
{
|
||||
WriteOp_Push_Alt(jit);
|
||||
break;
|
||||
}
|
||||
case OP_LOAD_BOTH:
|
||||
{
|
||||
WriteOp_Load_Both(jit);
|
||||
break;
|
||||
}
|
||||
case OP_LOAD_S_BOTH:
|
||||
{
|
||||
WriteOp_Load_S_Both(jit);
|
||||
break;
|
||||
}
|
||||
case OP_CONST:
|
||||
{
|
||||
WriteOp_Const(jit);
|
||||
break;
|
||||
}
|
||||
case OP_CONST_S:
|
||||
{
|
||||
WriteOp_Const_S(jit);
|
||||
break;
|
||||
}
|
||||
case OP_LOAD_I:
|
||||
{
|
||||
WriteOp_Load_I(jit);
|
||||
break;
|
||||
}
|
||||
case OP_LODB_I:
|
||||
{
|
||||
WriteOp_Lodb_I(jit);
|
||||
break;
|
||||
}
|
||||
case OP_STOR_I:
|
||||
{
|
||||
WriteOp_Stor_I(jit);
|
||||
break;
|
||||
}
|
||||
case OP_STRB_I:
|
||||
{
|
||||
WriteOp_Strb_I(jit);
|
||||
break;
|
||||
}
|
||||
case OP_LIDX:
|
||||
{
|
||||
WriteOp_Lidx(jit);
|
||||
break;
|
||||
}
|
||||
case OP_LIDX_B:
|
||||
{
|
||||
WriteOp_Lidx_B(jit);
|
||||
break;
|
||||
}
|
||||
case OP_IDXADDR_B:
|
||||
{
|
||||
WriteOp_Idxaddr_B(jit);
|
||||
break;
|
||||
}
|
||||
case OP_STACK:
|
||||
{
|
||||
WriteOp_Stack(jit);
|
||||
break;
|
||||
}
|
||||
case OP_HEAP:
|
||||
{
|
||||
WriteOp_Heap(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SDIV:
|
||||
{
|
||||
WriteOp_SDiv(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SDIV_ALT:
|
||||
{
|
||||
WriteOp_SDiv_Alt(jit);
|
||||
break;
|
||||
}
|
||||
case OP_RETN:
|
||||
{
|
||||
WriteOp_Retn(jit);
|
||||
break;
|
||||
}
|
||||
case OP_BOUNDS:
|
||||
{
|
||||
WriteOp_Bounds(jit);
|
||||
break;
|
||||
}
|
||||
case OP_HALT:
|
||||
{
|
||||
WriteOp_Halt(jit);
|
||||
break;
|
||||
}
|
||||
case OP_BREAK:
|
||||
{
|
||||
WriteOp_Break(jit);
|
||||
break;
|
||||
}
|
||||
case OP_JUMP:
|
||||
{
|
||||
WriteOp_Jump(jit);
|
||||
break;
|
||||
}
|
||||
case OP_JZER:
|
||||
{
|
||||
WriteOp_Jzer(jit);
|
||||
break;
|
||||
}
|
||||
case OP_JNZ:
|
||||
{
|
||||
WriteOp_Jnz(jit);
|
||||
break;
|
||||
}
|
||||
case OP_JEQ:
|
||||
{
|
||||
WriteOp_Jeq(jit);
|
||||
break;
|
||||
}
|
||||
case OP_JNEQ:
|
||||
{
|
||||
WriteOp_Jneq(jit);
|
||||
break;
|
||||
}
|
||||
case OP_JSLESS:
|
||||
{
|
||||
WriteOp_Jsless(jit);
|
||||
break;
|
||||
}
|
||||
case OP_JSGRTR:
|
||||
{
|
||||
WriteOp_JsGrtr(jit);
|
||||
break;
|
||||
}
|
||||
case OP_JSGEQ:
|
||||
{
|
||||
WriteOp_JsGeq(jit);
|
||||
break;
|
||||
}
|
||||
case OP_JSLEQ:
|
||||
{
|
||||
WriteOp_Jsleq(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SWITCH:
|
||||
{
|
||||
WriteOp_Switch(jit);
|
||||
break;
|
||||
}
|
||||
case OP_CASETBL:
|
||||
{
|
||||
WriteOp_Casetbl(jit);
|
||||
break;
|
||||
}
|
||||
case OP_CALL:
|
||||
{
|
||||
WriteOp_Call(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SYSREQ_C:
|
||||
{
|
||||
WriteOp_Sysreq_C(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SYSREQ_N:
|
||||
{
|
||||
WriteOp_Sysreq_N(jit);
|
||||
break;
|
||||
}
|
||||
case OP_TRACKER_PUSH_C:
|
||||
{
|
||||
WriteOp_Tracker_Push_C(jit);
|
||||
break;
|
||||
}
|
||||
case OP_TRACKER_POP_SETHEAP:
|
||||
{
|
||||
WriteOp_Tracker_Pop_SetHeap(jit);
|
||||
break;
|
||||
}
|
||||
case OP_GENARRAY:
|
||||
{
|
||||
WriteOp_GenArray(jit, false);
|
||||
break;
|
||||
}
|
||||
case OP_GENARRAY_Z:
|
||||
{
|
||||
WriteOp_GenArray(jit, true);
|
||||
break;
|
||||
}
|
||||
case OP_STRADJUST_PRI:
|
||||
{
|
||||
WriteOp_Stradjust_Pri(jit);
|
||||
break;
|
||||
}
|
||||
case OP_FABS:
|
||||
{
|
||||
WriteOp_FloatAbs(jit);
|
||||
break;
|
||||
}
|
||||
case OP_FLOAT:
|
||||
{
|
||||
WriteOp_Float(jit);
|
||||
break;
|
||||
}
|
||||
case OP_FLOATADD:
|
||||
{
|
||||
WriteOp_FloatAdd(jit);
|
||||
break;
|
||||
}
|
||||
case OP_FLOATSUB:
|
||||
{
|
||||
WriteOp_FloatSub(jit);
|
||||
break;
|
||||
}
|
||||
case OP_FLOATMUL:
|
||||
{
|
||||
WriteOp_FloatMul(jit);
|
||||
break;
|
||||
}
|
||||
case OP_FLOATDIV:
|
||||
{
|
||||
WriteOp_FloatDiv(jit);
|
||||
break;
|
||||
}
|
||||
case OP_RND_TO_NEAREST:
|
||||
{
|
||||
WriteOp_RountToNearest(jit);
|
||||
break;
|
||||
}
|
||||
case OP_RND_TO_FLOOR:
|
||||
{
|
||||
WriteOp_RoundToFloor(jit);
|
||||
break;
|
||||
}
|
||||
case OP_RND_TO_ZERO:
|
||||
{
|
||||
WriteOp_RoundToZero(jit);
|
||||
break;
|
||||
}
|
||||
case OP_RND_TO_CEIL:
|
||||
{
|
||||
WriteOp_RoundToCeil(jit);
|
||||
break;
|
||||
}
|
||||
case OP_FLOATCMP:
|
||||
{
|
||||
WriteOp_FloatCompare(jit);
|
||||
break;
|
||||
}
|
||||
case OP_STACKADJUST:
|
||||
{
|
||||
WriteOp_StackAdjust(jit);
|
||||
break;
|
||||
}
|
||||
case OP_ENDPROC:
|
||||
{
|
||||
WriteOp_EndProc(jit);
|
||||
break;
|
||||
}
|
||||
#if defined USE_UNGEN_OPCODES
|
||||
#include "ungen_opcode_switch.inc"
|
||||
#endif
|
||||
default:
|
||||
{
|
||||
data->error_set = SP_ERROR_INVALID_INSTRUCTION;
|
||||
break;
|
||||
}
|
@ -1,121 +0,0 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
case OP_UMUL:
|
||||
{
|
||||
WriteOp_UMul(jit);
|
||||
break;
|
||||
}
|
||||
case OP_LESS:
|
||||
{
|
||||
WriteOp_Less(jit);
|
||||
break;
|
||||
}
|
||||
case OP_LEQ:
|
||||
{
|
||||
WriteOp_Leq(jit);
|
||||
break;
|
||||
}
|
||||
case OP_GRTR:
|
||||
{
|
||||
WriteOp_Grtr(jit);
|
||||
break;
|
||||
}
|
||||
case OP_GEQ:
|
||||
{
|
||||
WriteOp_Geq(jit);
|
||||
break;
|
||||
}
|
||||
case OP_ALIGN_PRI:
|
||||
{
|
||||
WriteOp_Align_Pri(jit);
|
||||
break;
|
||||
}
|
||||
case OP_ALIGN_ALT:
|
||||
{
|
||||
WriteOp_Align_Alt(jit);
|
||||
break;
|
||||
}
|
||||
case OP_LCTRL:
|
||||
{
|
||||
WriteOp_Lctrl(jit);
|
||||
break;
|
||||
}
|
||||
case OP_SCTRL:
|
||||
{
|
||||
WriteOp_Sctrl(jit);
|
||||
break;
|
||||
}
|
||||
case OP_UDIV:
|
||||
{
|
||||
WriteOp_UDiv(jit);
|
||||
break;
|
||||
}
|
||||
case OP_UDIV_ALT:
|
||||
{
|
||||
WriteOp_UDiv_Alt(jit);
|
||||
break;
|
||||
}
|
||||
case OP_RET:
|
||||
{
|
||||
WriteOp_Ret(jit);
|
||||
break;
|
||||
}
|
||||
case OP_CMPS:
|
||||
{
|
||||
WriteOp_Cmps(jit);
|
||||
break;
|
||||
}
|
||||
case OP_JREL:
|
||||
{
|
||||
WriteOp_JRel(jit);
|
||||
break;
|
||||
}
|
||||
case OP_JLESS:
|
||||
{
|
||||
WriteOp_Jless(jit);
|
||||
break;
|
||||
}
|
||||
case OP_JLEQ:
|
||||
{
|
||||
WriteOp_Jeq(jit);
|
||||
break;
|
||||
}
|
||||
case OP_JGRTR:
|
||||
{
|
||||
WriteOp_Jgrtr(jit);
|
||||
break;
|
||||
}
|
||||
case OP_JGEQ:
|
||||
{
|
||||
WriteOp_Jgeq(jit);
|
||||
break;
|
||||
}
|
@ -1,325 +0,0 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_SOURCEPAWN_JIT_X86_UNGEN_OPCODES_H_
|
||||
#define _INCLUDE_SOURCEPAWN_JIT_X86_UNGEN_OPCODES_H_
|
||||
|
||||
inline void WriteOp_UMul(JitWriter *jit)
|
||||
{
|
||||
//mov ecx, edx
|
||||
//mul edx
|
||||
//mov edx, ecx
|
||||
IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_ALT, MOD_REG);
|
||||
IA32_Mul_Rm(jit, AMX_REG_ALT, MOD_REG);
|
||||
IA32_Mov_Reg_Rm(jit, AMX_REG_ALT, AMX_REG_TMP, MOD_REG);
|
||||
}
|
||||
|
||||
inline void WriteOp_Less(JitWriter *jit)
|
||||
{
|
||||
//cmp eax, edx ; PRI < ALT ? (unsigned)
|
||||
//mov eax, 0
|
||||
//setb al
|
||||
IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
|
||||
IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0);
|
||||
IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_B);
|
||||
}
|
||||
|
||||
inline void WriteOp_Leq(JitWriter *jit)
|
||||
{
|
||||
//cmp eax, edx ; PRI <= ALT ? (unsigned)
|
||||
//mov eax, 0
|
||||
//setbe al
|
||||
IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
|
||||
IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0);
|
||||
IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_BE);
|
||||
}
|
||||
|
||||
inline void WriteOp_Grtr(JitWriter *jit)
|
||||
{
|
||||
//cmp eax, edx ; PRI > ALT ? (unsigned)
|
||||
//mov eax, 0
|
||||
//seta al
|
||||
IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
|
||||
IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0);
|
||||
IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_A);
|
||||
}
|
||||
|
||||
inline void WriteOp_Geq(JitWriter *jit)
|
||||
{
|
||||
//cmp eax, edx ; PRI >= ALT ? (unsigned)
|
||||
//mov eax, 0
|
||||
//setae al
|
||||
IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
|
||||
IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0);
|
||||
IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_AE);
|
||||
}
|
||||
|
||||
inline void WriteOp_Align_Pri(JitWriter *jit)
|
||||
{
|
||||
//xor eax, <cellsize - val>
|
||||
cell_t val = sizeof(cell_t) - jit->read_cell();
|
||||
if (val <= SCHAR_MAX && val >= SCHAR_MIN)
|
||||
{
|
||||
IA32_Xor_Rm_Imm8(jit, AMX_REG_PRI, MOD_REG, (jit_int8_t)val);
|
||||
} else {
|
||||
IA32_Xor_Eax_Imm32(jit, val);
|
||||
}
|
||||
}
|
||||
|
||||
inline void WriteOp_Align_Alt(JitWriter *jit)
|
||||
{
|
||||
//xor edx, <cellsize - val>
|
||||
cell_t val = sizeof(cell_t) - jit->read_cell();
|
||||
if (val <= SCHAR_MAX && val >= SCHAR_MIN)
|
||||
{
|
||||
IA32_Xor_Rm_Imm8(jit, AMX_REG_ALT, MOD_REG, (jit_int8_t)val);
|
||||
} else {
|
||||
IA32_Xor_Rm_Imm32(jit, AMX_REG_ALT, MOD_REG, val);
|
||||
}
|
||||
}
|
||||
|
||||
inline void WriteOp_Cmps(JitWriter *jit)
|
||||
{
|
||||
//push edi
|
||||
//push esi
|
||||
//lea esi, [ebp+edx]
|
||||
//lea edi, [ebp+eax]
|
||||
//mov ecx, <val>
|
||||
unsigned int val = jit->read_cell();
|
||||
|
||||
IA32_Push_Reg(jit, REG_EDI);
|
||||
IA32_Push_Reg(jit, REG_ESI);
|
||||
IA32_Lea_Reg_DispEBPRegMult(jit, REG_ESI, AMX_REG_DAT, AMX_REG_ALT, NOSCALE);
|
||||
IA32_Lea_Reg_DispEBPRegMult(jit, REG_EDI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE);
|
||||
IA32_Mov_Reg_Imm32(jit, REG_ECX, val);
|
||||
|
||||
//xor eax, eax
|
||||
//repe cmpsb
|
||||
//je :cmps1
|
||||
IA32_Xor_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_PRI, MOD_REG);
|
||||
IA32_Rep(jit);
|
||||
IA32_Cmpsb(jit);
|
||||
jitoffs_t jmp = IA32_Jump_Cond_Imm8(jit, CC_E, 0);
|
||||
|
||||
//sbb eax, eax
|
||||
//sbb eax, -1
|
||||
IA32_Sbb_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_PRI, MOD_REG);
|
||||
IA32_Sbb_Rm_Imm8(jit, AMX_REG_PRI, -1, MOD_REG);
|
||||
|
||||
//:cmps1
|
||||
//pop esi
|
||||
//pop edi
|
||||
IA32_Send_Jump8_Here(jit, jmp);
|
||||
IA32_Pop_Reg(jit, REG_ESI);
|
||||
IA32_Pop_Reg(jit, REG_EDI);
|
||||
}
|
||||
|
||||
inline void WriteOp_Lctrl(JitWriter *jit)
|
||||
{
|
||||
cell_t val = jit->read_cell();
|
||||
switch (val)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
//mov ecx, [esi+ctx]
|
||||
//mov eax, [ecx+ctx.codebase]
|
||||
IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_CONTEXT);
|
||||
IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_PRI, AMX_REG_TMP, offsetof(sp_context_t, codebase));
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
//mov eax, ebp
|
||||
IA32_Mov_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_DAT, MOD_REG);
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
//mov eax, [esi+hea]
|
||||
IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_PRI, AMX_REG_INFO, AMX_INFO_HEAP);
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
//mov ecx, [esi+ctx]
|
||||
//mov eax, [ecx+ctx.memory]
|
||||
IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_CONTEXT);
|
||||
IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_PRI, AMX_REG_TMP, offsetof(sp_context_t, memory));
|
||||
break;
|
||||
}
|
||||
case 4:
|
||||
{
|
||||
//mov eax, edi
|
||||
//sub eax, ebp - unrelocate
|
||||
IA32_Mov_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_STK, MOD_REG);
|
||||
IA32_Sub_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_DAT, MOD_REG);
|
||||
break;
|
||||
}
|
||||
case 5:
|
||||
{
|
||||
//mov eax, [esi+frm]
|
||||
IA32_Mov_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_INFO, MOD_MEM_REG);
|
||||
break;
|
||||
}
|
||||
case 6:
|
||||
{
|
||||
//mov eax, [cip]
|
||||
jitoffs_t imm32 = IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0);
|
||||
jitoffs_t save = jit->get_outputpos();
|
||||
jit->set_outputpos(imm32);
|
||||
jit->write_int32((uint32_t)(jit->outbase + save));
|
||||
jit->set_outputpos(save);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void WriteOp_Sctrl(JitWriter *jit)
|
||||
{
|
||||
cell_t val = jit->read_cell();
|
||||
switch (val)
|
||||
{
|
||||
case 2:
|
||||
{
|
||||
//mov [esi+hea], eax
|
||||
IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, AMX_REG_PRI, AMX_INFO_HEAP);
|
||||
break;
|
||||
}
|
||||
case 4:
|
||||
{
|
||||
//lea edi, [ebp+eax]
|
||||
IA32_Lea_Reg_DispEBPRegMult(jit, AMX_REG_STK, AMX_REG_DAT, AMX_REG_PRI, NOSCALE);
|
||||
break;
|
||||
}
|
||||
case 5:
|
||||
{
|
||||
//lea ebx, [ebp+eax] - overwrite frm
|
||||
//mov [esi+frm], eax - overwrite stacked frame
|
||||
IA32_Lea_Reg_DispEBPRegMult(jit, AMX_REG_FRM, AMX_REG_DAT, AMX_REG_PRI, NOSCALE);
|
||||
IA32_Mov_Rm_Reg(jit, AMX_REG_INFO, AMX_REG_PRI, MOD_MEM_REG);
|
||||
break;
|
||||
}
|
||||
case 6:
|
||||
{
|
||||
IA32_Jump_Reg(jit, AMX_REG_PRI);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void WriteOp_UDiv(JitWriter *jit)
|
||||
{
|
||||
//mov ecx, edx
|
||||
//xor edx, edx
|
||||
//div ecx
|
||||
IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_ALT, MOD_REG);
|
||||
IA32_Xor_Reg_Rm(jit, AMX_REG_ALT, AMX_REG_ALT, MOD_REG);
|
||||
Write_Check_DivZero(jit, AMX_REG_TMP);
|
||||
IA32_Div_Rm(jit, AMX_REG_TMP, MOD_REG);
|
||||
}
|
||||
|
||||
inline void WriteOp_UDiv_Alt(JitWriter *jit)
|
||||
{
|
||||
//mov ecx, eax
|
||||
//mov eax, edx
|
||||
//xor edx, edx
|
||||
//div ecx
|
||||
IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_PRI, MOD_REG);
|
||||
IA32_Mov_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
|
||||
IA32_Xor_Reg_Rm(jit, AMX_REG_ALT, AMX_REG_ALT, MOD_REG);
|
||||
Write_Check_DivZero(jit, AMX_REG_TMP);
|
||||
IA32_Div_Rm(jit, AMX_REG_TMP, MOD_REG);
|
||||
}
|
||||
|
||||
inline void WriteOp_Ret(JitWriter *jit)
|
||||
{
|
||||
//mov ebx, [edi] - get old FRM
|
||||
//add edi, 4 - pop stack
|
||||
//mov [esi+frm], ebx - restore
|
||||
//add ebx, ebp - relocate
|
||||
//ret
|
||||
IA32_Mov_Reg_Rm(jit, AMX_REG_FRM, AMX_REG_STK, MOD_MEM_REG);
|
||||
IA32_Add_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG);
|
||||
IA32_Mov_Rm_Reg(jit, AMX_REG_INFO, AMX_REG_FRM, MOD_MEM_REG);
|
||||
IA32_Add_Reg_Rm(jit, AMX_REG_FRM, AMX_REG_DAT, MOD_REG);
|
||||
IA32_Return(jit);
|
||||
}
|
||||
|
||||
inline void WriteOp_JRel(JitWriter *jit)
|
||||
{
|
||||
//jmp <offs> ;relative jump
|
||||
cell_t cip_offs = jit->read_cell();
|
||||
|
||||
/* Note that since code size calculation has to be done in the same
|
||||
* phase as building relocation information, we cannot know the jump size
|
||||
* beforehand. Thus, we always write full 32bit jumps for safety.
|
||||
*/
|
||||
jitoffs_t jmp = IA32_Jump_Imm32(jit, 0);
|
||||
IA32_Write_Jump32(jit, jmp, RelocLookup(jit, cip_offs));
|
||||
}
|
||||
|
||||
inline void WriteOp_Jless(JitWriter *jit)
|
||||
{
|
||||
//cmp eax, edx
|
||||
//jb <target>
|
||||
cell_t target = jit->read_cell();
|
||||
IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
|
||||
IA32_Jump_Cond_Imm32(jit, CC_B, RelocLookup(jit, target, false));
|
||||
}
|
||||
|
||||
inline void WriteOp_Jleq(JitWriter *jit)
|
||||
{
|
||||
//cmp eax, edx
|
||||
//jbe <target>
|
||||
cell_t target = jit->read_cell();
|
||||
IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
|
||||
IA32_Jump_Cond_Imm32(jit, CC_BE, RelocLookup(jit, target, false));
|
||||
}
|
||||
|
||||
inline void WriteOp_Jgrtr(JitWriter *jit)
|
||||
{
|
||||
//cmp eax, edx
|
||||
//ja <target>
|
||||
cell_t target = jit->read_cell();
|
||||
IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
|
||||
IA32_Jump_Cond_Imm32(jit, CC_A, RelocLookup(jit, target, false));
|
||||
}
|
||||
|
||||
inline void WriteOp_Jgeq(JitWriter *jit)
|
||||
{
|
||||
//cmp eax, edx
|
||||
//jae <target>
|
||||
cell_t target = jit->read_cell();
|
||||
IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG);
|
||||
IA32_Jump_Cond_Imm32(jit, CC_AE, RelocLookup(jit, target, false));
|
||||
}
|
||||
|
||||
#endif //_INCLUDE_SOURCEPAWN_JIT_X86_UNGEN_OPCODES_H_
|
Loading…
Reference in New Issue
Block a user