From 9e56725406639e42caaad2733f56c66b0f5dccf5 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 8 Aug 2013 09:41:24 -0700 Subject: [PATCH] Refactor the JIT to use a newer, simpler macro assembler. (bug 5827, r=ann) --- public/jit/assembler.h | 294 ++ public/jit/x86/assembler-x86.h | 842 ++++ public/jit/x86/x86_macros.h | 1509 +------ public/sourcepawn/ke_allocator_policies.h | 53 + public/sourcepawn/ke_utility.h | 318 ++ public/sourcepawn/ke_vector.h | 166 + public/sourcepawn/sp_vm_types.h | 4 +- sourcepawn/jit/AMBuilder | 2 +- sourcepawn/jit/BaseRuntime.cpp | 843 ++-- sourcepawn/jit/BaseRuntime.h | 134 +- sourcepawn/jit/Makefile | 2 +- sourcepawn/jit/Makefile.shell | 111 + sourcepawn/jit/dll_exports.cpp | 339 +- sourcepawn/jit/engine2.cpp | 10 +- sourcepawn/jit/opcodes.cpp | 137 + sourcepawn/jit/opcodes.h | 262 ++ sourcepawn/jit/sp_vm_basecontext.cpp | 54 +- sourcepawn/jit/sp_vm_basecontext.h | 1 - sourcepawn/jit/sp_vm_engine.cpp | 4 +- sourcepawn/jit/x86/jit_x86.cpp | 4669 ++++++++------------ sourcepawn/jit/x86/jit_x86.h | 256 +- sourcepawn/jit/x86/opcode_helpers.cpp | 706 --- sourcepawn/jit/x86/opcode_helpers.h | 317 -- sourcepawn/jit/x86/opcode_switch.inc | 779 ---- sourcepawn/jit/x86/ungen_opcode_switch.inc | 121 - sourcepawn/jit/x86/ungen_opcodes.h | 325 -- 26 files changed, 5150 insertions(+), 7108 deletions(-) create mode 100644 public/jit/assembler.h create mode 100644 public/jit/x86/assembler-x86.h create mode 100644 public/sourcepawn/ke_allocator_policies.h create mode 100644 public/sourcepawn/ke_utility.h create mode 100644 public/sourcepawn/ke_vector.h create mode 100644 sourcepawn/jit/Makefile.shell create mode 100644 sourcepawn/jit/opcodes.cpp create mode 100644 sourcepawn/jit/opcodes.h delete mode 100644 sourcepawn/jit/x86/opcode_helpers.cpp delete mode 100644 sourcepawn/jit/x86/opcode_helpers.h delete mode 100644 sourcepawn/jit/x86/opcode_switch.inc delete mode 100644 sourcepawn/jit/x86/ungen_opcode_switch.inc delete mode 100644 sourcepawn/jit/x86/ungen_opcodes.h diff --git a/public/jit/assembler.h b/public/jit/assembler.h new file mode 100644 index 00000000..d37a3ab7 --- /dev/null +++ b/public/jit/assembler.h @@ -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 . + * + * 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 . + * + * Version: $Id$ + */ +#ifndef _include_sourcepawn_assembler_h__ +#define _include_sourcepawn_assembler_h__ + +#include +#include +#include +#include +#include + +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(byte); + } + void writeInt32(int32_t word) { + write(word); + } + void writeUint32(uint32_t word) { + write(word); + } + void writePointer(void *ptr) { + write(ptr); + } + + template + void write(const T &t) { + assertCanWrite(sizeof(T)); + *reinterpret_cast(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__ + diff --git a/public/jit/x86/assembler-x86.h b/public/jit/x86/assembler-x86.h new file mode 100644 index 00000000..5afcd443 --- /dev/null +++ b/public/jit/x86/assembler-x86.h @@ -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 . + * + * 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 . + * + * Version: $Id$ + */ +#ifndef _include_sourcepawn_assembler_x86_h__ +#define _include_sourcepawn_assembler_x86_h__ + +#include +#include +#include + +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(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(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(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(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(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(ip - 4) = delta; + } + + void emitToExecutableMemory(void *code) { + assert(!outOfMemory()); + + // Relocate anything we emitted as rel32 with an external pointer. + uint8_t *base = reinterpret_cast(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(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(base + offset - 4); + *reinterpret_cast(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 + void shift_cl(const T &t, uint8_t r) { + emit1(0xd3, r, t); + } + + template + 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 external_refs_; + ke::Vector local_refs_; +}; + +#endif // _include_sourcepawn_assembler_x86_h__ + diff --git a/public/jit/x86/x86_macros.h b/public/jit/x86/x86_macros.h index 8c371cd4..685a5c2b 100644 --- a/public/jit/x86/x86_macros.h +++ b/public/jit/x86/x86_macros.h @@ -32,6 +32,10 @@ #ifndef _INCLUDE_JIT_X86_MACROS_H #define _INCLUDE_JIT_X86_MACROS_H +// :XXX: +// :XXX: This file is deprecated. For new code, use assembler-x86.h. +// :XXX: + #include //MOD R/M @@ -83,120 +87,38 @@ #define CC_G 0xF #define CC_NLE CC_G -//Opcodes with encoding information -#define IA32_XOR_RM_REG 0x31 // encoding is /r -#define IA32_XOR_REG_RM 0x33 // encoding is /r -#define IA32_XOR_EAX_IMM32 0x35 // encoding is /r -#define IA32_XOR_RM_IMM32 0x81 // encoding is /6 -#define IA32_XOR_RM_IMM8 0x83 // encoding is /6 -#define IA32_ADD_RM_REG 0x01 // encoding is /r -#define IA32_ADD_REG_RM 0x03 // encoding is /r -#define IA32_ADD_RM_IMM32 0x81 // encoding is /0 -#define IA32_ADD_RM_IMM8 0x83 // encoding is /0 -#define IA32_ADD_EAX_IMM32 0x05 // no extra encoding -#define IA32_SUB_RM_REG 0x29 // encoding is /r -#define IA32_SUB_REG_RM 0x2B // encoding is /r -#define IA32_SUB_RM_IMM8 0x83 // encoding is /5 -#define IA32_SUB_RM_IMM32 0x81 // encoding is /5 -#define IA32_SBB_REG_RM 0x1B // encoding is /r -#define IA32_SBB_RM_IMM8 0x83 // encoding is -#define IA32_JMP_IMM32 0xE9 // encoding is imm32 -#define IA32_JMP_IMM8 0xEB // encoding is imm8 -#define IA32_JMP_RM 0xFF // encoding is /4 -#define IA32_CALL_IMM32 0xE8 // relative call, -#define IA32_CALL_RM 0xFF // encoding is /2 -#define IA32_MOV_REG_IMM 0xB8 // encoding is +r -#define IA32_MOV_RM8_REG 0x88 // encoding is /r -#define IA32_MOV_RM_REG 0x89 // encoding is /r -#define IA32_MOV_REG_RM 0x8B // encoding is /r -#define IA32_MOV_REG8_RM8 0x8A // encoding is /r -#define IA32_MOV_RM8_REG8 0x88 // encoding is /r -#define IA32_MOV_RM_IMM32 0xC7 // encoding is /0 -#define IA32_MOV_EAX_MEM 0xA1 // encoding is -#define IA32_CMP_RM_IMM32 0x81 // encoding is /7 -#define IA32_CMP_RM_IMM8 0x83 // encoding is /7 -#define IA32_CMP_AL_IMM32 0x3C // no extra encoding -#define IA32_CMP_EAX_IMM32 0x3D // no extra encoding -#define IA32_CMP_RM_REG 0x39 // encoding is /r -#define IA32_CMP_REG_RM 0x3B // encoding is /r -#define IA32_CMPSB 0xA6 // no extra encoding -#define IA32_TEST_RM_REG 0x85 // encoding is /r -#define IA32_JCC_IMM 0x70 // encoding is +cc -#define IA32_JCC_IMM32_1 0x0F // opcode part 1 -#define IA32_JCC_IMM32_2 0x80 // encoding is +cc -#define IA32_RET 0xC3 // no extra encoding -#define IA32_RETN 0xC2 // encoding is -#define IA32_NEG_RM 0xF7 // encoding is /3 -#define IA32_INC_REG 0x40 // encoding is +r -#define IA32_INC_RM 0xFF // encoding is /0 -#define IA32_DEC_REG 0x48 // encoding is +r -#define IA32_DEC_RM 0xFF // encoding is /1 -#define IA32_OR_REG_RM 0x0B // encoding is /r -#define IA32_AND_REG_RM 0x23 // encoding is /r -#define IA32_AND_EAX_IMM32 0x25 // encoding is -#define IA32_AND_RM_IMM32 0x81 // encoding is /4 -#define IA32_AND_RM_IMM8 0x83 // encoding is /4 -#define IA32_NOT_RM 0xF7 // encoding is /2 -#define IA32_DIV_RM 0xF7 // encoding is /6 -#define IA32_MUL_RM 0xF7 // encoding is /4 -#define IA32_IDIV_RM 0xF7 // encoding is /7 -#define IA32_IMUL_RM 0xF7 // encoding is /5 -#define IA32_IMUL_REG_IMM32 0x69 // encoding is /r -#define IA32_IMUL_REG_IMM8 0x6B // encoding is /r -#define IA32_IMUL_REG_RM_1 0x0F // encoding is _2 -#define IA32_IMUL_REG_RM_2 0xAF // encoding is /r -#define IA32_SHR_RM_IMM8 0xC1 // encoding is /5 -#define IA32_SHR_RM_1 0xD1 // encoding is /5 -#define IA32_SHL_RM_IMM8 0xC1 // encoding is /4 -#define IA32_SHL_RM_1 0xD1 // encoding is /4 -#define IA32_SAR_RM_CL 0xD3 // encoding is /7 -#define IA32_SAR_RM_1 0xD1 // encoding is /7 -#define IA32_SHR_RM_CL 0xD3 // encoding is /5 -#define IA32_SHL_RM_CL 0xD3 // encoding is /4 -#define IA32_SAR_RM_IMM8 0xC1 // encoding is /7 -#define IA32_SETCC_RM8_1 0x0F // opcode part 1 -#define IA32_SETCC_RM8_2 0x90 // encoding is +cc /0 (8bits) -#define IA32_CMOVCC_RM_1 0x0F // opcode part 1 -#define IA32_CMOVCC_RM_2 0x40 // encoding is +cc /r -#define IA32_XCHG_EAX_REG 0x90 // encoding is +r -#define IA32_LEA_REG_MEM 0x8D // encoding is /r -#define IA32_POP_REG 0x58 // encoding is +r +#define IA32_MOVZX_R32_RM8_1 0x0F // opcode part 1 +#define IA32_MOVZX_R32_RM16_1 0x0F // opcode part 1 #define IA32_PUSH_REG 0x50 // encoding is +r -#define IA32_PUSH_RM 0xFF // encoding is /6 +#define IA32_POP_REG 0x58 // encoding is +r #define IA32_PUSH_IMM32 0x68 // encoding is #define IA32_PUSH_IMM8 0x6A // encoding is -#define IA32_REP 0xF3 // no extra encoding -#define IA32_MOVSD 0xA5 // no extra encoding +#define IA32_ADD_RM_IMM32 0x81 // encoding is /0 +#define IA32_SUB_RM_IMM32 0x81 // encoding is /5 +#define IA32_ADD_RM_IMM8 0x83 // encoding is /0 +#define IA32_AND_RM_IMM8 0x83 // encoding is /4 +#define IA32_SUB_RM_IMM8 0x83 // encoding is /5 +#define IA32_MOV_RM8_REG8 0x88 // encoding is /r +#define IA32_MOV_RM_REG 0x89 // encoding is /r +#define IA32_MOV_REG8_RM8 0x8A // encoding is /r +#define IA32_MOV_REG_RM 0x8B // encoding is /r +#define IA32_LEA_REG_MEM 0x8D // encoding is /r #define IA32_MOVSB 0xA4 // no extra encoding -#define IA32_STOSD 0xAB // no extra encoding -#define IA32_CLD 0xFC // no extra encoding -#define IA32_PUSHAD 0x60 // no extra encoding -#define IA32_POPAD 0x61 // no extra encoding -#define IA32_NOP 0x90 // no extra encoding -#define IA32_INT3 0xCC // no extra encoding -#define IA32_FSTP_MEM32 0xD9 // encoding is /3 -#define IA32_FSTP_MEM64 0xDD // encoding is /3 -#define IA32_FLD_MEM32 0xD9 // encoding is /0 -#define IA32_FLD_MEM64 0xDD // encoding is /0 -#define IA32_FILD_MEM32 0xDB // encoding is /0 -#define IA32_FADD_MEM32 0xD8 // encoding is /0 -#define IA32_FADD_FPREG_ST0_1 0xDC // opcode part 1 -#define IA32_FADD_FPREG_ST0_2 0xC0 // encoding is +r -#define IA32_FSUB_MEM32 0xD8 // encoding is /4 -#define IA32_FMUL_MEM32 0xD8 // encoding is /1 -#define IA32_FDIV_MEM32 0xD8 // encoding is /6 -#define IA32_FSTCW_MEM16_1 0x9B // opcode part 1 -#define IA32_FSTCW_MEM16_2 0xD9 // encoding is /7 -#define IA32_FLDCW_MEM16 0xD9 // encoding is /5 -#define IA32_FISTP_MEM32 0xDB // encoding is /3 -#define IA32_FUCOMIP_1 0xDF // opcode part 1 -#define IA32_FUCOMIP_2 0xE8 // encoding is +r -#define IA32_FSTP_FPREG_1 0xDD // opcode part 1 -#define IA32_FSTP_FPREG_2 0xD8 // encoding is +r -#define IA32_MOVZX_R32_RM8_1 0x0F // opcode part 1 +#define IA32_MOVSD 0xA5 // no extra encoding #define IA32_MOVZX_R32_RM8_2 0xB6 // encoding is /r -#define IA32_MOVZX_R32_RM16_1 0x0F // opcode part 1 #define IA32_MOVZX_R32_RM16_2 0xB7 // encoding is /r +#define IA32_MOV_REG_IMM 0xB8 // encoding is +r +#define IA32_FLD_MEM32 0xD9 // encoding is /0 +#define IA32_FSTP_MEM32 0xD9 // encoding is /3 +#define IA32_FLD_MEM64 0xDD // encoding is /0 +#define IA32_FSTP_MEM64 0xDD // encoding is /3 +#define IA32_CALL_IMM32 0xE8 // relative call, +#define IA32_JMP_IMM32 0xE9 // encoding is imm32 +#define IA32_RETN 0xC2 // encoding is +#define IA32_RET 0xC3 // no extra encoding +#define IA32_REP 0xF3 // no extra encoding +#define IA32_CLD 0xFC // no extra encoding +#define IA32_CALL_RM 0xFF // encoding is /2 inline jit_uint8_t ia32_modrm(jit_uint8_t mode, jit_uint8_t reg, jit_uint8_t rm) { @@ -221,574 +143,9 @@ inline jit_uint8_t ia32_sib(jit_uint8_t mode, jit_uint8_t index, jit_uint8_t bas return sib; } -/*********************** - * INCREMENT/DECREMENT * - ***********************/ - -inline void IA32_Inc_Reg(JitWriter *jit, jit_uint8_t reg) +inline void IA32_Return(JitWriter *jit) { - jit->write_ubyte(IA32_INC_REG+reg); -} - -inline void IA32_Inc_Rm_Disp8(JitWriter *jit, jit_uint8_t reg, jit_int8_t disp) -{ - jit->write_ubyte(IA32_INC_RM); - jit->write_ubyte(ia32_modrm(MOD_DISP8, 0, reg)); - jit->write_byte(disp); -} - -inline void IA32_Inc_Rm_Disp32(JitWriter *jit, jit_uint8_t reg, jit_int32_t disp) -{ - jit->write_ubyte(IA32_INC_RM); - jit->write_ubyte(ia32_modrm(MOD_DISP32, 0, reg)); - jit->write_int32(disp); -} - -inline void IA32_Inc_Rm_Disp_Reg(JitWriter *jit, jit_uint8_t base, jit_uint8_t reg, jit_uint8_t scale) -{ - jit->write_ubyte(IA32_INC_RM); - jit->write_ubyte(ia32_modrm(MOD_MEM_REG, 0, REG_SIB)); - jit->write_ubyte(ia32_sib(scale, reg, base)); -} - -inline void IA32_Dec_Reg(JitWriter *jit, jit_uint8_t reg) -{ - jit->write_ubyte(IA32_DEC_REG+reg); -} - -inline void IA32_Dec_Rm_Disp8(JitWriter *jit, jit_uint8_t reg, jit_int8_t disp) -{ - jit->write_ubyte(IA32_DEC_RM); - jit->write_ubyte(ia32_modrm(MOD_DISP8, 1, reg)); - jit->write_byte(disp); -} - -inline void IA32_Dec_Rm_Disp32(JitWriter *jit, jit_uint8_t reg, jit_int32_t disp) -{ - jit->write_ubyte(IA32_DEC_RM); - jit->write_ubyte(ia32_modrm(MOD_DISP32, 1, reg)); - jit->write_int32(disp); -} - -inline void IA32_Dec_Rm_Disp_Reg(JitWriter *jit, jit_uint8_t base, jit_uint8_t reg, jit_uint8_t scale) -{ - jit->write_ubyte(IA32_DEC_RM); - jit->write_ubyte(ia32_modrm(MOD_MEM_REG, 1, REG_SIB)); - jit->write_ubyte(ia32_sib(scale, reg, base)); -} - -/**************** - * BINARY LOGIC * - ****************/ - -inline void IA32_Xor_Rm_Reg(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t dest_mode) -{ - jit->write_ubyte(IA32_XOR_RM_REG); - jit->write_ubyte(ia32_modrm(dest_mode, src, dest)); -} - -inline void IA32_Xor_Reg_Rm(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t dest_mode) -{ - jit->write_ubyte(IA32_XOR_REG_RM); - jit->write_ubyte(ia32_modrm(dest_mode, dest, src)); -} - -inline void IA32_Xor_Rm_Imm8(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode, jit_int8_t value) -{ - jit->write_ubyte(IA32_XOR_RM_IMM8); - jit->write_ubyte(ia32_modrm(mode, 6, reg)); - jit->write_byte(value); -} - -inline void IA32_Xor_Rm_Imm32(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode, jit_int32_t value) -{ - jit->write_ubyte(IA32_XOR_RM_IMM32); - jit->write_ubyte(ia32_modrm(mode, 6, reg)); - jit->write_int32(value); -} - -inline void IA32_Xor_Eax_Imm32(JitWriter *jit, jit_int32_t value) -{ - jit->write_ubyte(IA32_XOR_EAX_IMM32); - jit->write_int32(value); -} - -inline void IA32_Neg_Rm(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode) -{ - jit->write_ubyte(IA32_NEG_RM); - jit->write_ubyte(ia32_modrm(mode, 3, reg)); -} - -inline void IA32_Or_Reg_Rm(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode) -{ - jit->write_ubyte(IA32_OR_REG_RM); - jit->write_ubyte(ia32_modrm(mode, dest, src)); -} - -inline void IA32_And_Reg_Rm(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode) -{ - jit->write_ubyte(IA32_AND_REG_RM); - jit->write_ubyte(ia32_modrm(mode, dest, src)); -} - -inline void IA32_And_Rm_Imm32(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode, jit_int32_t value) -{ - jit->write_ubyte(IA32_AND_RM_IMM32); - jit->write_ubyte(ia32_modrm(mode, 4, reg)); - jit->write_int32(value); -} - -inline void IA32_And_Rm_Imm8(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode, jit_int8_t value) -{ - jit->write_ubyte(IA32_AND_RM_IMM8); - jit->write_ubyte(ia32_modrm(mode, 4, reg)); - jit->write_byte(value); -} - -inline void IA32_And_Eax_Imm32(JitWriter *jit, jit_int32_t value) -{ - jit->write_ubyte(IA32_AND_EAX_IMM32); - jit->write_int32(value); -} - -inline void IA32_Not_Rm(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode) -{ - jit->write_ubyte(IA32_NOT_RM); - jit->write_ubyte(ia32_modrm(mode, 2, reg)); -} - -inline void IA32_Shr_Rm_Imm8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t value, jit_uint8_t mode) -{ - jit->write_ubyte(IA32_SHR_RM_IMM8); - jit->write_ubyte(ia32_modrm(mode, 5, dest)); - jit->write_ubyte(value); -} - -inline void IA32_Shr_Rm_1(JitWriter *jit, jit_uint8_t dest, jit_uint8_t mode) -{ - jit->write_ubyte(IA32_SHR_RM_1); - jit->write_ubyte(ia32_modrm(mode, 5, dest)); -} - -inline void IA32_Shl_Rm_Imm8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t value, jit_uint8_t mode) -{ - jit->write_ubyte(IA32_SHL_RM_IMM8); - jit->write_ubyte(ia32_modrm(mode, 4, dest)); - jit->write_ubyte(value); -} - -inline void IA32_Shl_Rm_1(JitWriter *jit, jit_uint8_t dest, jit_uint8_t mode) -{ - jit->write_ubyte(IA32_SHL_RM_1); - jit->write_ubyte(ia32_modrm(mode, 4, dest)); -} - -inline void IA32_Sar_Rm_Imm8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t value, jit_uint8_t mode) -{ - jit->write_ubyte(IA32_SAR_RM_IMM8); - jit->write_ubyte(ia32_modrm(mode, 7, dest)); - jit->write_ubyte(value); -} - -inline void IA32_Sar_Rm_CL(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode) -{ - jit->write_ubyte(IA32_SAR_RM_CL); - jit->write_ubyte(ia32_modrm(mode, 7, reg)); -} - -inline void IA32_Sar_Rm_1(JitWriter *jit, jit_uint8_t dest, jit_uint8_t mode) -{ - jit->write_ubyte(IA32_SAR_RM_1); - jit->write_ubyte(ia32_modrm(mode, 7, dest)); -} - -inline void IA32_Shr_Rm_CL(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode) -{ - jit->write_ubyte(IA32_SHR_RM_CL); - jit->write_ubyte(ia32_modrm(mode, 5, reg)); -} - -inline void IA32_Shl_Rm_CL(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode) -{ - jit->write_ubyte(IA32_SHL_RM_CL); - jit->write_ubyte(ia32_modrm(mode, 4, reg)); -} - -inline void IA32_Xchg_Eax_Reg(JitWriter *jit, jit_uint8_t reg) -{ - jit->write_ubyte(IA32_XCHG_EAX_REG+reg); -} - -/********************** - * ARITHMETIC (BASIC) * - **********************/ - -inline void IA32_Add_Rm_Reg(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode) -{ - jit->write_ubyte(IA32_ADD_RM_REG); - jit->write_ubyte(ia32_modrm(mode, src, dest)); -} - -inline void IA32_Add_Reg_Rm(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode) -{ - jit->write_ubyte(IA32_ADD_REG_RM); - jit->write_ubyte(ia32_modrm(mode, dest, src)); -} - -inline void IA32_Add_Rm_Imm8(JitWriter *jit, jit_uint8_t reg, jit_int8_t value, jit_uint8_t mode) -{ - jit->write_ubyte(IA32_ADD_RM_IMM8); - jit->write_ubyte(ia32_modrm(mode, 0, reg)); - jit->write_byte(value); -} - -inline void IA32_Add_Rm_Imm32(JitWriter *jit, jit_uint8_t reg, jit_int32_t value, jit_uint8_t mode) -{ - jit->write_ubyte(IA32_ADD_RM_IMM32); - jit->write_ubyte(ia32_modrm(mode, 0, reg)); - jit->write_int32(value); -} - -inline void IA32_Add_Eax_Imm32(JitWriter *jit, jit_int32_t value) -{ - jit->write_ubyte(IA32_ADD_EAX_IMM32); - jit->write_int32(value); -} - -inline void IA32_Sub_Rm_Reg(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode) -{ - jit->write_ubyte(IA32_SUB_RM_REG); - jit->write_ubyte(ia32_modrm(mode, src, dest)); -} - -inline void IA32_Sub_Reg_Rm(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode) -{ - jit->write_ubyte(IA32_SUB_REG_RM); - jit->write_ubyte(ia32_modrm(mode, dest, src)); -} - -inline void IA32_Sub_Reg_Rm_Disp8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int8_t disp8) -{ - jit->write_ubyte(IA32_SUB_REG_RM); - jit->write_ubyte(ia32_modrm(MOD_DISP8, dest, src)); - jit->write_byte(disp8); -} - -inline void IA32_Sub_Rm_Reg_Disp8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int8_t disp8) -{ - jit->write_ubyte(IA32_SUB_RM_REG); - jit->write_ubyte(ia32_modrm(MOD_DISP8, src, dest)); - jit->write_byte(disp8); -} - -inline void IA32_Sub_Rm_Imm8(JitWriter *jit, jit_uint8_t reg, jit_int8_t val, jit_uint8_t mode) -{ - jit->write_ubyte(IA32_SUB_RM_IMM8); - jit->write_ubyte(ia32_modrm(mode, 5, reg)); - jit->write_byte(val); -} - -inline void IA32_Sub_Rm_Imm32(JitWriter *jit, jit_uint8_t reg, jit_int32_t val, jit_uint8_t mode) -{ - jit->write_ubyte(IA32_SUB_RM_IMM32); - jit->write_ubyte(ia32_modrm(mode, 5, reg)); - jit->write_int32(val); -} - -inline void IA32_Sbb_Reg_Rm(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode) -{ - jit->write_ubyte(IA32_SBB_REG_RM); - jit->write_ubyte(ia32_modrm(mode, dest, src)); -} - -inline void IA32_Sbb_Rm_Imm8(JitWriter *jit, jit_uint8_t dest, jit_int8_t value, jit_uint8_t mode) -{ - jit->write_ubyte(IA32_SBB_RM_IMM8); - jit->write_ubyte(ia32_modrm(mode, 3, dest)); - jit->write_byte(value); -} - -inline void IA32_Div_Rm(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode) -{ - jit->write_ubyte(IA32_DIV_RM); - jit->write_ubyte(ia32_modrm(mode, 6, reg)); -} - -inline void IA32_IDiv_Rm(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode) -{ - jit->write_ubyte(IA32_IDIV_RM); - jit->write_ubyte(ia32_modrm(mode, 7, reg)); -} - -inline void IA32_Mul_Rm(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode) -{ - jit->write_ubyte(IA32_MUL_RM); - jit->write_ubyte(ia32_modrm(mode, 4, reg)); -} - -inline void IA32_IMul_Rm(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode) -{ - jit->write_ubyte(IA32_IMUL_RM); - jit->write_ubyte(ia32_modrm(mode, 5, reg)); -} - -inline void IA32_IMul_Reg_Imm8(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode, jit_int8_t value) -{ - jit->write_ubyte(IA32_IMUL_REG_IMM8); - jit->write_ubyte(ia32_modrm(mode, 0, reg)); - jit->write_byte(value); -} - -inline void IA32_IMul_Reg_Imm32(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode, jit_int32_t value) -{ - jit->write_ubyte(IA32_IMUL_REG_IMM32); - jit->write_ubyte(ia32_modrm(mode, 0, reg)); - jit->write_int32(value); -} - -inline void IA32_IMul_Reg_Rm(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode) -{ - jit->write_ubyte(IA32_IMUL_REG_RM_1); - jit->write_ubyte(IA32_IMUL_REG_RM_2); - jit->write_ubyte(ia32_modrm(mode, dest, src)); -} - -inline void IA32_Add_Rm_Reg_Disp8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int8_t disp) -{ - jit->write_ubyte(IA32_ADD_RM_REG); - jit->write_ubyte(ia32_modrm(MOD_DISP8, src, dest)); - jit->write_byte(disp); -} - -inline void IA32_Add_Reg_Rm_Disp8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int8_t disp) -{ - jit->write_ubyte(IA32_ADD_REG_RM); - jit->write_ubyte(ia32_modrm(MOD_DISP8, dest, src)); - jit->write_byte(disp); -} - -inline void IA32_Add_Rm_Imm8_Disp8(JitWriter *jit, - jit_uint8_t dest, - jit_int8_t val, - jit_int8_t disp8) -{ - jit->write_ubyte(IA32_ADD_RM_IMM8); - jit->write_ubyte(ia32_modrm(MOD_DISP8, 0, dest)); - jit->write_byte(disp8); - jit->write_byte(val); -} - -inline void IA32_Add_Rm_Imm32_Disp8(JitWriter *jit, - jit_uint8_t dest, - jit_int32_t val, - jit_int8_t disp8) -{ - jit->write_ubyte(IA32_ADD_RM_IMM32); - jit->write_ubyte(ia32_modrm(MOD_DISP8, 0, dest)); - jit->write_byte(disp8); - jit->write_int32(val); -} - -inline jitoffs_t IA32_Add_Rm_Imm32_Later(JitWriter *jit, - jit_uint8_t dest, - jit_uint8_t mode) -{ - jit->write_ubyte(IA32_ADD_RM_IMM32); - jit->write_ubyte(ia32_modrm(mode, 0, dest)); - jitoffs_t ptr = jit->get_outputpos(); - jit->write_int32(0); - return ptr; -} - -inline void IA32_Add_Rm_Imm8_Disp32(JitWriter *jit, - jit_uint8_t dest, - jit_int8_t val, - jit_int32_t disp32) -{ - jit->write_ubyte(IA32_ADD_RM_IMM8); - jit->write_ubyte(ia32_modrm(MOD_DISP32, 0, dest)); - jit->write_int32(disp32); - jit->write_byte(val); -} - -inline void IA32_Add_RmEBP_Imm8_Disp_Reg(JitWriter *jit, - jit_uint8_t dest_base, - jit_uint8_t dest_index, - jit_uint8_t dest_scale, - jit_int8_t val) -{ - jit->write_ubyte(IA32_ADD_RM_IMM8); - jit->write_ubyte(ia32_modrm(MOD_DISP8, 0, REG_SIB)); - jit->write_ubyte(ia32_sib(dest_scale, dest_index, dest_base)); - jit->write_byte(0); - jit->write_byte(val); -} - -inline void IA32_Sub_Rm_Imm8_Disp8(JitWriter *jit, - jit_uint8_t dest, - jit_int8_t val, - jit_int8_t disp8) -{ - jit->write_ubyte(IA32_SUB_RM_IMM8); - jit->write_ubyte(ia32_modrm(MOD_DISP8, 5, dest)); - jit->write_byte(disp8); - jit->write_byte(val); -} - -inline void IA32_Sub_Rm_Imm8_Disp32(JitWriter *jit, - jit_uint8_t dest, - jit_int8_t val, - jit_int32_t disp32) -{ - jit->write_ubyte(IA32_SUB_RM_IMM8); - jit->write_ubyte(ia32_modrm(MOD_DISP32, 5, dest)); - jit->write_int32(disp32); - jit->write_byte(val); -} - -inline void IA32_Sub_RmEBP_Imm8_Disp_Reg(JitWriter *jit, - jit_uint8_t dest_base, - jit_uint8_t dest_index, - jit_uint8_t dest_scale, - jit_int8_t val) -{ - jit->write_ubyte(IA32_SUB_RM_IMM8); - jit->write_ubyte(ia32_modrm(MOD_DISP8, 5, REG_SIB)); - jit->write_ubyte(ia32_sib(dest_scale, dest_index, dest_base)); - jit->write_byte(0); - jit->write_byte(val); -} - -/** -* Memory Instructions -*/ - -inline void IA32_Lea_Reg_DispRegMult(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src_base, jit_uint8_t src_index, jit_uint8_t scale) -{ - jit->write_ubyte(IA32_LEA_REG_MEM); - jit->write_ubyte(ia32_modrm(MOD_MEM_REG, dest, REG_SIB)); - jit->write_ubyte(ia32_sib(scale, src_index, src_base)); -} - -inline void IA32_Lea_Reg_DispEBPRegMult(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src_base, jit_uint8_t src_index, jit_uint8_t scale) -{ - jit->write_ubyte(IA32_LEA_REG_MEM); - jit->write_ubyte(ia32_modrm(MOD_DISP8, dest, REG_SIB)); - jit->write_ubyte(ia32_sib(scale, src_index, src_base)); - jit->write_byte(0); -} - -inline void IA32_Lea_Reg_DispRegMultImm8(JitWriter *jit, - jit_uint8_t dest, - jit_uint8_t src_base, - jit_uint8_t src_index, - jit_uint8_t scale, - jit_int8_t val) -{ - jit->write_ubyte(IA32_LEA_REG_MEM); - jit->write_ubyte(ia32_modrm(MOD_DISP8, dest, REG_SIB)); - jit->write_ubyte(ia32_sib(scale, src_index, src_base)); - jit->write_byte(val); -} - -inline void IA32_Lea_Reg_DispRegMultImm32(JitWriter *jit, - jit_uint8_t dest, - jit_uint8_t src_base, - jit_uint8_t src_index, - jit_uint8_t scale, - jit_int32_t val) -{ - jit->write_ubyte(IA32_LEA_REG_MEM); - jit->write_ubyte(ia32_modrm(MOD_DISP32, dest, REG_SIB)); - jit->write_ubyte(ia32_sib(scale, src_index, src_base)); - jit->write_int32(val); -} - -inline void IA32_Lea_Reg_RegMultImm32(JitWriter *jit, - jit_uint8_t dest, - jit_uint8_t src_index, - jit_uint8_t scale, - jit_int32_t val) -{ - jit->write_ubyte(IA32_LEA_REG_MEM); - jit->write_ubyte(ia32_modrm(MOD_MEM_REG, dest, REG_SIB)); - jit->write_ubyte(ia32_sib(scale, src_index, REG_IMM_BASE)); - jit->write_int32(val); -} - -inline void IA32_Lea_DispRegImm8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src_base, jit_int8_t val) -{ - jit->write_ubyte(IA32_LEA_REG_MEM); - jit->write_ubyte(ia32_modrm(MOD_DISP8, dest, src_base)); - jit->write_byte(val); -} - -inline void IA32_Lea_DispRegImm32(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src_base, jit_int32_t val) -{ - jit->write_ubyte(IA32_LEA_REG_MEM); - jit->write_ubyte(ia32_modrm(MOD_DISP32, dest, src_base)); - jit->write_int32(val); -} - -/** -* Stack Instructions -*/ - -inline void IA32_Pop_Reg(JitWriter *jit, jit_uint8_t reg) -{ - jit->write_ubyte(IA32_POP_REG+reg); -} - -inline void IA32_Push_Reg(JitWriter *jit, jit_uint8_t reg) -{ - jit->write_ubyte(IA32_PUSH_REG+reg); -} - -inline void IA32_Push_Imm8(JitWriter *jit, jit_int8_t val) -{ - jit->write_ubyte(IA32_PUSH_IMM8); - jit->write_byte(val); -} - -inline void IA32_Push_Imm32(JitWriter *jit, jit_int32_t val) -{ - jit->write_ubyte(IA32_PUSH_IMM32); - jit->write_int32(val); -} - -inline void IA32_Pushad(JitWriter *jit) -{ - jit->write_ubyte(IA32_PUSHAD); -} - -inline void IA32_Popad(JitWriter *jit) -{ - jit->write_ubyte(IA32_POPAD); -} - -inline void IA32_Push_Rm_Disp8(JitWriter *jit, jit_uint8_t reg, jit_int8_t disp8) -{ - jit->write_ubyte(IA32_PUSH_RM); - jit->write_ubyte(ia32_modrm(MOD_DISP8, 6, reg)); - jit->write_byte(disp8); -} - -inline void IA32_Push_Rm_Disp8_ESP(JitWriter *jit, jit_int8_t disp8) -{ - jit->write_ubyte(IA32_PUSH_RM); - jit->write_ubyte(ia32_modrm(MOD_DISP8, 6, REG_SIB)); - jit->write_ubyte(ia32_sib(NOSCALE, REG_NOIDX, REG_ESP)); - jit->write_byte(disp8); -} - -/** - * Moving from REGISTER/MEMORY to REGISTER - */ - -inline void IA32_Mov_Eax_Mem(JitWriter *jit, jit_uint32_t mem) -{ - jit->write_ubyte(IA32_MOV_EAX_MEM); - jit->write_uint32(mem); + jit->write_ubyte(IA32_RET); } inline void IA32_Mov_Reg_Rm(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode) @@ -797,432 +154,6 @@ inline void IA32_Mov_Reg_Rm(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, j jit->write_ubyte(ia32_modrm(mode, dest, src)); } -inline void IA32_Mov_Reg8_Rm8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode) -{ - jit->write_ubyte(IA32_MOV_REG8_RM8); - jit->write_ubyte(ia32_modrm(mode, dest, src)); -} - -inline void IA32_Mov_Reg_RmESP(JitWriter *jit, jit_uint8_t dest) -{ - jit->write_ubyte(IA32_MOV_REG_RM); - jit->write_ubyte(ia32_modrm(MOD_MEM_REG, dest, REG_ESP)); - jit->write_ubyte(ia32_sib(NOSCALE, REG_NOIDX, REG_ESP)); -} - -inline void IA32_Mov_Reg_Rm_Disp8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int8_t disp) -{ - jit->write_ubyte(IA32_MOV_REG_RM); - jit->write_ubyte(ia32_modrm(MOD_DISP8, dest, src)); - jit->write_byte(disp); -} - -inline void IA32_Mov_Reg8_Rm8_Disp8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int8_t disp) -{ - jit->write_ubyte(IA32_MOV_REG8_RM8); - jit->write_ubyte(ia32_modrm(MOD_DISP8, dest, src)); - jit->write_byte(disp); -} - -inline void IA32_Mov_Reg_Esp_Disp8(JitWriter *jit, jit_uint8_t dest, jit_int8_t disp) -{ - jit->write_ubyte(IA32_MOV_REG_RM); - jit->write_ubyte(ia32_modrm(MOD_DISP8, dest, REG_SIB)); - jit->write_ubyte(ia32_sib(NOSCALE, REG_NOIDX, REG_ESP)); - jit->write_byte(disp); -} - -inline void IA32_Mov_Reg_Rm_Disp32(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int32_t disp) -{ - jit->write_ubyte(IA32_MOV_REG_RM); - jit->write_ubyte(ia32_modrm(MOD_DISP32, dest, src)); - jit->write_int32(disp); -} - -inline void IA32_Mov_Reg8_Rm8_Disp32(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int32_t disp) -{ - jit->write_ubyte(IA32_MOV_REG8_RM8); - jit->write_ubyte(ia32_modrm(MOD_DISP32, dest, src)); - jit->write_int32(disp); -} - -inline void IA32_Mov_Reg_Rm_Disp_Reg(JitWriter *jit, - jit_uint8_t dest, - jit_uint8_t src_base, - jit_uint8_t src_index, - jit_uint8_t src_scale) -{ - jit->write_ubyte(IA32_MOV_REG_RM); - jit->write_ubyte(ia32_modrm(MOD_MEM_REG, dest, REG_SIB)); - jit->write_ubyte(ia32_sib(src_scale, src_index, src_base)); -} - -inline void IA32_Mov_Reg_Rm_Disp_Reg_Disp8(JitWriter *jit, - jit_uint8_t dest, - jit_uint8_t src_base, - jit_uint8_t src_index, - jit_uint8_t src_scale, - jit_int8_t disp8) -{ - jit->write_ubyte(IA32_MOV_REG_RM); - jit->write_ubyte(ia32_modrm(MOD_DISP8, dest, REG_SIB)); - jit->write_ubyte(ia32_sib(src_scale, src_index, src_base)); - jit->write_byte(disp8); -} - -inline void IA32_Mov_Reg_RmEBP_Disp_Reg(JitWriter *jit, - jit_uint8_t dest, - jit_uint8_t src_base, - jit_uint8_t src_index, - jit_uint8_t src_scale) -{ - jit->write_ubyte(IA32_MOV_REG_RM); - jit->write_ubyte(ia32_modrm(MOD_DISP8, dest, REG_SIB)); - jit->write_ubyte(ia32_sib(src_scale, src_index, src_base)); - jit->write_byte(0); -} - -/** - * Moving from REGISTER to REGISTER/MEMORY - */ - -inline void IA32_Mov_Rm_Reg(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode) -{ - jit->write_ubyte(IA32_MOV_RM_REG); - jit->write_ubyte(ia32_modrm(mode, src, dest)); -} - -inline void IA32_Mov_Rm8_Reg8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode) -{ - jit->write_ubyte(IA32_MOV_RM8_REG8); - jit->write_ubyte(ia32_modrm(mode, src, dest)); -} - -inline void IA32_Mov_RmESP_Reg(JitWriter *jit, jit_uint8_t src) -{ - jit->write_ubyte(IA32_MOV_RM_REG); - jit->write_ubyte(ia32_modrm(MOD_MEM_REG, src, REG_ESP)); - jit->write_ubyte(ia32_sib(NOSCALE, REG_NOIDX, REG_ESP)); -} - -inline void IA32_Mov_Rm_Reg_Disp8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int8_t disp) -{ - jit->write_ubyte(IA32_MOV_RM_REG); - jit->write_ubyte(ia32_modrm(MOD_DISP8, src, dest)); - jit->write_byte(disp); -} - -inline void IA32_Mov_Rm_Reg_Disp32(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int32_t disp) -{ - jit->write_ubyte(IA32_MOV_RM_REG); - jit->write_ubyte(ia32_modrm(MOD_DISP32, src, dest)); - jit->write_int32(disp); -} - -inline void IA32_Mov_RmEBP_Reg_Disp_Reg(JitWriter *jit, - jit_uint8_t dest_base, - jit_uint8_t dest_index, - jit_uint8_t dest_scale, - jit_uint8_t src) -{ - jit->write_ubyte(IA32_MOV_RM_REG); - jit->write_ubyte(ia32_modrm(MOD_DISP8, src, REG_SIB)); - jit->write_ubyte(ia32_sib(dest_scale, dest_index, dest_base)); - jit->write_byte(0); -} - -inline void IA32_Mov_Rm8EBP_Reg_Disp_Reg(JitWriter *jit, - jit_uint8_t dest_base, - jit_uint8_t dest_index, - jit_uint8_t dest_scale, - jit_uint8_t src) -{ - jit->write_ubyte(IA32_MOV_RM8_REG); - jit->write_ubyte(ia32_modrm(MOD_DISP8, src, REG_SIB)); - jit->write_ubyte(ia32_sib(dest_scale, dest_index, dest_base)); - jit->write_byte(0); -} - -inline void IA32_Mov_Rm16EBP_Reg_Disp_Reg(JitWriter *jit, - jit_uint8_t dest_base, - jit_uint8_t dest_index, - jit_uint8_t dest_scale, - jit_uint8_t src) -{ - jit->write_ubyte(IA32_16BIT_PREFIX); - jit->write_ubyte(IA32_MOV_RM_REG); - jit->write_ubyte(ia32_modrm(MOD_DISP8, src, REG_SIB)); - jit->write_ubyte(ia32_sib(dest_scale, dest_index, dest_base)); - jit->write_byte(0); -} - -/** - * Moving from IMMEDIATE to REGISTER - */ - -inline jitoffs_t IA32_Mov_Reg_Imm32(JitWriter *jit, jit_uint8_t dest, jit_int32_t num) -{ - jitoffs_t offs; - jit->write_ubyte(IA32_MOV_REG_IMM+dest); - offs = jit->get_outputpos(); - jit->write_int32(num); - return offs; -} - -inline void IA32_Mov_Rm_Imm32(JitWriter *jit, jit_uint8_t dest, jit_int32_t val, jit_uint8_t mode) -{ - jit->write_ubyte(IA32_MOV_RM_IMM32); - jit->write_ubyte(ia32_modrm(mode, 0, dest)); - jit->write_int32(val); -} - -inline void IA32_Mov_Rm_Imm32_Disp8(JitWriter *jit, - jit_uint8_t dest, - jit_int32_t val, - jit_int8_t disp8) -{ - jit->write_ubyte(IA32_MOV_RM_IMM32); - jit->write_ubyte(ia32_modrm(MOD_DISP8, 0, dest)); - jit->write_byte(disp8); - jit->write_int32(val); -} - -inline void IA32_Mov_Rm_Imm32_Disp32(JitWriter *jit, - jit_uint8_t dest, - jit_int32_t val, - jit_int32_t disp32) -{ - jit->write_ubyte(IA32_MOV_RM_IMM32); - jit->write_ubyte(ia32_modrm(MOD_DISP32, 0, dest)); - jit->write_int32(disp32); - jit->write_int32(val); -} - -inline void IA32_Mov_Rm_Imm32_SIB(JitWriter *jit, - jit_uint8_t dest, - jit_int32_t val, - jit_int32_t disp, - jit_uint8_t index, - jit_uint8_t scale) -{ - jit->write_ubyte(IA32_MOV_RM_IMM32); - - if (disp >= SCHAR_MIN && disp <= SCHAR_MAX) - { - jit->write_ubyte(ia32_modrm(MOD_DISP8, 0, REG_SIB)); - } - else - { - jit->write_ubyte(ia32_modrm(MOD_DISP32, 0, REG_SIB)); - } - - jit->write_ubyte(ia32_sib(scale, index, dest)); - - if (disp >= SCHAR_MIN && disp <= SCHAR_MAX) - { - jit->write_byte((jit_int8_t)disp); - } - else - { - jit->write_int32(disp); - } - - jit->write_int32(val); -} - -inline void IA32_Mov_RmEBP_Imm32_Disp_Reg(JitWriter *jit, - jit_uint8_t dest_base, - jit_uint8_t dest_index, - jit_uint8_t dest_scale, - jit_int32_t val) -{ - jit->write_ubyte(IA32_MOV_RM_IMM32); - jit->write_ubyte(ia32_modrm(MOD_DISP8, 0, REG_SIB)); - jit->write_ubyte(ia32_sib(dest_scale, dest_index, dest_base)); - jit->write_byte(0); - jit->write_int32(val); -} - -inline void IA32_Mov_ESP_Disp8_Imm32(JitWriter *jit, jit_int8_t disp8, jit_int32_t val) -{ - jit->write_ubyte(IA32_MOV_RM_IMM32); - jit->write_ubyte(ia32_modrm(MOD_DISP8, 0, REG_SIB)); - jit->write_ubyte(ia32_sib(NOSCALE, REG_NOIDX, REG_ESP)); - jit->write_byte(disp8); - jit->write_int32(val); -} - -/** -* Floating Point Instructions -*/ - -inline void IA32_Fstcw_Mem16_ESP(JitWriter *jit) -{ - jit->write_ubyte(IA32_FSTCW_MEM16_1); - jit->write_ubyte(IA32_FSTCW_MEM16_2); - jit->write_ubyte(ia32_modrm(MOD_MEM_REG, 7, REG_SIB)); - jit->write_ubyte(ia32_sib(NOSCALE, REG_NOIDX, REG_ESP)); -} - -inline void IA32_Fldcw_Mem16_ESP(JitWriter *jit) -{ - jit->write_ubyte(IA32_FLDCW_MEM16); - jit->write_ubyte(ia32_modrm(MOD_MEM_REG, 5, REG_SIB)); - jit->write_ubyte(ia32_sib(NOSCALE, REG_NOIDX, REG_ESP)); -} - -inline void IA32_Fldcw_Mem16_Disp8_ESP(JitWriter *jit, jit_int8_t disp8) -{ - jit->write_ubyte(IA32_FLDCW_MEM16); - jit->write_ubyte(ia32_modrm(MOD_DISP8, 5, REG_SIB)); - jit->write_ubyte(ia32_sib(NOSCALE, REG_NOIDX, REG_ESP)); - jit->write_byte(disp8); -} - -inline void IA32_Fistp_Mem32_ESP(JitWriter *jit) -{ - jit->write_ubyte(IA32_FISTP_MEM32); - jit->write_ubyte(ia32_modrm(MOD_MEM_REG, 3, REG_SIB)); - jit->write_ubyte(ia32_sib(NOSCALE, REG_NOIDX, REG_ESP)); -} - -inline void IA32_Fistp_Mem32_Disp8_Esp(JitWriter *jit, jit_int8_t disp8) -{ - jit->write_ubyte(IA32_FISTP_MEM32); - jit->write_ubyte(ia32_modrm(MOD_DISP8, 3, REG_SIB)); - jit->write_ubyte(ia32_sib(NOSCALE, REG_NOIDX, REG_ESP)); - jit->write_byte(disp8); -} - -inline void IA32_Fucomip_ST0_FPUreg(JitWriter *jit, jit_uint8_t reg) -{ - jit->write_ubyte(IA32_FUCOMIP_1); - jit->write_ubyte(IA32_FUCOMIP_2+reg); -} - -inline void IA32_Fadd_FPUreg_ST0(JitWriter *jit, jit_uint8_t reg) -{ - jit->write_ubyte(IA32_FADD_FPREG_ST0_1); - jit->write_ubyte(IA32_FADD_FPREG_ST0_2+reg); -} - -inline void IA32_Fadd_Mem32_Disp8(JitWriter *jit, jit_uint8_t src, jit_int8_t val) -{ - jit->write_ubyte(IA32_FADD_MEM32); - jit->write_ubyte(ia32_modrm(MOD_DISP8, 0, src)); - jit->write_byte(val); -} - -inline void IA32_Fadd_Mem32_ESP(JitWriter *jit) -{ - jit->write_ubyte(IA32_FADD_MEM32); - jit->write_ubyte(ia32_modrm(MOD_MEM_REG, 0, REG_SIB)); - jit->write_ubyte(ia32_sib(NOSCALE, REG_NOIDX, REG_ESP)); -} - -inline void IA32_Fsub_Mem32_Disp8(JitWriter *jit, jit_uint8_t src, jit_int8_t val) -{ - jit->write_ubyte(IA32_FSUB_MEM32); - jit->write_ubyte(ia32_modrm(MOD_DISP8, 4, src)); - jit->write_byte(val); -} - -inline void IA32_Fmul_Mem32_Disp8(JitWriter *jit, jit_uint8_t src, jit_int8_t val) -{ - jit->write_ubyte(IA32_FMUL_MEM32); - jit->write_ubyte(ia32_modrm(MOD_DISP8, 1, src)); - jit->write_byte(val); -} - -inline void IA32_Fdiv_Mem32_Disp8(JitWriter *jit, jit_uint8_t src, jit_int8_t val) -{ - jit->write_ubyte(IA32_FDIV_MEM32); - jit->write_ubyte(ia32_modrm(MOD_DISP8, 6, src)); - jit->write_byte(val); -} - -inline void IA32_Fild_Mem32(JitWriter *jit, jit_uint8_t src) -{ - jit->write_ubyte(IA32_FILD_MEM32); - jit->write_ubyte(ia32_modrm(MOD_MEM_REG, 0, src)); -} - -inline void IA32_Fstp_Mem32(JitWriter *jit, jit_uint8_t dest) -{ - jit->write_ubyte(IA32_FSTP_MEM32); - jit->write_ubyte(ia32_modrm(MOD_MEM_REG, 3, dest)); -} - -inline void IA32_Fstp_Mem64(JitWriter *jit, jit_uint8_t dest) -{ - jit->write_ubyte(IA32_FSTP_MEM64); - jit->write_ubyte(ia32_modrm(MOD_MEM_REG, 3, dest)); -} - -inline void IA32_Fstp_Mem32_ESP(JitWriter *jit) -{ - jit->write_ubyte(IA32_FSTP_MEM32); - jit->write_ubyte(ia32_modrm(MOD_MEM_REG, 3, REG_SIB)); - jit->write_ubyte(ia32_sib(NOSCALE, REG_NOIDX, REG_ESP)); -} - -inline void IA32_Fstp_Mem64_ESP(JitWriter *jit) -{ - jit->write_ubyte(IA32_FSTP_MEM64); - jit->write_ubyte(ia32_modrm(MOD_MEM_REG, 3, REG_SIB)); - jit->write_ubyte(ia32_sib(NOSCALE, REG_NOIDX, REG_ESP)); -} - -inline void IA32_Fstp_FPUreg(JitWriter *jit, jit_uint8_t reg) -{ - jit->write_ubyte(IA32_FSTP_FPREG_1); - jit->write_ubyte(IA32_FSTP_FPREG_2+reg); -} - -inline void IA32_Fld_Mem32(JitWriter *jit, jit_uint8_t src) -{ - jit->write_ubyte(IA32_FLD_MEM32); - jit->write_ubyte(ia32_modrm(MOD_MEM_REG, 0, src)); -} - -inline void IA32_Fld_Mem64(JitWriter *jit, jit_uint8_t src) -{ - jit->write_ubyte(IA32_FLD_MEM64); - jit->write_ubyte(ia32_modrm(MOD_MEM_REG, 0, src)); -} - -inline void IA32_Fld_Mem32_Disp8(JitWriter *jit, jit_uint8_t src, jit_int8_t val) -{ - jit->write_ubyte(IA32_FLD_MEM32); - jit->write_ubyte(ia32_modrm(MOD_DISP8, 0, src)); - jit->write_byte(val); -} - -inline void IA32_Fld_Mem64_Disp8(JitWriter *jit, jit_uint8_t src, jit_int8_t val) -{ - jit->write_ubyte(IA32_FLD_MEM64); - jit->write_ubyte(ia32_modrm(MOD_DISP8, 0, src)); - jit->write_byte(val); -} - -inline void IA32_Fld_Mem32_Disp32(JitWriter *jit, jit_uint8_t src, jit_int32_t val) -{ - jit->write_ubyte(IA32_FLD_MEM32); - jit->write_ubyte(ia32_modrm(MOD_DISP32, 0, src)); - jit->write_int32(val); -} - -inline void IA32_Fld_Mem64_Disp32(JitWriter *jit, jit_uint8_t src, jit_int32_t val) -{ - jit->write_ubyte(IA32_FLD_MEM64); - jit->write_ubyte(ia32_modrm(MOD_DISP32, 0, src)); - jit->write_int32(val); -} - -/** -* Move data with zero extend -*/ - inline void IA32_Movzx_Reg32_Rm8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode) { jit->write_ubyte(IA32_MOVZX_R32_RM8_1); @@ -1269,57 +200,76 @@ inline void IA32_Movzx_Reg32_Rm16_Disp32(JitWriter *jit, jit_uint8_t dest, jit_u jit->write_int32(disp); } -/** - * Branching/Jumping - */ - -inline jitoffs_t IA32_Jump_Cond_Imm8(JitWriter *jit, jit_uint8_t cond, jit_int8_t disp) +inline void IA32_Push_Reg(JitWriter *jit, jit_uint8_t reg) { - jitoffs_t ptr; - jit->write_ubyte(IA32_JCC_IMM+cond); - ptr = jit->get_outputpos(); + jit->write_ubyte(IA32_PUSH_REG+reg); +} + +inline void IA32_Pop_Reg(JitWriter *jit, jit_uint8_t reg) +{ + jit->write_ubyte(IA32_POP_REG+reg); +} + +inline void IA32_Lea_DispRegImm8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src_base, jit_int8_t val) +{ + jit->write_ubyte(IA32_LEA_REG_MEM); + jit->write_ubyte(ia32_modrm(MOD_DISP8, dest, src_base)); + jit->write_byte(val); +} + +inline void IA32_Lea_DispRegImm32(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src_base, jit_int32_t val) +{ + jit->write_ubyte(IA32_LEA_REG_MEM); + jit->write_ubyte(ia32_modrm(MOD_DISP32, dest, src_base)); + jit->write_int32(val); +} + +inline void IA32_Mov_Reg_Rm_Disp8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int8_t disp) +{ + jit->write_ubyte(IA32_MOV_REG_RM); + jit->write_ubyte(ia32_modrm(MOD_DISP8, dest, src)); jit->write_byte(disp); - return ptr; } -inline jitoffs_t IA32_Jump_Imm32(JitWriter *jit, jit_int32_t disp) +inline void IA32_Mov_Reg_Rm_Disp32(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int32_t disp) { - jitoffs_t ptr; - jit->write_ubyte(IA32_JMP_IMM32); - ptr = jit->get_outputpos(); + jit->write_ubyte(IA32_MOV_REG_RM); + jit->write_ubyte(ia32_modrm(MOD_DISP32, dest, src)); jit->write_int32(disp); - return ptr; } -inline jitoffs_t IA32_Jump_Imm8(JitWriter *jit, jit_int8_t disp) +inline void IA32_Sub_Rm_Imm8(JitWriter *jit, jit_uint8_t reg, jit_int8_t val, jit_uint8_t mode) { - jitoffs_t ptr; - jit->write_ubyte(IA32_JMP_IMM8); - ptr = jit->get_outputpos(); - jit->write_byte(disp); - return ptr; + jit->write_ubyte(IA32_SUB_RM_IMM8); + jit->write_ubyte(ia32_modrm(mode, 5, reg)); + jit->write_byte(val); } -inline jitoffs_t IA32_Jump_Cond_Imm32(JitWriter *jit, jit_uint8_t cond, jit_int32_t disp) +inline void IA32_Sub_Rm_Imm32(JitWriter *jit, jit_uint8_t reg, jit_int32_t val, jit_uint8_t mode) { - jitoffs_t ptr; - jit->write_ubyte(IA32_JCC_IMM32_1); - jit->write_ubyte(IA32_JCC_IMM32_2+cond); - ptr = jit->get_outputpos(); - jit->write_int32(disp); - return ptr; + jit->write_ubyte(IA32_SUB_RM_IMM32); + jit->write_ubyte(ia32_modrm(mode, 5, reg)); + jit->write_int32(val); } -inline void IA32_Jump_Reg(JitWriter *jit, jit_uint8_t reg) +inline void IA32_Cld(JitWriter *jit) { - jit->write_ubyte(IA32_JMP_RM); - jit->write_ubyte(ia32_modrm(MOD_REG, 4, reg)); + jit->write_ubyte(IA32_CLD); } -inline void IA32_Jump_Rm(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode) +inline void IA32_Rep(JitWriter *jit) { - jit->write_ubyte(IA32_JMP_RM); - jit->write_ubyte(ia32_modrm(mode, 4, reg)); + jit->write_ubyte(IA32_REP); +} + +inline void IA32_Movsd(JitWriter *jit) +{ + jit->write_ubyte(IA32_MOVSD); +} + +inline void IA32_Movsb(JitWriter *jit) +{ + jit->write_ubyte(IA32_MOVSB); } inline jitoffs_t IA32_Call_Imm32(JitWriter *jit, jit_int32_t disp) @@ -1331,36 +281,16 @@ inline jitoffs_t IA32_Call_Imm32(JitWriter *jit, jit_int32_t disp) return ptr; } -inline void IA32_Call_Reg(JitWriter *jit, jit_uint8_t reg) +inline void IA32_Mov_Rm8_Reg8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode) { - jit->write_ubyte(IA32_CALL_RM); - jit->write_ubyte(ia32_modrm(MOD_REG, 2, reg)); + jit->write_ubyte(IA32_MOV_RM8_REG8); + jit->write_ubyte(ia32_modrm(mode, src, dest)); } -inline void IA32_Write_Jump8(JitWriter *jit, jitoffs_t jmp, jitoffs_t target) +inline void IA32_Mov_Rm_Reg(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode) { - //save old ptr - jitcode_t oldptr = jit->outptr; - //get relative difference - jit_int8_t diff = (target - (jmp + 1)); - //overwrite old value - jit->outptr = jit->outbase + jmp; - jit->write_byte(diff); - //restore old ptr - jit->outptr = oldptr; -} - -inline void IA32_Write_Jump32(JitWriter *jit, jitoffs_t jmp, jitoffs_t target) -{ - //save old ptr - jitcode_t oldptr = jit->outptr; - //get relative difference - jit_int32_t diff = (target - (jmp + 4)); - //overwrite old value - jit->outptr = jit->outbase + jmp; - jit->write_int32(diff); - //restore old ptr - jit->outptr = oldptr; + jit->write_ubyte(IA32_MOV_RM_REG); + jit->write_ubyte(ia32_modrm(mode, src, dest)); } /** @@ -1379,54 +309,126 @@ inline void IA32_Write_Jump32_Abs(JitWriter *jit, jitoffs_t jmp, void *target) jit->outptr = oldptr; } -/* For writing and auto-calculating a relative target */ -inline void IA32_Jump_Imm32_Rel(JitWriter *jit, jitoffs_t target) +inline void IA32_Fstp_Mem32(JitWriter *jit, jit_uint8_t dest) { - jit->write_ubyte(IA32_JMP_IMM32); - IA32_Write_Jump32(jit, jit->get_outputpos(), target); - jit->outptr += 4; + jit->write_ubyte(IA32_FSTP_MEM32); + jit->write_ubyte(ia32_modrm(MOD_MEM_REG, 3, dest)); } -/* For writing and auto-calculating an absolute target */ -inline void IA32_Jump_Imm32_Abs(JitWriter *jit, void *target) +inline void IA32_Fstp_Mem64(JitWriter *jit, jit_uint8_t dest) { - jitoffs_t jmp; - - jmp = IA32_Jump_Imm32(jit, 0); - IA32_Write_Jump32_Abs(jit, jmp, target); + jit->write_ubyte(IA32_FSTP_MEM64); + jit->write_ubyte(ia32_modrm(MOD_MEM_REG, 3, dest)); } -inline void IA32_Jump_Cond_Imm32_Rel(JitWriter *jit, jit_uint8_t cond, jitoffs_t target) +inline void IA32_Mov_Rm_Reg_Disp8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int8_t disp) { - jit->write_ubyte(IA32_JCC_IMM32_1); - jit->write_ubyte(IA32_JCC_IMM32_2+cond); - IA32_Write_Jump32(jit, jit->get_outputpos(), target); - jit->outptr += 4; + jit->write_ubyte(IA32_MOV_RM_REG); + jit->write_ubyte(ia32_modrm(MOD_DISP8, src, dest)); + jit->write_byte(disp); } -inline void IA32_Jump_Cond_Imm32_Abs(JitWriter *jit, jit_uint8_t cond, void *target) +inline void IA32_Call_Reg(JitWriter *jit, jit_uint8_t reg) { - jit->write_ubyte(IA32_JCC_IMM32_1); - jit->write_ubyte(IA32_JCC_IMM32_2+cond); - IA32_Write_Jump32_Abs(jit, jit->get_outputpos(), target); - jit->outptr += 4; + jit->write_ubyte(IA32_CALL_RM); + jit->write_ubyte(ia32_modrm(MOD_REG, 2, reg)); } -inline void IA32_Send_Jump8_Here(JitWriter *jit, jitoffs_t jmp) +inline jitoffs_t IA32_Mov_Reg_Imm32(JitWriter *jit, jit_uint8_t dest, jit_int32_t num) { - jitoffs_t curptr = jit->get_outputpos(); - IA32_Write_Jump8(jit, jmp, curptr); + jitoffs_t offs; + jit->write_ubyte(IA32_MOV_REG_IMM+dest); + offs = jit->get_outputpos(); + jit->write_int32(num); + return offs; } -inline void IA32_Send_Jump32_Here(JitWriter *jit, jitoffs_t jmp) +inline void IA32_Add_Rm_Imm8(JitWriter *jit, jit_uint8_t reg, jit_int8_t value, jit_uint8_t mode) { - jitoffs_t curptr = jit->get_outputpos(); - IA32_Write_Jump32(jit, jmp, curptr); + jit->write_ubyte(IA32_ADD_RM_IMM8); + jit->write_ubyte(ia32_modrm(mode, 0, reg)); + jit->write_byte(value); } -inline void IA32_Return(JitWriter *jit) +inline void IA32_Add_Rm_Imm32(JitWriter *jit, jit_uint8_t reg, jit_int32_t value, jit_uint8_t mode) { - jit->write_ubyte(IA32_RET); + jit->write_ubyte(IA32_ADD_RM_IMM32); + jit->write_ubyte(ia32_modrm(mode, 0, reg)); + jit->write_int32(value); +} + +inline void IA32_And_Rm_Imm8(JitWriter *jit, jit_uint8_t reg, jit_uint8_t mode, jit_int8_t value) +{ + jit->write_ubyte(IA32_AND_RM_IMM8); + jit->write_ubyte(ia32_modrm(mode, 4, reg)); + jit->write_byte(value); +} + +inline void IA32_Lea_Reg_DispRegMultImm8(JitWriter *jit, + jit_uint8_t dest, + jit_uint8_t src_base, + jit_uint8_t src_index, + jit_uint8_t scale, + jit_int8_t val) +{ + jit->write_ubyte(IA32_LEA_REG_MEM); + jit->write_ubyte(ia32_modrm(MOD_DISP8, dest, REG_SIB)); + jit->write_ubyte(ia32_sib(scale, src_index, src_base)); + jit->write_byte(val); +} + +inline void IA32_Fld_Mem32_Disp8(JitWriter *jit, jit_uint8_t src, jit_int8_t val) +{ + jit->write_ubyte(IA32_FLD_MEM32); + jit->write_ubyte(ia32_modrm(MOD_DISP8, 0, src)); + jit->write_byte(val); +} + +inline void IA32_Fld_Mem64_Disp8(JitWriter *jit, jit_uint8_t src, jit_int8_t val) +{ + jit->write_ubyte(IA32_FLD_MEM64); + jit->write_ubyte(ia32_modrm(MOD_DISP8, 0, src)); + jit->write_byte(val); +} + +inline void IA32_Fld_Mem32(JitWriter *jit, jit_uint8_t src) +{ + jit->write_ubyte(IA32_FLD_MEM32); + jit->write_ubyte(ia32_modrm(MOD_MEM_REG, 0, src)); +} + +inline void IA32_Fld_Mem64(JitWriter *jit, jit_uint8_t src) +{ + jit->write_ubyte(IA32_FLD_MEM64); + jit->write_ubyte(ia32_modrm(MOD_MEM_REG, 0, src)); +} + +inline void IA32_Fld_Mem32_Disp32(JitWriter *jit, jit_uint8_t src, jit_int32_t val) +{ + jit->write_ubyte(IA32_FLD_MEM32); + jit->write_ubyte(ia32_modrm(MOD_DISP32, 0, src)); + jit->write_int32(val); +} + +inline void IA32_Fld_Mem64_Disp32(JitWriter *jit, jit_uint8_t src, jit_int32_t val) +{ + jit->write_ubyte(IA32_FLD_MEM64); + jit->write_ubyte(ia32_modrm(MOD_DISP32, 0, src)); + jit->write_int32(val); +} + +inline void IA32_Fstp_Mem32_ESP(JitWriter *jit) +{ + jit->write_ubyte(IA32_FSTP_MEM32); + jit->write_ubyte(ia32_modrm(MOD_MEM_REG, 3, REG_SIB)); + jit->write_ubyte(ia32_sib(NOSCALE, REG_NOIDX, REG_ESP)); +} + +inline void IA32_Fstp_Mem64_ESP(JitWriter *jit) +{ + jit->write_ubyte(IA32_FSTP_MEM64); + jit->write_ubyte(ia32_modrm(MOD_MEM_REG, 3, REG_SIB)); + jit->write_ubyte(ia32_sib(NOSCALE, REG_NOIDX, REG_ESP)); } inline void IA32_Return_Popstack(JitWriter *jit, unsigned short bytes) @@ -1435,130 +437,33 @@ inline void IA32_Return_Popstack(JitWriter *jit, unsigned short bytes) jit->write_ushort(bytes); } -inline void IA32_Test_Rm_Reg(JitWriter *jit, jit_uint8_t reg1, jit_uint8_t reg2, jit_uint8_t mode) +inline void IA32_Push_Imm8(JitWriter *jit, jit_int8_t val) { - jit->write_ubyte(IA32_TEST_RM_REG); - jit->write_ubyte(ia32_modrm(mode, reg2, reg1)); + jit->write_ubyte(IA32_PUSH_IMM8); + jit->write_byte(val); } -inline void IA32_Cmp_Rm_Reg(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode) +inline void IA32_Push_Imm32(JitWriter *jit, jit_int32_t val) { - jit->write_ubyte(IA32_CMP_RM_REG); - jit->write_ubyte(ia32_modrm(mode, src, dest)); + jit->write_ubyte(IA32_PUSH_IMM32); + jit->write_int32(val); } -inline void IA32_Cmp_Reg_Rm(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_uint8_t mode) +inline void IA32_Mov_Reg8_Rm8_Disp8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int8_t disp) { - jit->write_ubyte(IA32_CMP_REG_RM); - jit->write_ubyte(ia32_modrm(mode, dest, src)); -} - -inline void IA32_Cmp_Reg_Rm_ESP(JitWriter *jit, jit_uint8_t cmpreg) -{ - jit->write_ubyte(IA32_CMP_REG_RM); - jit->write_ubyte(ia32_modrm(MOD_MEM_REG, cmpreg, REG_SIB)); - jit->write_ubyte(ia32_sib(NOSCALE, REG_NOIDX, REG_ESP)); -} - -inline void IA32_Cmp_Reg_Rm_Disp8(JitWriter *jit, jit_uint8_t reg1, jit_uint8_t reg2, jit_int8_t disp8) -{ - jit->write_ubyte(IA32_CMP_REG_RM); - jit->write_ubyte(ia32_modrm(MOD_DISP8, reg1, reg2)); - jit->write_byte(disp8); -} - -inline void IA32_Cmp_Rm_Imm8(JitWriter *jit, jit_uint8_t mode, jit_uint8_t rm, jit_int8_t imm8) -{ - jit->write_ubyte(IA32_CMP_RM_IMM8); - jit->write_ubyte(ia32_modrm(mode, 7, rm)); - jit->write_byte(imm8); -} - -inline void IA32_Cmp_Rm_Imm32(JitWriter *jit, jit_uint8_t mode, jit_uint8_t rm, jit_int32_t imm32) -{ - jit->write_ubyte(IA32_CMP_RM_IMM32); - jit->write_ubyte(ia32_modrm(mode, 7, rm)); - jit->write_int32(imm32); -} - -inline void IA32_Cmp_Rm_Imm32_Disp8(JitWriter *jit, jit_uint8_t reg, jit_int8_t disp8, jit_int32_t imm32) -{ - jit->write_ubyte(IA32_CMP_RM_IMM32); - jit->write_ubyte(ia32_modrm(MOD_DISP8, 7, reg)); - jit->write_byte(disp8); - jit->write_int32(imm32); -} - -inline void IA32_Cmp_Rm_Disp8_Imm8(JitWriter *jit, jit_uint8_t reg, jit_int8_t disp, jit_int8_t imm8) -{ - jit->write_ubyte(IA32_CMP_RM_IMM8); - jit->write_ubyte(ia32_modrm(MOD_DISP8, 7, reg)); - jit->write_byte(disp); - jit->write_byte(imm8); -} - -inline void IA32_Cmp_Al_Imm8(JitWriter *jit, jit_int8_t value) -{ - jit->write_ubyte(IA32_CMP_AL_IMM32); - jit->write_byte(value); -} - -inline void IA32_Cmp_Eax_Imm32(JitWriter *jit, jit_int32_t value) -{ - jit->write_ubyte(IA32_CMP_EAX_IMM32); - jit->write_int32(value); -} - -inline void IA32_SetCC_Rm8(JitWriter *jit, jit_uint8_t reg, jit_uint8_t cond) -{ - jit->write_ubyte(IA32_SETCC_RM8_1); - jit->write_ubyte(IA32_SETCC_RM8_2+cond); - jit->write_ubyte(ia32_modrm(MOD_REG, 0, reg)); -} - -inline void IA32_CmovCC_Rm(JitWriter *jit, jit_uint8_t src, jit_uint8_t cond) -{ - jit->write_ubyte(IA32_CMOVCC_RM_1); - jit->write_ubyte(IA32_CMOVCC_RM_2+cond); - jit->write_ubyte(ia32_modrm(MOD_MEM_REG, 0, src)); -} - -inline void IA32_CmovCC_Rm_Disp8(JitWriter *jit, jit_uint8_t src, jit_uint8_t cond, jit_int8_t disp) -{ - jit->write_ubyte(IA32_CMOVCC_RM_1); - jit->write_ubyte(IA32_CMOVCC_RM_2+cond); - jit->write_ubyte(ia32_modrm(MOD_DISP8, 0, src)); + jit->write_ubyte(IA32_MOV_REG8_RM8); + jit->write_ubyte(ia32_modrm(MOD_DISP8, dest, src)); jit->write_byte(disp); } -inline void IA32_Cmpsb(JitWriter *jit) +inline jitoffs_t IA32_Jump_Imm32(JitWriter *jit, jit_int32_t disp) { - jit->write_ubyte(IA32_CMPSB); -} - -inline void IA32_Rep(JitWriter *jit) -{ - jit->write_ubyte(IA32_REP); -} - -inline void IA32_Movsd(JitWriter *jit) -{ - jit->write_ubyte(IA32_MOVSD); -} - -inline void IA32_Movsb(JitWriter *jit) -{ - jit->write_ubyte(IA32_MOVSB); -} - -inline void IA32_Stosd(JitWriter *jit) -{ - jit->write_ubyte(IA32_STOSD); -} - -inline void IA32_Cld(JitWriter *jit) -{ - jit->write_ubyte(IA32_CLD); + jitoffs_t ptr; + jit->write_ubyte(IA32_JMP_IMM32); + ptr = jit->get_outputpos(); + jit->write_int32(disp); + return ptr; } #endif //_INCLUDE_JIT_X86_MACROS_H + diff --git a/public/sourcepawn/ke_allocator_policies.h b/public/sourcepawn/ke_allocator_policies.h new file mode 100644 index 00000000..28ee2176 --- /dev/null +++ b/public/sourcepawn/ke_allocator_policies.h @@ -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 +#include + +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_ diff --git a/public/sourcepawn/ke_utility.h b/public/sourcepawn/ke_utility.h new file mode 100644 index 00000000..0539f400 --- /dev/null +++ b/public/sourcepawn/ke_utility.h @@ -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 +#include +#include +#if defined(_MSC_VER) +# include +#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 +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(p)); +#elif defined(KE_64BIT) + return HashInt64(reinterpret_cast(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 +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 static inline T +Min(const T &t1, const T &t2) +{ + return t1 < t2 ? t1 : t2; +} + +template static inline T +Max(const T &t1, const T &t2) +{ + return t1 > t2 ? t1 : t2; +} + +template T +ReturnAndVoid(T &t) +{ + T saved = t; + t = T(); + return saved; +} + +#define OFFSETOF(Class, Member) reinterpret_cast(&((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_ diff --git a/public/sourcepawn/ke_vector.h b/public/sourcepawn/ke_vector.h new file mode 100644 index 00000000..c5ad0d40 --- /dev/null +++ b/public/sourcepawn/ke_vector.h @@ -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 +#include +#include +#include + +namespace ke { + +template +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_ */ + diff --git a/public/sourcepawn/sp_vm_types.h b/public/sourcepawn/sp_vm_types.h index c0c38d52..fc6c9729 100644 --- a/public/sourcepawn/sp_vm_types.h +++ b/public/sourcepawn/sp_vm_types.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! */ /********************************************** diff --git a/sourcepawn/jit/AMBuilder b/sourcepawn/jit/AMBuilder index 4655302a..db304d85 100644 --- a/sourcepawn/jit/AMBuilder +++ b/sourcepawn/jit/AMBuilder @@ -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', diff --git a/sourcepawn/jit/BaseRuntime.cpp b/sourcepawn/jit/BaseRuntime.cpp index 7a07e58a..ec18e44d 100644 --- a/sourcepawn/jit/BaseRuntime.cpp +++ b/sourcepawn/jit/BaseRuntime.cpp @@ -1,3 +1,4 @@ +// vim: set ts=8 sts=2 sw=2 tw=99 et: #include #include #include @@ -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; inum_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) + 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; } diff --git a/sourcepawn/jit/BaseRuntime.h b/sourcepawn/jit/BaseRuntime.h index 6c9fecc7..6e5b9dcc 100644 --- a/sourcepawn/jit/BaseRuntime.h +++ b/sourcepawn/jit/BaseRuntime.h @@ -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 +#include #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 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_ diff --git a/sourcepawn/jit/Makefile b/sourcepawn/jit/Makefile index 202be411..399dd911 100644 --- a/sourcepawn/jit/Makefile +++ b/sourcepawn/jit/Makefile @@ -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 \ diff --git a/sourcepawn/jit/Makefile.shell b/sourcepawn/jit/Makefile.shell new file mode 100644 index 00000000..f19c7399 --- /dev/null +++ b/sourcepawn/jit/Makefile.shell @@ -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) + diff --git a/sourcepawn/jit/dll_exports.cpp b/sourcepawn/jit/dll_exports.cpp index 36305d9a..04ab44c1 100644 --- a/sourcepawn/jit/dll_exports.cpp +++ b/sourcepawn/jit/dll_exports.cpp @@ -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 . - * - * 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 . - * - * Version: $Id$ - */ - -#include -#include -#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 . + * + * 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 . + * + * Version: $Id$ + */ + +#include +#include +#include +#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 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 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: \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 + diff --git a/sourcepawn/jit/engine2.cpp b/sourcepawn/jit/engine2.cpp index f17a98b4..fc691956 100644 --- a/sourcepawn/jit/engine2.cpp +++ b/sourcepawn/jit/engine2.cpp @@ -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 : ""); + rt->SetName(name != NULL ? name : ""); rt->ApplyCompilationOptions(NULL); diff --git a/sourcepawn/jit/opcodes.cpp b/sourcepawn/jit/opcodes.cpp new file mode 100644 index 00000000..83a0ce9e --- /dev/null +++ b/sourcepawn/jit/opcodes.cpp @@ -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 . + * + * 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 . + * + * 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"); +} + diff --git a/sourcepawn/jit/opcodes.h b/sourcepawn/jit/opcodes.h new file mode 100644 index 00000000..048e1492 --- /dev/null +++ b/sourcepawn/jit/opcodes.h @@ -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 . + * + * 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 . + * + * Version: $Id$ + */ + +#ifndef _INCLUDE_SOURCEPAWN_JIT_X86_OPCODES_H_ +#define _INCLUDE_SOURCEPAWN_JIT_X86_OPCODES_H_ + +#include + +// 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_ diff --git a/sourcepawn/jit/sp_vm_basecontext.cpp b/sourcepawn/jit/sp_vm_basecontext.cpp index 8c91b9df..b59dcee3 100644 --- a/sourcepawn/jit/sp_vm_basecontext.cpp +++ b/sourcepawn/jit/sp_vm_basecontext.cpp @@ -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) diff --git a/sourcepawn/jit/sp_vm_basecontext.h b/sourcepawn/jit/sp_vm_basecontext.h index 7bd5058a..dce3c9fa 100644 --- a/sourcepawn/jit/sp_vm_basecontext.h +++ b/sourcepawn/jit/sp_vm_basecontext.h @@ -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]; diff --git a/sourcepawn/jit/sp_vm_engine.cpp b/sourcepawn/jit/sp_vm_engine.cpp index 80a685e3..a156b9a4 100644 --- a/sourcepawn/jit/sp_vm_engine.cpp +++ b/sourcepawn/jit/sp_vm_engine.cpp @@ -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) diff --git a/sourcepawn/jit/x86/jit_x86.cpp b/sourcepawn/jit/x86/jit_x86.cpp index 33f0530d..034aebe2 100644 --- a/sourcepawn/jit/x86/jit_x86.cpp +++ b/sourcepawn/jit/x86/jit_x86.cpp @@ -1,5 +1,5 @@ /** - * vim: set ts=4 : + * vim: set ts=2 sw=2 tw=99 et: * ============================================================================= * SourceMod * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. @@ -33,8 +33,6 @@ #include #include #include "jit_x86.h" -#include "opcode_helpers.h" -#include #include "../sp_vm_engine.h" #include "../engine2.h" #include "../BaseRuntime.h" @@ -46,2994 +44,1971 @@ using namespace Knight; #include "ungen_opcodes.h" #endif +#define __ masm. + JITX86 g_Jit; KeCodeCache *g_pCodeCache = NULL; ISourcePawnEngine *engine = &g_engine1; -inline sp_plugin_t *GETPLUGIN(sp_context_t *ctx) +static inline void * +LinkCode(AssemblerX86 &masm) { - return (sp_plugin_t *)(ctx->vm[JITVARS_PLUGIN]); + if (masm.outOfMemory()) + return NULL; + + void *code = Knight::KE_AllocCode(g_pCodeCache, masm.length()); + if (!code) + return NULL; + + masm.emitToExecutableMemory(code); + return code; } -inline void WriteOp_Move_Pri(JitWriter *jit) +static inline ConditionCode +OpToCondition(OPCODE op) { - //mov eax, edx - IA32_Mov_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); + switch (op) { + case OP_EQ: + case OP_JEQ: + return equal; + case OP_NEQ: + case OP_JNEQ: + return not_equal; + case OP_SLESS: + case OP_JSLESS: + return less; + case OP_SLEQ: + case OP_JSLEQ: + return less_equal; + case OP_SGRTR: + case OP_JSGRTR: + return greater; + case OP_SGEQ: + case OP_JSGEQ: + return greater_equal; + default: + assert(false); + return negative; + } } -inline void WriteOp_Move_Alt(JitWriter *jit) +struct array_creation_t { - //mov edx, eax - IA32_Mov_Reg_Rm(jit, AMX_REG_ALT, AMX_REG_PRI, MOD_REG); + const cell_t *dim_list; /* Dimension sizes */ + cell_t dim_count; /* Number of dimensions */ + cell_t *data_offs; /* Current offset AFTER the indirection vectors (data) */ + cell_t *base; /* array base */ +}; + +static cell_t +GenerateInnerArrayIndirectionVectors(array_creation_t *ar, int dim, cell_t cur_offs) +{ + cell_t write_offs = cur_offs; + cell_t *data_offs = ar->data_offs; + + cur_offs += ar->dim_list[dim]; + + // Dimension n-x where x > 2 will have sub-vectors. + // Otherwise, we just need to reference the data section. + if (ar->dim_count > 2 && dim < ar->dim_count - 2) { + // For each index at this dimension, write offstes to our sub-vectors. + // After we write one sub-vector, we generate its sub-vectors recursively. + // At the end, we're given the next offset we can use. + for (int i = 0; i < ar->dim_list[dim]; i++) { + ar->base[write_offs] = (cur_offs - write_offs) * sizeof(cell_t); + write_offs++; + cur_offs = GenerateInnerArrayIndirectionVectors(ar, dim + 1, cur_offs); + } + } else { + // In this section, there are no sub-vectors, we need to write offsets + // to the data. This is separate so the data stays in one big chunk. + // The data offset will increment by the size of the last dimension, + // because that is where the data is finally computed as. + for (int i = 0; i < ar->dim_list[dim]; i++) { + ar->base[write_offs] = (*data_offs - write_offs) * sizeof(cell_t); + write_offs++; + *data_offs = *data_offs + ar->dim_list[dim + 1]; + } + } + + return cur_offs; } -inline void WriteOp_Xchg(JitWriter *jit) +static cell_t +calc_indirection(const array_creation_t *ar, cell_t dim) { - //xchg eax, edx - IA32_Xchg_Eax_Reg(jit, AMX_REG_ALT); + 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; } -inline void WriteOp_Push(JitWriter *jit) +static void +GenerateArrayIndirectionVectors(cell_t *arraybase, cell_t dims[], cell_t _dimcount, bool autozero) { - //push stack, DAT offset based - //sub edi, 4 - //mov ecx, [ebp+] - //mov [edi], ecx - cell_t val = jit->read_cell(); - IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG); - //optimize encoding a bit... - 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(jit, AMX_REG_STK, AMX_REG_TMP, MOD_MEM_REG); + array_creation_t ar; + cell_t data_offs; + + /* Reverse the dimensions */ + cell_t dim_list[sDIMEN_MAX]; + int cur_dim = 0; + for (int i = _dimcount - 1; i >= 0; i--) + dim_list[cur_dim++] = dims[i]; + + ar.base = arraybase; + ar.dim_list = dim_list; + ar.dim_count = _dimcount; + ar.data_offs = &data_offs; + + data_offs = calc_indirection(&ar, 0); + + GenerateInnerArrayIndirectionVectors(&ar, 0, 0); } -inline void WriteOp_Push_C(JitWriter *jit) +static int +JIT_VerifyLowBoundTracker(sp_context_t *ctx) { - //push stack - //mov [edi-4], - //sub edi, 4 - cell_t val = jit->read_cell(); - IA32_Mov_Rm_Imm32_Disp8(jit, AMX_REG_STK, val, -4); - IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG); + tracker_t *trk = (tracker_t *)(ctx->vm[JITVARS_TRACKER]); + if (trk->pCur <= trk->pBase) + return SP_ERROR_TRACKER_BOUNDS; + return SP_ERROR_NONE; } -inline void WriteOp_Zero(JitWriter *jit) +static int +JIT_VerifyOrAllocateTracker(sp_context_t *ctx) { - //mov [ebp+], 0 - cell_t val = jit->read_cell(); - if (val <= SCHAR_MAX && val >= SCHAR_MIN) - { - IA32_Mov_Rm_Imm32_Disp8(jit, AMX_REG_DAT, 0, (jit_int8_t)val); - } else { - IA32_Mov_Rm_Imm32_Disp32(jit, AMX_REG_DAT, 0, val); - } + 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; } -inline void WriteOp_Zero_S(JitWriter *jit) +#if !defined NDEBUG +static const char * +GetFunctionName(const sp_plugin_t *plugin, uint32_t offs) { - //mov [ebx+], 0 - cell_t val = jit->read_cell(); - if (val <= SCHAR_MAX && val >= SCHAR_MIN) - { - IA32_Mov_Rm_Imm32_Disp8(jit, AMX_REG_FRM, 0, (jit_int8_t)val); - } else { - IA32_Mov_Rm_Imm32_Disp32(jit, AMX_REG_FRM, 0, val); - } + if (!plugin->debug.unpacked) { + uint32_t max, iter; + sp_fdbg_symbol_t *sym; + sp_fdbg_arraydim_t *arr; + uint8_t *cursor = (uint8_t *)(plugin->debug.symbols); + + max = plugin->debug.syms_num; + for (iter = 0; iter < max; iter++) { + sym = (sp_fdbg_symbol_t *)cursor; + + if (sym->ident == SP_SYM_FUNCTION && sym->codestart <= offs && sym->codeend > offs) + return plugin->debug.stringbase + sym->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; + } + + cursor += sizeof(sp_fdbg_symbol_t); + } + } else { + uint32_t max, iter; + sp_u_fdbg_symbol_t *sym; + sp_u_fdbg_arraydim_t *arr; + uint8_t *cursor = (uint8_t *)(plugin->debug.symbols); + + max = plugin->debug.syms_num; + for (iter = 0; iter < max; iter++) { + sym = (sp_u_fdbg_symbol_t *)cursor; + + if (sym->ident == SP_SYM_FUNCTION && sym->codestart <= offs && sym->codeend > offs) + return plugin->debug.stringbase + sym->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; + } + + cursor += sizeof(sp_u_fdbg_symbol_t); + } + } + + return NULL; } - -inline void WriteOp_Push_S(JitWriter *jit) -{ - //push stack, FRM offset based - //sub edi, 4 - //mov ecx, [ebx+] - //mov [edi], ecx - cell_t val = jit->read_cell(); - IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG); - //optimize encoding a bit... - 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(jit, AMX_REG_STK, AMX_REG_TMP, MOD_MEM_REG); -} - -inline void WriteOp_Push_Pri(JitWriter *jit) -{ - //mov [edi-4], eax - //sub edi, 4 - IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_STK, AMX_REG_PRI, -4); - IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG); -} - -inline void WriteOp_Push_Alt(JitWriter *jit) -{ - //mov [edi-4], edx - //sub edi, 4 - IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_STK, AMX_REG_ALT, -4); - IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG); -} - -inline void WriteOp_Push2_C(JitWriter *jit) -{ - Macro_PushN_C(jit, 2); -} - -inline void WriteOp_Push3_C(JitWriter *jit) -{ - Macro_PushN_C(jit, 3); -} - -inline void WriteOp_Push4_C(JitWriter *jit) -{ - Macro_PushN_C(jit, 4); -} - -inline void WriteOp_Push5_C(JitWriter *jit) -{ - Macro_PushN_C(jit, 5); -} - -inline void WriteOp_Push2_Adr(JitWriter *jit) -{ - Macro_PushN_Addr(jit, 2); -} - -inline void WriteOp_Push3_Adr(JitWriter *jit) -{ - Macro_PushN_Addr(jit, 3); -} - -inline void WriteOp_Push4_Adr(JitWriter *jit) -{ - Macro_PushN_Addr(jit, 4); -} - -inline void WriteOp_Push5_Adr(JitWriter *jit) -{ - Macro_PushN_Addr(jit, 5); -} - -inline void WriteOp_Push2_S(JitWriter *jit) -{ - Macro_PushN_S(jit, 2); -} - -inline void WriteOp_Push3_S(JitWriter *jit) -{ - Macro_PushN_S(jit, 3); -} - -inline void WriteOp_Push4_S(JitWriter *jit) -{ - Macro_PushN_S(jit, 4); -} - -inline void WriteOp_Push5_S(JitWriter *jit) -{ - Macro_PushN_S(jit, 5); -} - -inline void WriteOp_Push5(JitWriter *jit) -{ - Macro_PushN(jit, 5); -} - -inline void WriteOp_Push4(JitWriter *jit) -{ - Macro_PushN(jit, 4); -} - -inline void WriteOp_Push3(JitWriter *jit) -{ - Macro_PushN(jit, 3); -} - -inline void WriteOp_Push2(JitWriter *jit) -{ - Macro_PushN(jit, 2); -} - -inline void WriteOp_Zero_Pri(JitWriter *jit) -{ - //xor eax, eax - IA32_Xor_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_PRI, MOD_REG); -} - -inline void WriteOp_Zero_Alt(JitWriter *jit) -{ - //xor edx, edx - IA32_Xor_Reg_Rm(jit, AMX_REG_ALT, AMX_REG_ALT, MOD_REG); -} - -inline void WriteOp_Add(JitWriter *jit) -{ - //add eax, edx - IA32_Add_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); -} - -inline void WriteOp_Sub(JitWriter *jit) -{ - //sub eax, edx - IA32_Sub_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); -} - -inline void WriteOp_Sub_Alt(JitWriter *jit) -{ - //neg eax - //add eax, edx - IA32_Neg_Rm(jit, AMX_REG_PRI, MOD_REG); - IA32_Add_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); -} - -inline void WriteOp_Proc(JitWriter *jit) -{ -#if 0 /* :TODO: We no longer use this */ - /* Specialized code to align this taking in account the function magic number */ - jitoffs_t cur_offs = jit->get_outputpos(); - jitoffs_t offset = ((cur_offs & 0xFFFFFFF8) + 8) - cur_offs; - if (!((offset + cur_offs) & 8)) - { - offset += 8; - } - if (offset) - { - for (jit_uint32_t i=0; iwrite_ubyte(IA32_INT3); - } - } - - /* Write the info struct about this function */ - jit->write_uint32(JIT_FUNCMAGIC); - jit->write_uint32(co->func_idx); - - /* Now we have to backpatch our reloction offset! */ - { - jitoffs_t offs = jit->get_inputpos() - sizeof(cell_t); - uint8_t *rebase = ((CompData *)jit->data)->rebase; - *(jitoffs_t *)(rebase + offs) = jit->get_outputpos(); - } - - /* Lastly, if we're writing, keep track of the function count */ - if (jit->outbase) - { - co->func_idx++; - } #endif - //push old frame on stack: - //mov ecx, [esi+frm] - //mov [edi-4], ecx - //sub edi, 8 ;extra un-used slot for non-existant CIP - IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_INFO, MOD_MEM_REG); - IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_STK, AMX_REG_TMP, -4); - IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 8, MOD_REG); - - //save frame: - //mov ecx, edi - get new frame - //mov ebx, edi - store frame back - //sub ecx, ebp - relocate local frame - //mov [esi+frm], ecx - IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_STK, MOD_REG); - IA32_Mov_Reg_Rm(jit, AMX_REG_FRM, AMX_REG_STK, MOD_REG); - IA32_Sub_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_DAT, MOD_REG); - IA32_Mov_Rm_Reg(jit, AMX_REG_INFO, AMX_REG_TMP, MOD_MEM_REG); -} - -inline void WriteOp_Lidx_B(JitWriter *jit) -{ - cell_t val = jit->read_cell(); - //shl eax, - //add eax, edx - //mov eax, [ebp+eax] - IA32_Shl_Rm_Imm8(jit, AMX_REG_PRI, (jit_uint8_t)val, MOD_REG); - IA32_Add_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); - Write_Check_VerifyAddr(jit, AMX_REG_PRI); - IA32_Mov_Reg_RmEBP_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE); -} - -inline void WriteOp_Idxaddr_B(JitWriter *jit) -{ - //shl eax, - //add eax, edx - cell_t val = jit->read_cell(); - IA32_Shl_Rm_Imm8(jit, AMX_REG_PRI, (jit_uint8_t)val, MOD_REG); - IA32_Add_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); -} - -inline void WriteOp_Shl(JitWriter *jit) -{ - //mov ecx, edx - //shl eax, cl - IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_ALT, MOD_REG); - IA32_Shl_Rm_CL(jit, AMX_REG_PRI, MOD_REG); -} - -inline void WriteOp_Shr(JitWriter *jit) -{ - //mov ecx, edx - //shr eax, cl - IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_ALT, MOD_REG); - IA32_Shr_Rm_CL(jit, AMX_REG_PRI, MOD_REG); -} - -inline void WriteOp_Sshr(JitWriter *jit) -{ - //mov ecx, edx - //sar eax, cl - IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_ALT, MOD_REG); - IA32_Sar_Rm_CL(jit, AMX_REG_PRI, MOD_REG); -} - -inline void WriteOp_Shl_C_Pri(JitWriter *jit) -{ - //shl eax, - jit_uint8_t val = (jit_uint8_t)jit->read_cell(); - if (val == 1) - { - IA32_Shl_Rm_1(jit, AMX_REG_PRI, MOD_REG); - } else { - IA32_Shl_Rm_Imm8(jit, AMX_REG_PRI, val, MOD_REG); - } -} - -inline void WriteOp_Shl_C_Alt(JitWriter *jit) -{ - //shl edx, - jit_uint8_t val = (jit_uint8_t)jit->read_cell(); - if (val == 1) - { - IA32_Shl_Rm_1(jit, AMX_REG_ALT, MOD_REG); - } else { - IA32_Shl_Rm_Imm8(jit, AMX_REG_ALT, val, MOD_REG); - } -} - -inline void WriteOp_Shr_C_Pri(JitWriter *jit) -{ - //shr eax, - jit_uint8_t val = (jit_uint8_t)jit->read_cell(); - if (val == 1) - { - IA32_Shr_Rm_1(jit, AMX_REG_PRI, MOD_REG); - } else { - IA32_Shr_Rm_Imm8(jit, AMX_REG_PRI, val, MOD_REG); - } -} - -inline void WriteOp_Shr_C_Alt(JitWriter *jit) -{ - //shr edx, - jit_uint8_t val = (jit_uint8_t)jit->read_cell(); - if (val == 1) - { - IA32_Shr_Rm_1(jit, AMX_REG_ALT, MOD_REG); - } else { - IA32_Shr_Rm_Imm8(jit, AMX_REG_ALT, val, MOD_REG); - } -} - -inline void WriteOp_SMul(JitWriter *jit) -{ - //mov ecx, edx - //imul edx - //mov edx, ecx - IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_ALT, MOD_REG); - IA32_IMul_Rm(jit, AMX_REG_ALT, MOD_REG); - IA32_Mov_Reg_Rm(jit, AMX_REG_ALT, AMX_REG_TMP, MOD_REG); -} - -inline void WriteOp_Not(JitWriter *jit) -{ - //test eax, eax - //mov eax, 0 - //sete al - IA32_Test_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_PRI, MOD_REG); - IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0); - IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_E); -} - -inline void WriteOp_Neg(JitWriter *jit) -{ - //neg eax - IA32_Neg_Rm(jit, AMX_REG_PRI, MOD_REG); -} - -inline void WriteOp_Xor(JitWriter *jit) -{ - //xor eax, edx - IA32_Xor_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); -} - -inline void WriteOp_Or(JitWriter *jit) -{ - //or eax, edx - IA32_Or_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); -} - -inline void WriteOp_And(JitWriter *jit) -{ - //and eax, edx - IA32_And_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); -} - -inline void WriteOp_Invert(JitWriter *jit) -{ - //not eax - IA32_Not_Rm(jit, AMX_REG_PRI, MOD_REG); -} - -inline void WriteOp_Add_C(JitWriter *jit) -{ - //add eax, - cell_t val = jit->read_cell(); - if (val <= SCHAR_MAX && val >= SCHAR_MIN) - IA32_Add_Rm_Imm8(jit, AMX_REG_PRI, (jit_int8_t)val, MOD_REG); - else - IA32_Add_Eax_Imm32(jit, val); -} - -inline void WriteOp_SMul_C(JitWriter *jit) -{ - //imul eax, - cell_t val = jit->read_cell(); - if (val <= SCHAR_MAX && val >= SCHAR_MIN) - IA32_IMul_Reg_Imm8(jit, AMX_REG_PRI, MOD_REG, (jit_int8_t)val); - else - IA32_IMul_Reg_Imm32(jit, AMX_REG_PRI, MOD_REG, val); -} - -inline void WriteOp_Sign_Pri(JitWriter *jit) -{ - //shl eax, 24 - //sar eax, 24 - IA32_Shl_Rm_Imm8(jit, AMX_REG_PRI, 24, MOD_REG); - IA32_Sar_Rm_Imm8(jit, AMX_REG_PRI, 24, MOD_REG); -} - -inline void WriteOp_Sign_Alt(JitWriter *jit) -{ - //shl edx, 24 - //sar edx, 24 - IA32_Shl_Rm_Imm8(jit, AMX_REG_ALT, 24, MOD_REG); - IA32_Sar_Rm_Imm8(jit, AMX_REG_ALT, 24, MOD_REG); -} - -inline void WriteOp_Eq(JitWriter *jit) -{ - //cmp eax, edx ; PRI == ALT ? - //mov eax, 0 - //sete 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_E); -} - -inline void WriteOp_Neq(JitWriter *jit) -{ - //cmp eax, edx ; PRI != ALT ? - //mov eax, 0 - //setne 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_NE); -} - -inline void WriteOp_Sless(JitWriter *jit) -{ - //cmp eax, edx ; PRI < ALT ? (signed) - //mov eax, 0 - //setl 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_L); -} - -inline void WriteOp_Sleq(JitWriter *jit) -{ - //cmp eax, edx ; PRI <= ALT ? (signed) - //mov eax, 0 - //setle 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_LE); -} - -inline void WriteOp_Sgrtr(JitWriter *jit) -{ - //cmp eax, edx ; PRI > ALT ? (signed) - //mov eax, 0 - //setg 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_G); -} - -inline void WriteOp_Sgeq(JitWriter *jit) -{ - //cmp eax, edx ; PRI >= ALT ? (signed) - //mov eax, 0 - //setge 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_GE); -} - -inline void WriteOp_Eq_C_Pri(JitWriter *jit) -{ - //cmp eax, ; PRI == value ? - //mov eax, 0 - //sete al - cell_t val = jit->read_cell(); - if (val <= SCHAR_MAX && val >= SCHAR_MIN) - IA32_Cmp_Rm_Imm8(jit, MOD_REG, AMX_REG_PRI, (jit_int8_t)val); - else - IA32_Cmp_Eax_Imm32(jit, val); - IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, 0); - IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_E); -} - -inline void WriteOp_Eq_C_Alt(JitWriter *jit) -{ - //xor eax, eax - //cmp edx, ; ALT == value ? - //sete al - cell_t val = jit->read_cell(); - IA32_Xor_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_PRI, MOD_REG); - if (val <= SCHAR_MAX && val >= SCHAR_MIN) - IA32_Cmp_Rm_Imm8(jit, MOD_REG, AMX_REG_ALT, (jit_int8_t)val); - else - IA32_Cmp_Rm_Imm32(jit, MOD_REG, AMX_REG_ALT, val); - IA32_SetCC_Rm8(jit, AMX_REG_PRI, CC_E); -} - -inline void WriteOp_Inc_Pri(JitWriter *jit) -{ - //add eax, 1 - IA32_Add_Rm_Imm8(jit, AMX_REG_PRI, 1, MOD_REG); -} - -inline void WriteOp_Inc_Alt(JitWriter *jit) -{ - //add edx, 1 - IA32_Add_Rm_Imm8(jit, AMX_REG_ALT, 1, MOD_REG); -} - -inline void WriteOp_Inc(JitWriter *jit) -{ - //add [ebp+], 1 - cell_t val = jit->read_cell(); - if (val <= SCHAR_MAX && val >= SCHAR_MIN) - IA32_Add_Rm_Imm8_Disp8(jit, AMX_REG_DAT, 1, (jit_int8_t)val); - else - IA32_Add_Rm_Imm8_Disp32(jit, AMX_REG_DAT, 1, val); -} - -inline void WriteOp_Inc_S(JitWriter *jit) -{ - //add [ebx+], 1 - cell_t val = jit->read_cell(); - if (val <= SCHAR_MAX && val >= SCHAR_MIN) - IA32_Add_Rm_Imm8_Disp8(jit, AMX_REG_FRM, 1, (jit_int8_t)val); - else - IA32_Add_Rm_Imm8_Disp32(jit, AMX_REG_FRM, 1, val); -} - -inline void WriteOp_Inc_I(JitWriter *jit) -{ - //add [ebp+eax], 1 - IA32_Add_RmEBP_Imm8_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_PRI, NOSCALE, 1); -} - -inline void WriteOp_Dec_Pri(JitWriter *jit) -{ - //sub eax, 1 - IA32_Sub_Rm_Imm8(jit, AMX_REG_PRI, 1, MOD_REG); -} - -inline void WriteOp_Dec_Alt(JitWriter *jit) -{ - //sub edx, 1 - IA32_Sub_Rm_Imm8(jit, AMX_REG_ALT, 1, MOD_REG); -} - -inline void WriteOp_Dec(JitWriter *jit) -{ - //sub [ebp+], 1 - cell_t val = jit->read_cell(); - if (val <= SCHAR_MAX && val >= SCHAR_MIN) - { - IA32_Sub_Rm_Imm8_Disp8(jit, AMX_REG_DAT, 1, (jit_int8_t)val); - } else { - IA32_Sub_Rm_Imm8_Disp32(jit, AMX_REG_DAT, 1, val); - } -} - -inline void WriteOp_Dec_S(JitWriter *jit) -{ - //sub [ebx+], 1 - cell_t val = jit->read_cell(); - if (val <= SCHAR_MAX && val >= SCHAR_MIN) - { - IA32_Sub_Rm_Imm8_Disp8(jit, AMX_REG_FRM, 1, (jit_int8_t)val); - } else { - IA32_Sub_Rm_Imm8_Disp32(jit, AMX_REG_FRM, 1, val); - } -} - -inline void WriteOp_Dec_I(JitWriter *jit) -{ - //sub [ebp+eax], 1 - IA32_Sub_RmEBP_Imm8_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_PRI, NOSCALE, 1); -} - -inline void WriteOp_Load_Pri(JitWriter *jit) -{ - //mov eax, [ebp+] - cell_t val = jit->read_cell(); - if (val <= SCHAR_MAX && val >= SCHAR_MIN) - { - IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_PRI, AMX_REG_DAT, (jit_int8_t)val); - } else { - IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_PRI, AMX_REG_DAT, val); - } -} - -inline void WriteOp_Load_Alt(JitWriter *jit) -{ - //mov edx, [ebp+] - cell_t val = jit->read_cell(); - if (val <= SCHAR_MAX && val >= SCHAR_MIN) - { - IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_ALT, AMX_REG_DAT, (jit_int8_t)val); - } else { - IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_ALT, AMX_REG_DAT, val); - } -} - -inline void WriteOp_Load_S_Pri(JitWriter *jit) -{ - //mov eax, [ebx+] - cell_t val = jit->read_cell(); - if (val <= SCHAR_MAX && val >= SCHAR_MIN) - { - IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_PRI, AMX_REG_FRM, (jit_int8_t)val); - } else { - IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_PRI, AMX_REG_FRM, val); - } -} - -inline void WriteOp_Load_S_Alt(JitWriter *jit) -{ - //mov edx, [ebx+] - cell_t val = jit->read_cell(); - if (val <= SCHAR_MAX && val >= SCHAR_MIN) - { - IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_ALT, AMX_REG_FRM, (jit_int8_t)val); - } else { - IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_ALT, AMX_REG_FRM, val); - } -} - -inline void WriteOp_Lref_Pri(JitWriter *jit) -{ - //mov eax, [ebp+] - //mov eax, [ebp+eax] - cell_t val = jit->read_cell(); - if (val <= SCHAR_MAX && val >= SCHAR_MIN) - { - IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_PRI, AMX_REG_DAT, (jit_int8_t)val); - } else { - IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_PRI, AMX_REG_DAT, val); - } - IA32_Mov_Reg_RmEBP_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE); -} - -inline void WriteOp_Lref_Alt(JitWriter *jit) -{ - //mov edx, [ebp+] - //mov edx, [ebp+edx] - cell_t val = jit->read_cell(); - if (val <= SCHAR_MAX && val >= SCHAR_MIN) - { - IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_ALT, AMX_REG_DAT, (jit_int8_t)val); - } else { - IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_ALT, AMX_REG_DAT, val); - } - IA32_Mov_Reg_RmEBP_Disp_Reg(jit, AMX_REG_ALT, AMX_REG_DAT, AMX_REG_ALT, NOSCALE); -} - -inline void WriteOp_Lref_S_Pri(JitWriter *jit) -{ - //mov eax, [ebx+] - //mov eax, [ebp+eax] - cell_t val = jit->read_cell(); - if (val <= SCHAR_MAX && val >= SCHAR_MIN) - { - IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_PRI, AMX_REG_FRM, (jit_int8_t)val); - } else { - IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_PRI, AMX_REG_FRM, val); - } - IA32_Mov_Reg_RmEBP_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE); -} - -inline void WriteOp_Lref_S_Alt(JitWriter *jit) -{ - //mov edx, [ebx+] - //mov edx, [ebp+edx] - cell_t val = jit->read_cell(); - if (val <= SCHAR_MAX && val >= SCHAR_MIN) - { - IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_ALT, AMX_REG_FRM, (jit_int8_t)val); - } else { - IA32_Mov_Reg_Rm_Disp32(jit, AMX_REG_ALT, AMX_REG_FRM, val); - } - IA32_Mov_Reg_RmEBP_Disp_Reg(jit, AMX_REG_ALT, AMX_REG_DAT, AMX_REG_ALT, NOSCALE); -} - -inline void WriteOp_Const_Pri(JitWriter *jit) -{ - //mov eax, - cell_t val = jit->read_cell(); - IA32_Mov_Reg_Imm32(jit, AMX_REG_PRI, val); -} - -inline void WriteOp_Const_Alt(JitWriter *jit) -{ - //mov edx, - cell_t val = jit->read_cell(); - IA32_Mov_Reg_Imm32(jit, AMX_REG_ALT, val); -} - -inline void WriteOp_Addr_Pri(JitWriter *jit) -{ - //mov eax, [esi+frm] - //add eax, - cell_t val = jit->read_cell(); - IA32_Mov_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_INFO, MOD_MEM_REG); - if (val <= SCHAR_MAX && val >= SCHAR_MIN) - { - IA32_Add_Rm_Imm8(jit, AMX_REG_PRI, (jit_int8_t)val, MOD_REG); - } else { - IA32_Add_Eax_Imm32(jit, val); - } -} - -inline void WriteOp_Addr_Alt(JitWriter *jit) -{ - //mov edx, [esi+frm] - //add edx, - cell_t val = jit->read_cell(); - IA32_Mov_Reg_Rm(jit, AMX_REG_ALT, AMX_REG_INFO, MOD_MEM_REG); - if (val <= SCHAR_MAX && val >= SCHAR_MIN) - { - IA32_Add_Rm_Imm8(jit, AMX_REG_ALT, (jit_int8_t)val, MOD_REG); - } else { - IA32_Add_Rm_Imm32(jit, AMX_REG_ALT, val, MOD_REG); - } -} - -inline void WriteOp_Stor_Pri(JitWriter *jit) -{ - //mov [ebp+], eax - cell_t val = jit->read_cell(); - if (val <= SCHAR_MAX && val >= SCHAR_MIN) - { - IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_DAT, AMX_REG_PRI, (jit_int8_t)val); - } else { - IA32_Mov_Rm_Reg_Disp32(jit, AMX_REG_DAT, AMX_REG_PRI, val); - } -} - -inline void WriteOp_Stor_Alt(JitWriter *jit) -{ - //mov [ebp+], edx - cell_t val = jit->read_cell(); - if (val <= SCHAR_MAX && val >= SCHAR_MIN) - { - IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_DAT, AMX_REG_ALT, (jit_int8_t)val); - } else { - IA32_Mov_Rm_Reg_Disp32(jit, AMX_REG_DAT, AMX_REG_ALT, val); - } -} - -inline void WriteOp_Stor_S_Pri(JitWriter *jit) -{ - //mov [ebx+], eax - cell_t val = jit->read_cell(); - if (val <= SCHAR_MAX && val >= SCHAR_MIN) - { - IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_FRM, AMX_REG_PRI, (jit_int8_t)val); - } else { - IA32_Mov_Rm_Reg_Disp32(jit, AMX_REG_FRM, AMX_REG_PRI, val); - } -} - -inline void WriteOp_Stor_S_Alt(JitWriter *jit) -{ - //mov [ebx+], edx - cell_t val = jit->read_cell(); - if (val <= SCHAR_MAX && val >= SCHAR_MIN) - { - IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_FRM, AMX_REG_ALT, (jit_int8_t)val); - } else { - IA32_Mov_Rm_Reg_Disp32(jit, AMX_REG_FRM, AMX_REG_ALT, val); - } -} - -inline void WriteOp_Idxaddr(JitWriter *jit) -{ - //lea eax, [edx+4*eax] - IA32_Lea_Reg_DispRegMult(jit, AMX_REG_PRI, AMX_REG_ALT, AMX_REG_PRI, SCALE4); -} - -inline void WriteOp_Sref_Pri(JitWriter *jit) -{ - //mov ecx, [ebp+] - //mov [ebp+ecx], eax - cell_t 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_RmEBP_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, AMX_REG_PRI); -} - -inline void WriteOp_Sref_Alt(JitWriter *jit) -{ - //mov ecx, [ebp+] - //mov [ebp+ecx], edx - cell_t 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_RmEBP_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, AMX_REG_ALT); -} - -inline void WriteOp_Sref_S_Pri(JitWriter *jit) -{ - //mov ecx, [ebx+] - //mov [ebp+ecx], eax - cell_t 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_RmEBP_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, AMX_REG_PRI); -} - -inline void WriteOp_Sref_S_Alt(JitWriter *jit) -{ - //mov ecx, [ebx+] - //mov [ebp+ecx], edx - cell_t 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_RmEBP_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, AMX_REG_ALT); -} - -inline void WriteOp_Pop_Pri(JitWriter *jit) -{ - //mov eax, [edi] - //add edi, 4 - IA32_Mov_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_STK, MOD_MEM_REG); - IA32_Add_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG); -} - -inline void WriteOp_Pop_Alt(JitWriter *jit) -{ - //mov edx, [edi] - //add edi, 4 - IA32_Mov_Reg_Rm(jit, AMX_REG_ALT, AMX_REG_STK, MOD_MEM_REG); - IA32_Add_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG); -} - -inline void WriteOp_Swap_Pri(JitWriter *jit) -{ - //add [edi], eax - //sub eax, [edi] - //add [edi], eax - //neg eax - IA32_Add_Rm_Reg(jit, AMX_REG_STK, AMX_REG_PRI, MOD_MEM_REG); - IA32_Sub_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_STK, MOD_MEM_REG); - IA32_Add_Rm_Reg(jit, AMX_REG_STK, AMX_REG_PRI, MOD_MEM_REG); - IA32_Neg_Rm(jit, AMX_REG_PRI, MOD_REG); -} - -inline void WriteOp_Swap_Alt(JitWriter *jit) -{ - //add [edi], edx - //sub edx, [edi] - //add [edi], edx - //neg edx - IA32_Add_Rm_Reg(jit, AMX_REG_STK, AMX_REG_ALT, MOD_MEM_REG); - IA32_Sub_Reg_Rm(jit, AMX_REG_ALT, AMX_REG_STK, MOD_MEM_REG); - IA32_Add_Rm_Reg(jit, AMX_REG_STK, AMX_REG_ALT, MOD_MEM_REG); - IA32_Neg_Rm(jit, AMX_REG_ALT, MOD_REG); -} - -inline void WriteOp_PushAddr(JitWriter *jit) -{ - //mov ecx, [esi+frm] ;get address (offset from frame) - //sub edi, 4 - //add ecx, - //mov [edi], ecx - cell_t val = jit->read_cell(); - IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_INFO, MOD_MEM_REG); - IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG); - if (val <= SCHAR_MAX && val >= SCHAR_MIN) - { - IA32_Add_Rm_Imm8(jit, AMX_REG_TMP, (jit_int8_t)val, MOD_REG); - } else { - IA32_Add_Rm_Imm32(jit, AMX_REG_TMP, val, MOD_REG); - } - IA32_Mov_Rm_Reg(jit, AMX_REG_STK, AMX_REG_TMP, MOD_MEM_REG); -} - -inline void WriteOp_Movs(JitWriter *jit) -{ - //cld - //push esi - //push edi - //lea esi, [ebp+eax] - //lea edi, [ebp+edx] - //if dword: - // mov ecx, dword - // rep movsd - //if byte: - // mov ecx, byte - // rep movsb - //pop edi - //pop esi - cell_t val = jit->read_cell(); - unsigned int dwords = val >> 2; - unsigned int bytes = val & 0x3; - - IA32_Cld(jit); - IA32_Push_Reg(jit, REG_ESI); - IA32_Push_Reg(jit, REG_EDI); - IA32_Lea_Reg_DispEBPRegMult(jit, REG_ESI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE); - IA32_Lea_Reg_DispEBPRegMult(jit, REG_EDI, AMX_REG_DAT, AMX_REG_ALT, NOSCALE); - if (dwords) - { - IA32_Mov_Reg_Imm32(jit, REG_ECX, dwords); - IA32_Rep(jit); - IA32_Movsd(jit); - } - if (bytes) - { - IA32_Mov_Reg_Imm32(jit, REG_ECX, bytes); - IA32_Rep(jit); - IA32_Movsb(jit); - } - IA32_Pop_Reg(jit, REG_EDI); - IA32_Pop_Reg(jit, REG_ESI); -} - -inline void WriteOp_Fill(JitWriter *jit) -{ - //push edi - //lea edi, [ebp+edx] - //mov ecx, >> 2 - //cld - //rep stosd - //pop edi - unsigned int val = jit->read_cell() >> 2; - - IA32_Push_Reg(jit, REG_EDI); - IA32_Lea_Reg_DispEBPRegMult(jit, REG_EDI, AMX_REG_DAT, AMX_REG_ALT, NOSCALE); - IA32_Mov_Reg_Imm32(jit, REG_ECX, val); - IA32_Cld(jit); - IA32_Rep(jit); - IA32_Stosd(jit); - IA32_Pop_Reg(jit, REG_EDI); -} - -inline void WriteOp_GenArray(JitWriter *jit, bool autozero) -{ - cell_t val = jit->read_cell(); - if (val == 1) - { - /* flat array. we can generate this without indirection tables. */ - /* Note that we can overwrite ALT because technically STACK should be destroying ALT */ - //mov edx, [esi+info.heap] - //mov ecx, [edi] - //mov [edi], edx ;store base of array into stack - //lea edx, [edx+ecx*4] ;get the final new heap pointer - //mov [esi+info.heap], edx ;store heap pointer back - //add edx, ebp ;relocate - //cmp edx, edi ;compare against stack pointer - //jae :error ;error out if not enough space - IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_ALT, AMX_REG_INFO, AMX_INFO_HEAP); - IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_STK, MOD_MEM_REG); - IA32_Mov_Rm_Reg(jit, AMX_REG_STK, AMX_REG_ALT, MOD_MEM_REG); - IA32_Lea_Reg_DispRegMult(jit, AMX_REG_ALT, AMX_REG_ALT, AMX_REG_TMP, SCALE4); - IA32_Mov_Rm_Reg_Disp8(jit, AMX_REG_INFO, AMX_REG_ALT, AMX_INFO_HEAP); - IA32_Add_Reg_Rm(jit, AMX_REG_ALT, AMX_REG_DAT, MOD_REG); - IA32_Cmp_Reg_Rm(jit, AMX_REG_ALT, AMX_REG_STK, MOD_REG); - IA32_Jump_Cond_Imm32_Rel(jit, CC_AE, ((CompData *)jit->data)->jit_error_heaplow); - - WriteOp_Tracker_Push_Reg(jit, REG_ECX); - - if (autozero) - { - /* Zero out the array - inline a quick fill */ - //push eax ;save pri - //push edi ;save stk - //xor eax, eax ;zero source - //mov edi, [edi] ;get heap ptr out of the stack - //add edi, ebp ;relocate - //cld ;clear direction flag - //rep stosd ;copy (note: ECX is sane from above) - //pop edi ;pop stk - //pop eax ;pop pri - IA32_Push_Reg(jit, REG_EAX); - IA32_Push_Reg(jit, REG_EDI); - IA32_Xor_Reg_Rm(jit, REG_EAX, REG_EAX, MOD_REG); - IA32_Mov_Reg_Rm(jit, REG_EDI, REG_EDI, MOD_MEM_REG); - IA32_Add_Reg_Rm(jit, REG_EDI, REG_EBP, MOD_REG); - IA32_Cld(jit); - IA32_Rep(jit); - IA32_Stosd(jit); - IA32_Pop_Reg(jit, REG_EDI); - IA32_Pop_Reg(jit, REG_EAX); - } - } else { - //mov ecx, num_dims - //mov edx, 0/1 - //call [genarray] - IA32_Mov_Reg_Imm32(jit, AMX_REG_TMP, val); - if (autozero) - { - IA32_Mov_Reg_Imm32(jit, REG_EDX, 1); - } else { - IA32_Mov_Reg_Imm32(jit, REG_EDX, 0); - } - jitoffs_t call = IA32_Call_Imm32(jit, 0); - IA32_Write_Jump32_Abs(jit, call, g_Jit.GetGenArrayIntrinsic()); - } -} - -inline void WriteOp_Load_Both(JitWriter *jit) -{ - WriteOp_Load_Pri(jit); - WriteOp_Load_Alt(jit); -} - -inline void WriteOp_Load_S_Both(JitWriter *jit) -{ - WriteOp_Load_S_Pri(jit); - WriteOp_Load_S_Alt(jit); -} - -inline void WriteOp_Const(JitWriter *jit) -{ - //mov [ebp+], - cell_t addr = jit->read_cell(); - cell_t val = jit->read_cell(); - if (addr <= SCHAR_MAX && addr >= SCHAR_MIN) - { - IA32_Mov_Rm_Imm32_Disp8(jit, AMX_REG_DAT, val, (jit_int8_t)addr); - } else { - IA32_Mov_Rm_Imm32_Disp32(jit, AMX_REG_DAT, val, addr); - } -} - -inline void WriteOp_Const_S(JitWriter *jit) -{ - //mov [ebx+], - cell_t offs = jit->read_cell(); - cell_t val = jit->read_cell(); - if (offs <= SCHAR_MAX && offs >= SCHAR_MIN) - { - IA32_Mov_Rm_Imm32_Disp8(jit, AMX_REG_FRM, val, (jit_int8_t)offs); - } else { - IA32_Mov_Rm_Imm32_Disp32(jit, AMX_REG_FRM, val, offs); - } -} - -inline void WriteOp_Load_I(JitWriter *jit) -{ - //mov eax, [ebp+eax] - Write_Check_VerifyAddr(jit, AMX_REG_PRI); - IA32_Mov_Reg_RmEBP_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE); -} - -inline void WriteOp_Lodb_I(JitWriter *jit) -{ - Write_Check_VerifyAddr(jit, AMX_REG_PRI); - - //mov eax, [ebp+eax] - IA32_Mov_Reg_RmEBP_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE); - - //and eax, - cell_t val = jit->read_cell(); - switch(val) - { - case 1: - { - IA32_And_Eax_Imm32(jit, 0x000000FF); - break; - } - case 2: - { - IA32_And_Eax_Imm32(jit, 0x0000FFFF); - break; - } - } -} - -inline void WriteOp_Stor_I(JitWriter *jit) -{ - //mov [ebp+edx], eax - Write_Check_VerifyAddr(jit, AMX_REG_ALT); - IA32_Mov_RmEBP_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_ALT, NOSCALE, AMX_REG_PRI); -} - -inline void WriteOp_Strb_I(JitWriter *jit) -{ - Write_Check_VerifyAddr(jit, AMX_REG_ALT); - //mov [ebp+edx], eax - cell_t val = jit->read_cell(); - switch (val) - { - case 1: - { - IA32_Mov_Rm8EBP_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_ALT, NOSCALE, AMX_REG_PRI); - break; - } - case 2: - { - IA32_Mov_Rm16EBP_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_ALT, NOSCALE, AMX_REG_PRI); - break; - } - case 4: - { - IA32_Mov_RmEBP_Reg_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_ALT, NOSCALE, AMX_REG_PRI); - break; - } - } -} - -inline void WriteOp_Lidx(JitWriter *jit) -{ - //lea eax, [edx+4*eax] - //mov eax, [ebp+eax] - IA32_Lea_Reg_DispRegMult(jit, AMX_REG_PRI, AMX_REG_ALT, AMX_REG_PRI, SCALE4); - Write_Check_VerifyAddr(jit, AMX_REG_PRI); - IA32_Mov_Reg_RmEBP_Disp_Reg(jit, AMX_REG_PRI, AMX_REG_DAT, AMX_REG_PRI, NOSCALE); -} - -inline void WriteOp_Stack(JitWriter *jit) -{ - //add edi, - cell_t val = jit->read_cell(); - if (val <= SCHAR_MAX && val >= SCHAR_MIN) - { - IA32_Add_Rm_Imm8(jit, AMX_REG_STK, (jit_int8_t)val, MOD_REG); - } else { - IA32_Add_Rm_Imm32(jit, AMX_REG_STK, val, MOD_REG); - } - - if (val > 0) - { - Write_CheckStack_Min(jit); - } else if (val < 0) { - Write_CheckStack_Low(jit); - } -} - -inline void WriteOp_StackAdjust(JitWriter *jit) -{ - cell_t val = jit->read_cell(); - - assert(val <= 0); - - //lea edi, [ebx-val] - - if (val <= SCHAR_MAX && val >= SCHAR_MIN) - { - IA32_Lea_DispRegImm8(jit, AMX_REG_STK, AMX_REG_FRM, val); - } - else - { - IA32_Lea_DispRegImm32(jit, AMX_REG_STK, AMX_REG_FRM, val); - } - - /* We assume the compiler has generated good code -- - * That is, we do not bother validating this amount! - */ -} - -inline void WriteOp_Heap(JitWriter *jit) -{ - //mov edx, [esi+hea] - //add [esi+hea], - cell_t val = jit->read_cell(); - IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_ALT, AMX_REG_INFO, AMX_INFO_HEAP); - if (val <= SCHAR_MAX && val >= SCHAR_MIN) - { - IA32_Add_Rm_Imm8_Disp8(jit, AMX_REG_INFO, (jit_int8_t)val, AMX_INFO_HEAP); - } else { - IA32_Add_Rm_Imm32_Disp8(jit, AMX_REG_INFO, val, AMX_INFO_HEAP); - } - - /* NOTE: Backwards from op.stack */ - if (val > 0) - { - Write_CheckHeap_Low(jit); - } else if (val < 0) { - Write_CheckHeap_Min(jit); - } -} - -inline void WriteOp_SDiv(JitWriter *jit) -{ - //mov ecx, edx - //mov edx, eax - //sar edx, 31 - //idiv ecx - IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_ALT, MOD_REG); - IA32_Mov_Reg_Rm(jit, AMX_REG_ALT, AMX_REG_PRI, MOD_REG); - IA32_Sar_Rm_Imm8(jit, AMX_REG_ALT, 31, MOD_REG); - Write_Check_DivZero(jit, AMX_REG_TMP); - IA32_IDiv_Rm(jit, AMX_REG_TMP, MOD_REG); -} - -inline void WriteOp_SDiv_Alt(JitWriter *jit) -{ - //mov ecx, eax - //mov eax, edx - //sar edx, 31 - //idiv 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_Sar_Rm_Imm8(jit, AMX_REG_ALT, 31, MOD_REG); - Write_Check_DivZero(jit, AMX_REG_TMP); - IA32_IDiv_Rm(jit, AMX_REG_TMP, MOD_REG); -} - -inline void WriteOp_Retn(JitWriter *jit) -{ - //mov ebx, [edi+4] - get old frm - //add edi, 8 - pop stack - //mov [esi+frm], ebx - restore frame pointer - //add ebx, ebp - relocate - IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_FRM, AMX_REG_STK, 4); - IA32_Add_Rm_Imm8(jit, AMX_REG_STK, 8, 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); - - /* pop params */ - //mov ecx, [edi] - //lea edi, [edi+ecx*4+4] - IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_STK, MOD_MEM_REG); - IA32_Lea_Reg_DispRegMultImm8(jit, AMX_REG_STK, AMX_REG_STK, AMX_REG_TMP, SCALE4, 4); - - //ret - return (EIP on real stack!) - IA32_Return(jit); -} - -void ProfCallGate_Begin(sp_context_t *ctx, const char *name) -{ - ((IProfiler *)ctx->vm[JITVARS_PROFILER])->OnFunctionBegin((IPluginContext *)ctx->vm[JITVARS_BASECTX], name); -} - -void ProfCallGate_End(sp_context_t *ctx) -{ - ((IProfiler *)ctx->vm[JITVARS_PROFILER])->OnFunctionEnd(); -} - -const char *find_func_name(sp_plugin_t *plugin, uint32_t offs) -{ - if (!plugin->debug.unpacked) - { - uint32_t max, iter; - sp_fdbg_symbol_t *sym; - sp_fdbg_arraydim_t *arr; - uint8_t *cursor = (uint8_t *)(plugin->debug.symbols); - - max = plugin->debug.syms_num; - for (iter = 0; iter < max; iter++) - { - sym = (sp_fdbg_symbol_t *)cursor; - - if (sym->ident == SP_SYM_FUNCTION - && sym->codestart <= offs - && sym->codeend > offs) - { - return plugin->debug.stringbase + sym->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; - } - - cursor += sizeof(sp_fdbg_symbol_t); - } - } - else - { - uint32_t max, iter; - sp_u_fdbg_symbol_t *sym; - sp_u_fdbg_arraydim_t *arr; - uint8_t *cursor = (uint8_t *)(plugin->debug.symbols); - - max = plugin->debug.syms_num; - for (iter = 0; iter < max; iter++) - { - sym = (sp_u_fdbg_symbol_t *)cursor; - - if (sym->ident == SP_SYM_FUNCTION - && sym->codestart <= offs - && sym->codeend > offs) - { - return plugin->debug.stringbase + sym->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; - } - - cursor += sizeof(sp_u_fdbg_symbol_t); - } - } - - return NULL; -} - -inline void WriteOp_Call(JitWriter *jit) -{ - cell_t offs; - jitoffs_t jmp; - CompData *data; - uint32_t func_idx; - - data = (CompData *)jit->data; - offs = jit->read_cell(); - - /* Get the context + rp */ - //mov eax, [esi+ctx] - //mov ecx, [eax+rp] - IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_CONTEXT); - IA32_Mov_Reg_Rm_Disp8(jit, REG_ECX, REG_EAX, offsetof(sp_context_t, rp)); - - /* Check if the return stack is used up. */ - //cmp ecx, - //jae :stacklow - IA32_Cmp_Rm_Imm32(jit, MOD_REG, REG_ECX, SP_MAX_RETURN_STACK); - IA32_Jump_Cond_Imm32_Rel(jit, CC_AE, data->jit_error_stacklow); - - /* Add us to the return stack */ - //mov [eax+ecx*4+cips], cip - IA32_Mov_Rm_Imm32_SIB(jit, - REG_EAX, - (uint8_t *)(jit->inptr - 2) - data->plugin->pcode, - offsetof(sp_context_t, rstk_cips), - REG_ECX, - SCALE4); - - /* Increment the return stack pointer */ - //inc [eax+rp] - if ((int)offsetof(sp_context_t, rp) >= SCHAR_MIN && (int)offsetof(sp_context_t, rp) <= SCHAR_MAX) - { - IA32_Inc_Rm_Disp8(jit, REG_EAX, offsetof(sp_context_t, rp)); - } - else - { - IA32_Inc_Rm_Disp32(jit, REG_EAX, offsetof(sp_context_t, rp)); - } - - /* Store the CIP of the function we're about to call. */ - IA32_Mov_Rm_Imm32_Disp8(jit, AMX_REG_INFO, offs, AMX_INFO_CIP); - - /* Call the function */ - func_idx = FuncLookup(data, offs); - - /* We need to emit a delayed thunk instead. */ - if (func_idx == 0) - { - if (jit->outbase == NULL) - { - data->num_thunks++; - - /* We still emit the call because we need consistent size counting */ - IA32_Call_Imm32(jit, 0); - } - else - { - call_thunk_t *thunk; - - /* Find the thunk we're associated with */ - thunk = &data->thunks[data->num_thunks]; - data->num_thunks++; - - /* Emit the call, save its target position. - * Save thunk info, then patch the target to the thunk. - */ - thunk->patch_addr = IA32_Call_Imm32(jit, 0); - thunk->pcode_offs = offs; - IA32_Write_Jump32(jit, thunk->patch_addr, thunk->thunk_addr); - } - } - /* The function is already jitted. We can emit a direct call. */ - else - { - JitFunction *fn; - - fn = data->runtime->GetJittedFunction(func_idx); - jmp = IA32_Call_Imm32(jit, 0); - IA32_Write_Jump32_Abs(jit, jmp, fn->GetEntryAddress()); - } - - /* Restore the last cip */ - //mov [esi+cip], - IA32_Mov_Rm_Imm32_Disp8(jit, - AMX_REG_INFO, - (uint8_t *)(jit->inptr - 2) - data->plugin->pcode, - AMX_INFO_CIP); - - /* Mark us as leaving the last frame. */ - //mov ecx, [esi+ctx] - //dec [ecx+rp] - IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_CONTEXT); - IA32_Dec_Rm_Disp8(jit, REG_ECX, offsetof(sp_context_t, rp)); -} - -inline void WriteOp_Bounds(JitWriter *jit) -{ - cell_t val = jit->read_cell(); - - //cmp eax, - //ja :error - if (val <= SCHAR_MAX && val >= SCHAR_MIN) - { - IA32_Cmp_Rm_Imm8(jit, MOD_REG, AMX_REG_PRI, (jit_int8_t)val); - } else { - IA32_Cmp_Eax_Imm32(jit, val); - } - IA32_Jump_Cond_Imm32_Rel(jit, CC_A, ((CompData *)jit->data)->jit_error_bounds); -} - -inline void WriteOp_Halt(JitWriter *jit) -{ - AlignMe(jit); - - //mov ecx, [esi+ret] - //mov [ecx], eax - IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_RETVAL); - IA32_Mov_Rm_Reg(jit, AMX_REG_TMP, AMX_REG_PRI, MOD_MEM_REG); - - /* :TODO: - * We don't support sleeping or halting with weird values. - * So we're omitting the mov eax that was here. - */ - jit->read_cell(); - - IA32_Jump_Imm32_Abs(jit, g_Jit.GetReturnPoint()); -} - -inline void WriteOp_Break(JitWriter *jit) -{ - CompData *data; - - data = (CompData *)jit->data; - - //mov [esi+cip], - IA32_Mov_Rm_Imm32_Disp8(jit, - AMX_REG_INFO, - (uint8_t *)(jit->inptr - 1) - data->plugin->pcode, - AMX_INFO_CIP); -} - -inline void WriteOp_Jump(JitWriter *jit) -{ - //jmp - cell_t amx_offs = jit->read_cell(); - IA32_Jump_Imm32_Rel(jit, RelocLookup(jit, amx_offs, false)); -} - -inline void WriteOp_Jzer(JitWriter *jit) -{ - //test eax, eax - //jz - cell_t target = jit->read_cell(); - IA32_Test_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_PRI, MOD_REG); - IA32_Jump_Cond_Imm32_Rel(jit, CC_Z, RelocLookup(jit, target, false)); -} - -inline void WriteOp_Jnz(JitWriter *jit) -{ - //test eax, eax - //jnz - cell_t target = jit->read_cell(); - IA32_Test_Rm_Reg(jit, AMX_REG_PRI, AMX_REG_PRI, MOD_REG); - IA32_Jump_Cond_Imm32_Rel(jit, CC_NZ, RelocLookup(jit, target, false)); -} - -inline void WriteOp_Jeq(JitWriter *jit) -{ - //cmp eax, edx - //je - cell_t target = jit->read_cell(); - IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); - IA32_Jump_Cond_Imm32_Rel(jit, CC_E, RelocLookup(jit, target, false)); -} - -inline void WriteOp_Jneq(JitWriter *jit) -{ - //cmp eax, edx - //jne - cell_t target = jit->read_cell(); - IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); - IA32_Jump_Cond_Imm32_Rel(jit, CC_NE, RelocLookup(jit, target, false)); -} - -inline void WriteOp_Jsless(JitWriter *jit) -{ - //cmp eax, edx - //jl - cell_t target = jit->read_cell(); - IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); - IA32_Jump_Cond_Imm32_Rel(jit, CC_L, RelocLookup(jit, target, false)); -} - -inline void WriteOp_Jsleq(JitWriter *jit) -{ - //cmp eax, edx - //jle - cell_t target = jit->read_cell(); - IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); - IA32_Jump_Cond_Imm32_Rel(jit, CC_LE, RelocLookup(jit, target, false)); -} - -inline void WriteOp_JsGrtr(JitWriter *jit) -{ - //cmp eax, edx - //jg - cell_t target = jit->read_cell(); - IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); - IA32_Jump_Cond_Imm32_Rel(jit, CC_G, RelocLookup(jit, target, false)); -} - -inline void WriteOp_JsGeq(JitWriter *jit) -{ - //cmp eax, edx - //jge - cell_t target = jit->read_cell(); - IA32_Cmp_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_ALT, MOD_REG); - IA32_Jump_Cond_Imm32_Rel(jit, CC_GE, RelocLookup(jit, target, false)); -} - -inline void WriteOp_Switch(JitWriter *jit) -{ - CompData *data = (CompData *)jit->data; - cell_t offs = jit->read_cell(); - cell_t *tbl = (cell_t *)((char *)data->plugin->pcode + offs + sizeof(cell_t)); - - struct casetbl - { - cell_t val; - cell_t offs; - }; - - /* Read the number of cases, then advance by one */ - cell_t num_cases = *tbl++; - if (!num_cases) - { - /* Special treatment for 0 cases */ - //jmp - IA32_Jump_Imm32_Rel(jit, RelocLookup(jit, *tbl, false)); - } else { - /* Check if the case layout is fully sequential */ - casetbl *iter = (casetbl *)(tbl + 1); - casetbl *cases = iter; - cell_t first = iter[0].val; - cell_t last = first; - bool sequential = true; - for (cell_t i=1; i HIGH) - * This check is valid for both sequential and non-sequential. - */ - cell_t low_bound = cases[0].val; - if (low_bound != 0) - { - /* negate it so we'll get a lower bound of 0 */ - //lea ecx, [eax-] - low_bound = -low_bound; - if (low_bound >= SCHAR_MIN && low_bound <= SCHAR_MAX) - { - IA32_Lea_DispRegImm8(jit, AMX_REG_TMP, AMX_REG_PRI, low_bound); - } else { - IA32_Lea_DispRegImm32(jit, AMX_REG_TMP, AMX_REG_PRI, low_bound); - } - } else { - //mov ecx, eax - IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_PRI, MOD_REG); - } - cell_t high_bound = abs(cases[0].val - cases[num_cases-1].val); - //cmp ecx, - if (high_bound >= SCHAR_MIN && high_bound <= SCHAR_MAX) - { - IA32_Cmp_Rm_Imm8(jit, MOD_REG, AMX_REG_TMP, high_bound); - } else { - IA32_Cmp_Rm_Imm32(jit, MOD_REG, AMX_REG_TMP, high_bound); - } - //ja - IA32_Jump_Cond_Imm32_Rel(jit, CC_A, RelocLookup(jit, *tbl, false)); - - /** - * Now we've taken the default case out of the way, it's time to do the - * full check, which is different for sequential vs. non-sequential. - */ - if (sequential) - { - /* we're now theoretically guaranteed to be jumping to a correct offset. - * ECX still has the correctly bound offset in it, luckily! - * thus, we simply need to relocate ECX and store the cases. - */ - //lea ecx, [ecx*4] - //add ecx, - IA32_Lea_Reg_RegMultImm32(jit, AMX_REG_TMP, AMX_REG_TMP, SCALE4, 0); - jitoffs_t tbl_offs = IA32_Add_Rm_Imm32_Later(jit, AMX_REG_TMP, MOD_REG); - IA32_Jump_Rm(jit, AMX_REG_TMP, MOD_MEM_REG); - /* The case table starts here. Go back and write the output pointer. */ - jitoffs_t cur_pos = jit->get_outputpos(); - jit->set_outputpos(tbl_offs); - jit->write_uint32((jit_uint32_t)(jit->outbase + cur_pos)); - jit->set_outputpos(cur_pos); - //now we can write the case table, finally! - jit_uint32_t base = (jit_uint32_t)jit->outbase; - for (cell_t i=0; iwrite_uint32(base + RelocLookup(jit, cases[i].offs, false)); - } - } else { - /* The slow version. Go through each case and generate a check. - * In the future we should replace case tables of more than ~8 cases with a - * hash table lookup. - * :THOUGHT: Another method of optimizing this - fill in the gaps with jumps to the default case, - * but only if we're under N cases or so! - * :THOUGHT: Write out a static btree lookup :) - */ - cell_t val; - for (cell_t i=0; i - IA32_Cmp_Eax_Imm32(jit, val); - IA32_Jump_Cond_Imm32_Rel(jit, CC_E, RelocLookup(jit, cases[i].offs, false)); - } - /* After all this, jump to the default case! */ - IA32_Jump_Imm32_Rel(jit, RelocLookup(jit, *tbl, false)); - } - } -} - -inline void WriteOp_Casetbl(JitWriter *jit) -{ - /* do nothing here, switch does all ze work */ - cell_t num_cases = jit->read_cell(); - - /* Two cells per case, one extra case for the default jump */ - num_cases = (num_cases * 2) + 1; - jit->inptr += num_cases; -} - -inline void WriteOp_Sysreq_C(JitWriter *jit) -{ - /* store the number of parameters on the stack, - * and store the native index as well. - */ - cell_t native_index = jit->read_cell(); - - if ((uint32_t)native_index >= ((CompData*)jit->data)->plugin->num_natives) - { - ((CompData *)jit->data)->error_set = SP_ERROR_INSTRUCTION_PARAM; - return; - } - - //mov ecx, - IA32_Mov_Reg_Imm32(jit, REG_ECX, native_index); - - jitoffs_t call = IA32_Call_Imm32(jit, 0); - IA32_Write_Jump32(jit, call, ((CompData *)jit->data)->jit_sysreq_c); -} - -inline void WriteOp_Sysreq_N(JitWriter *jit) -{ - /* The big daddy of opcodes. */ - cell_t native_index = jit->read_cell(); - cell_t num_params = jit->read_cell(); - CompData *data = (CompData *)jit->data; - - if ((uint32_t)native_index >= data->plugin->num_natives) - { - data->error_set = SP_ERROR_INSTRUCTION_PARAM; - return; - } - - /* store the number of parameters on the stack */ - //mov [edi-4], num_params - //sub edi, 4 - IA32_Mov_Rm_Imm32_Disp8(jit, AMX_REG_STK, num_params, -4); - IA32_Sub_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG); - - /* 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 ; native index - IA32_Push_Reg(jit, AMX_REG_STK); - if (native_index <= SCHAR_MAX && native_index >= SCHAR_MIN) - { - IA32_Push_Imm8(jit, (jit_int8_t)native_index); - } else { - IA32_Push_Imm32(jit, native_index); - } - - /* 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); - if ((data->profile & SP_PROF_NATIVES) == SP_PROF_NATIVES) - { - IA32_Write_Jump32_Abs(jit, call, (void *)NativeCallback_Profile); - } - else - { - IA32_Write_Jump32_Abs(jit, call, (void *)NativeCallback); - } - - /* check for errors */ - //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); - - /* pop the stack. do not check the margins. - * Note that this is not a true macro - we don't bother to - * set ALT here because nothing will be using it. - */ - num_params++; - num_params *= 4; - //add edi, - if (num_params <= SCHAR_MAX && num_params >= SCHAR_MIN) - { - IA32_Add_Rm_Imm8(jit, AMX_REG_STK, (jit_int8_t)num_params, MOD_REG); - } else { - IA32_Add_Rm_Imm32(jit, AMX_REG_STK, num_params, MOD_REG); - } -} - -inline void WriteOp_Tracker_Push_C(JitWriter *jit) -{ - cell_t val = jit->read_cell(); - - /* Save registers that may be damaged by the call */ - //push eax - //push edx - IA32_Push_Reg(jit, AMX_REG_PRI); - IA32_Push_Reg(jit, AMX_REG_ALT); - - /* 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 value into the stack and increment pCur */ - //mov edx, [eax+vm[]] - //mov ecx, [edx+pcur] - //add [edx+pcur], 4 - //mov [ecx], *4 ; we want the count in bytes not in cells - IA32_Mov_Reg_Rm_Disp8(jit, REG_EDX, REG_EAX, offsetof(sp_context_t, vm[JITVARS_TRACKER])); - IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, REG_EDX, offsetof(tracker_t, pCur)); - IA32_Add_Rm_Imm8_Disp8(jit, REG_EDX, 4, offsetof(tracker_t, pCur)); - IA32_Mov_Rm_Imm32(jit, AMX_REG_TMP, val*4, MOD_MEM_REG); - - /* Restore PRI & ALT */ - //pop edx - //pop eax - IA32_Pop_Reg(jit, AMX_REG_ALT); - IA32_Pop_Reg(jit, AMX_REG_PRI); -} - -inline void WriteOp_Tracker_Pop_SetHeap(JitWriter *jit) -{ - /* Save registers that may be damaged by the call */ - //push eax - //push edx - IA32_Push_Reg(jit, AMX_REG_PRI); - IA32_Push_Reg(jit, AMX_REG_ALT); - - /* Get the context ptr, push it and call the check */ - //mov eax, [esi+context] - //push eax - //call JIT_VerifyLowBoundTracker - 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_VerifyLowBoundTracker); - - /* 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); - - /* Pop the value from the stack and decrease the heap by it*/ - //mov edx, [eax+vm[]] - //sub [edx+pcur], 4 - //mov ecx, [edx+pcur] - //mov ecx, [ecx] - //sub [esi+hea], ecx - IA32_Mov_Reg_Rm_Disp8(jit, REG_EDX, REG_EAX, offsetof(sp_context_t, vm[JITVARS_TRACKER])); - IA32_Sub_Rm_Imm8_Disp8(jit, REG_EDX, 4, offsetof(tracker_t, pCur)); - IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, REG_EDX, offsetof(tracker_t, pCur)); - IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_TMP, MOD_MEM_REG); - IA32_Sub_Rm_Reg_Disp8(jit, AMX_REG_INFO, AMX_REG_TMP, AMX_INFO_HEAP); - - Write_CheckHeap_Min(jit); - - /* Restore PRI & ALT */ - //pop edx - //pop eax - IA32_Pop_Reg(jit, AMX_REG_ALT); - IA32_Pop_Reg(jit, AMX_REG_PRI); -} - -inline void WriteOp_Stradjust_Pri(JitWriter *jit) -{ - //add eax, 4 - //sar eax, 2 - IA32_Add_Rm_Imm8(jit, AMX_REG_PRI, 4, MOD_REG); - IA32_Sar_Rm_Imm8(jit, AMX_REG_PRI, 2, MOD_REG); -} - -inline void WriteOp_FloatAbs(JitWriter *jit) -{ - //mov eax, [edi] - //and eax, 0x7FFFFFFF - IA32_Mov_Reg_Rm(jit, AMX_REG_PRI, AMX_REG_STK, MOD_MEM_REG); - IA32_And_Eax_Imm32(jit, 0x7FFFFFFF); - - /* Rectify the stack */ - //add edi, 4 - IA32_Add_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG); -} - -inline void WriteOp_Float(JitWriter *jit) -{ - //fild [edi] - //push eax - //fstp [esp] - //pop eax - IA32_Fild_Mem32(jit, AMX_REG_STK); - IA32_Push_Reg(jit, AMX_REG_PRI); - IA32_Fstp_Mem32_ESP(jit); - IA32_Pop_Reg(jit, AMX_REG_PRI); - - /* Rectify the stack */ - //add edi, 4 - IA32_Add_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG); -} - -inline void WriteOp_FloatAdd(JitWriter *jit) -{ - //push eax - //fld [edi] - //fadd [edi+4] - //fstp [esp] - //pop eax - IA32_Push_Reg(jit, AMX_REG_PRI); - IA32_Fld_Mem32(jit, AMX_REG_STK); - IA32_Fadd_Mem32_Disp8(jit, AMX_REG_STK, 4); - IA32_Fstp_Mem32_ESP(jit); - IA32_Pop_Reg(jit, AMX_REG_PRI); - - /* Rectify the stack */ - //add edi, 8 - IA32_Add_Rm_Imm8(jit, AMX_REG_STK, 8, MOD_REG); -} - -inline void WriteOp_FloatSub(JitWriter *jit) -{ - //push eax - //fld [edi] - //fsub [edi+4] - //fstp [esp] - //pop eax - IA32_Push_Reg(jit, AMX_REG_PRI); - IA32_Fld_Mem32(jit, AMX_REG_STK); - IA32_Fsub_Mem32_Disp8(jit, AMX_REG_STK, 4); - IA32_Fstp_Mem32_ESP(jit); - IA32_Pop_Reg(jit, AMX_REG_PRI); - - /* Rectify the stack */ - //add edi, 8 - IA32_Add_Rm_Imm8(jit, AMX_REG_STK, 8, MOD_REG); -} - -inline void WriteOp_FloatMul(JitWriter *jit) -{ - //push eax - //fld [edi] - //fmul [edi+4] - //fstp [esp] - //pop eax - IA32_Push_Reg(jit, AMX_REG_PRI); - IA32_Fld_Mem32(jit, AMX_REG_STK); - IA32_Fmul_Mem32_Disp8(jit, AMX_REG_STK, 4); - IA32_Fstp_Mem32_ESP(jit); - IA32_Pop_Reg(jit, AMX_REG_PRI); - - /* Rectify the stack */ - //add edi, 8 - IA32_Add_Rm_Imm8(jit, AMX_REG_STK, 8, MOD_REG); -} - -inline void WriteOp_FloatDiv(JitWriter *jit) -{ - //push eax - //fld [edi] - //fdiv [edi+4] - //fstp [esp] - //pop eax - IA32_Push_Reg(jit, AMX_REG_PRI); - IA32_Fld_Mem32(jit, AMX_REG_STK); - IA32_Fdiv_Mem32_Disp8(jit, AMX_REG_STK, 4); - IA32_Fstp_Mem32_ESP(jit); - IA32_Pop_Reg(jit, AMX_REG_PRI); - - /* Rectify the stack */ - //add edi, 8 - IA32_Add_Rm_Imm8(jit, AMX_REG_STK, 8, MOD_REG); -} - -inline void WriteOp_RountToNearest(JitWriter *jit) -{ - //push eax - //fld [edi] - - //fstcw [esp] - //mov eax, [esp] - //push eax - - //mov [esp+4], 0x3FF - //fadd st(0), st(0) - //fldcw [esp+4] - - //push eax - //push 0x3F000000 ; 0.5f - //fadd [esp] - //fistp [esp+4] - //pop eax - //pop eax - - //pop ecx - //sar eax, 1 - //mov [esp], ecx - //fldcw [esp] - //add esp, 4 - - IA32_Push_Reg(jit, REG_EAX); - IA32_Fld_Mem32(jit, AMX_REG_STK); - - IA32_Fstcw_Mem16_ESP(jit); - IA32_Mov_Reg_RmESP(jit, REG_EAX); - IA32_Push_Reg(jit, REG_EAX); - - IA32_Mov_ESP_Disp8_Imm32(jit, 4, 0x3FF); - IA32_Fadd_FPUreg_ST0(jit, 0); - IA32_Fldcw_Mem16_Disp8_ESP(jit, 4); - - IA32_Push_Reg(jit, REG_EAX); - IA32_Push_Imm32(jit, 0x3F000000); - IA32_Fadd_Mem32_ESP(jit); - IA32_Fistp_Mem32_Disp8_Esp(jit, 4); - IA32_Pop_Reg(jit, REG_EAX); - IA32_Pop_Reg(jit, AMX_REG_PRI); - - IA32_Pop_Reg(jit, REG_ECX); - IA32_Sar_Rm_1(jit, REG_EAX, MOD_REG); - IA32_Mov_RmESP_Reg(jit, REG_ECX); - IA32_Fldcw_Mem16_ESP(jit); - IA32_Add_Rm_Imm8(jit, REG_ESP, 4, MOD_REG); - - /* Rectify the stack */ - //add edi, 4 - IA32_Add_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG); -} - -inline void WriteOp_RoundToFloor(JitWriter *jit) -{ - //push eax - //fld [edi] - - //fstcw [esp] - //mov eax, [esp] - //push eax - - //mov [esp+4], 0x7FF - //fldcw [esp+4] - - //push eax - //fistp [esp] - //pop eax - - //pop ecx - //mov [esp], ecx - //fldcw [esp] - //add esp, 4 - - IA32_Push_Reg(jit, REG_EAX); - IA32_Fld_Mem32(jit, AMX_REG_STK); - - IA32_Fstcw_Mem16_ESP(jit); - IA32_Mov_Reg_RmESP(jit, REG_EAX); - IA32_Push_Reg(jit, REG_EAX); - - IA32_Mov_ESP_Disp8_Imm32(jit, 4, 0x7FF); - IA32_Fldcw_Mem16_Disp8_ESP(jit, 4); - - IA32_Push_Reg(jit, REG_EAX); - IA32_Fistp_Mem32_ESP(jit); - IA32_Pop_Reg(jit, REG_EAX); - - IA32_Pop_Reg(jit, REG_ECX); - IA32_Mov_RmESP_Reg(jit, REG_ECX); - IA32_Fldcw_Mem16_ESP(jit); - IA32_Add_Rm_Imm8(jit, REG_ESP, 4, MOD_REG); - - /* Rectify the stack */ - //add edi, 4 - IA32_Add_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG); -} - -inline void WriteOp_RoundToCeil(JitWriter *jit) -{ - //push eax - //fld [edi] - - //fstcw [esp] - //mov eax, [esp] - //push eax - - //mov [esp+4], 0xBFF - //fldcw [esp+4] - - //push eax - //fistp [esp] - //pop eax - - //pop ecx - //mov [esp], ecx - //fldcw [esp] - //add esp, 4 - - IA32_Push_Reg(jit, REG_EAX); - IA32_Fld_Mem32(jit, AMX_REG_STK); - - IA32_Fstcw_Mem16_ESP(jit); - IA32_Mov_Reg_RmESP(jit, REG_EAX); - IA32_Push_Reg(jit, REG_EAX); - - IA32_Mov_ESP_Disp8_Imm32(jit, 4, 0xBFF); - IA32_Fldcw_Mem16_Disp8_ESP(jit, 4); - - IA32_Push_Reg(jit, REG_EAX); - IA32_Fistp_Mem32_ESP(jit); - IA32_Pop_Reg(jit, REG_EAX); - - IA32_Pop_Reg(jit, REG_ECX); - IA32_Mov_RmESP_Reg(jit, REG_ECX); - IA32_Fldcw_Mem16_ESP(jit); - IA32_Add_Rm_Imm8(jit, REG_ESP, 4, MOD_REG); - - /* Rectify the stack */ - //add edi, 4 - IA32_Add_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG); -} - -inline void WriteOp_RoundToZero(JitWriter *jit) -{ - //push eax - //fld [edi] - - //fstcw [esp] - //mov eax, [esp] - //push eax - - //mov [esp+4], 0xFFF - //fldcw [esp+4] - - //push eax - //fistp [esp] - //pop eax - - //pop ecx - //mov [esp], ecx - //fldcw [esp] - //add esp, 4 - - IA32_Push_Reg(jit, REG_EAX); - IA32_Fld_Mem32(jit, AMX_REG_STK); - - IA32_Fstcw_Mem16_ESP(jit); - IA32_Mov_Reg_RmESP(jit, REG_EAX); - IA32_Push_Reg(jit, REG_EAX); - - IA32_Mov_ESP_Disp8_Imm32(jit, 4, 0xFFF); - IA32_Fldcw_Mem16_Disp8_ESP(jit, 4); - - IA32_Push_Reg(jit, REG_EAX); - IA32_Fistp_Mem32_ESP(jit); - IA32_Pop_Reg(jit, REG_EAX); - - IA32_Pop_Reg(jit, REG_ECX); - IA32_Mov_RmESP_Reg(jit, REG_ECX); - IA32_Fldcw_Mem16_ESP(jit); - IA32_Add_Rm_Imm8(jit, REG_ESP, 4, MOD_REG); - - /* Rectify the stack */ - //add edi, 4 - IA32_Add_Rm_Imm8(jit, AMX_REG_STK, 4, MOD_REG); -} - -inline void WriteOp_FloatCompare(JitWriter *jit) -{ - //fld [edi] - //fld [edi+4] - //fucomip st(0), st(1) - //mov ecx, - //cmovz eax, [ecx+4] - //cmovb eax, [ecx+8] - //cmova eax, [ecx] - //fstp st(0) - - IA32_Fld_Mem32(jit, AMX_REG_STK); - IA32_Fld_Mem32_Disp8(jit, AMX_REG_STK, 4); - IA32_Fucomip_ST0_FPUreg(jit, 1); - IA32_Mov_Reg_Imm32(jit, AMX_REG_TMP, (jit_int32_t)g_Jit.GetRoundingTable()); - IA32_CmovCC_Rm_Disp8(jit, AMX_REG_TMP, CC_Z, 4); - IA32_CmovCC_Rm_Disp8(jit, AMX_REG_TMP, CC_B, 8); - IA32_CmovCC_Rm(jit, AMX_REG_TMP, CC_A); - IA32_Fstp_FPUreg(jit, 0); - - /* Rectify the stack */ - //add edi, 8 - IA32_Add_Rm_Imm8(jit, AMX_REG_STK, 8, MOD_REG); -} - -inline void WriteOp_EndProc(JitWriter *jit) -{ -} - -void Write_CallThunk(JitWriter *jit, jitoffs_t jmploc, cell_t pcode_offs) -{ - CompData *data; - jitoffs_t call; - - data = (CompData *)jit->data; - - //push - //push - //push - //call CompileFromThunk - //add esp, 4*3 - //test eax, eax - //jz :error - //call eax - //ret - IA32_Push_Imm32(jit, (jit_int32_t)(jit->outbase + jmploc)); - IA32_Push_Imm32(jit, pcode_offs); - IA32_Push_Imm32(jit, (jit_int32_t)(data->runtime)); - call = IA32_Call_Imm32(jit, 0); - IA32_Write_Jump32_Abs(jit, call, (void *)CompileThunk); - IA32_Add_Rm_Imm32(jit, REG_ESP, 4*3, MOD_REG); - IA32_Test_Rm_Reg(jit, REG_EAX, REG_EAX, MOD_REG); - call = IA32_Jump_Cond_Imm8(jit, CC_Z, 0); - IA32_Call_Reg(jit, REG_EAX); - IA32_Return(jit); - - /* We decrement the frame and store the target cip. */ - //:error - //mov [esi+cip], pcode_offs - //goto error - IA32_Send_Jump8_Here(jit, call); - Write_SetError(jit, SP_ERROR_INVALID_INSTRUCTION); -} - -/************************************************* - ************************************************* - * JIT PROPER ************************************ - * The rest from now on is the JIT engine * - ************************************************* - *************************************************/ - -void *CompileThunk(BaseRuntime *runtime, cell_t pcode_offs, void *jmploc_addr) -{ - int err; - JitFunction *fn; - uint32_t func_idx; - void *target_addr; - - if ((func_idx = FuncLookup((CompData *)runtime->m_pCo, pcode_offs)) == 0) - { - fn = g_Jit.CompileFunction(runtime, pcode_offs, &err); - } - else - { - fn = runtime->GetJittedFunction(func_idx); - -#if defined _DEBUG - g_engine1.GetDebugHook()->OnDebugSpew("Patching thunk to %s::%s", runtime->m_pPlugin->name, find_func_name(runtime->m_pPlugin, pcode_offs)); +static int +CompileFromThunk(BaseRuntime *runtime, cell_t pcode_offs, void **addrp, char *pc) +{ + JitFunction *fn = runtime->GetJittedFunctionByOffset(pcode_offs); + if (!fn) { + int err; + fn = g_Jit.CompileFunction(runtime, pcode_offs, &err); + if (!fn) + return err; + } + +#if !defined NDEBUG + g_engine1.GetDebugHook()->OnDebugSpew( + "Patching thunk to %s::%s\n", + runtime->plugin()->name, + GetFunctionName(runtime->plugin(), pcode_offs)); #endif - } + *addrp = fn->GetEntryAddress(); - if (fn == NULL) - { - return NULL; - } - - target_addr = fn->GetEntryAddress(); - - /* Right now, we always keep the code RWE */ - *(intptr_t *)((char *)jmploc_addr) = - intptr_t(target_addr) - (intptr_t(jmploc_addr) + 4); - - return target_addr; + /* Right now, we always keep the code RWE */ + *(intptr_t *)(pc - 4) = intptr_t(fn->GetEntryAddress()) - intptr_t(pc); + return SP_ERROR_NONE; } -cell_t NativeCallback(sp_context_t *ctx, ucell_t native_idx, cell_t *params) +static cell_t +NativeCallback(sp_context_t *ctx, ucell_t native_idx, cell_t *params) { - sp_native_t *native; - cell_t save_sp = ctx->sp; - cell_t save_hp = ctx->hp; - sp_plugin_t *pl = GETPLUGIN(ctx); + sp_native_t *native; + cell_t save_sp = ctx->sp; + cell_t save_hp = ctx->hp; + sp_plugin_t *pl = (sp_plugin_t *)(ctx->vm[JITVARS_PLUGIN]); - ctx->n_idx = native_idx; + ctx->n_idx = native_idx; - if (ctx->hp < (cell_t)pl->data_size) - { - ctx->n_err = SP_ERROR_HEAPMIN; - return 0; - } + if (ctx->hp < (cell_t)pl->data_size) { + ctx->n_err = SP_ERROR_HEAPMIN; + return 0; + } - if (ctx->hp + STACK_MARGIN > ctx->sp) - { - ctx->n_err = SP_ERROR_STACKLOW; - return 0; - } + if (ctx->hp + STACK_MARGIN > ctx->sp) { + ctx->n_err = SP_ERROR_STACKLOW; + return 0; + } - if ((uint32_t)ctx->sp >= pl->mem_size) - { - ctx->n_err = SP_ERROR_STACKMIN; - return 0; - } + if ((uint32_t)ctx->sp >= pl->mem_size) { + ctx->n_err = SP_ERROR_STACKMIN; + return 0; + } - native = &pl->natives[native_idx]; + native = &pl->natives[native_idx]; - if (native->status == SP_NATIVE_UNBOUND) - { - ctx->n_err = SP_ERROR_INVALID_NATIVE; - return 0; - } + if (native->status == SP_NATIVE_UNBOUND) { + ctx->n_err = SP_ERROR_INVALID_NATIVE; + return 0; + } - cell_t result = native->pfn(GET_CONTEXT(ctx), params); + cell_t result = native->pfn(GET_CONTEXT(ctx), params); - if (ctx->n_err != SP_ERROR_NONE) - { - return result; - } + if (ctx->n_err != SP_ERROR_NONE) + return result; - if (save_sp != ctx->sp) - { - ctx->n_err = SP_ERROR_STACKLEAK; - return result; - } - else if (save_hp != ctx->hp) - { - ctx->n_err = SP_ERROR_HEAPLEAK; - return result; - } + if (save_sp != ctx->sp) { + ctx->n_err = SP_ERROR_STACKLEAK; + return result; + } + if (save_hp != ctx->hp) { + ctx->n_err = SP_ERROR_HEAPLEAK; + return result; + } - return result; + return result; } -cell_t NativeCallback_Profile(sp_context_t *ctx, ucell_t native_idx, cell_t *params) +Compiler::Compiler(BaseRuntime *rt, cell_t pcode_offs) + : rt_(rt), + plugin_(rt->plugin()), + error_(SP_ERROR_NONE), + pcode_start_(pcode_offs), + code_start_(reinterpret_cast(plugin_->pcode + pcode_start_)), + cip_(code_start_), + code_end_(reinterpret_cast(plugin_->pcode + plugin_->pcode_size)) { - /* :TODO: */ - return NativeCallback(ctx, native_idx, params); + size_t nmaxops = plugin_->pcode_size / sizeof(cell_t) + 1; + jump_map_ = new Label[nmaxops]; } -uint32_t FuncLookup(CompData *data, cell_t pcode_offs) +Compiler::~Compiler() { - /* Offset must always be 1)positive and 2)less than or equal to the codesize */ - assert(pcode_offs >= 0 && (uint32_t)pcode_offs <= data->plugin->pcode_size); - - /* Do the lookup in the native dictionary. */ - return *(jitoffs_t *)(data->rebase + pcode_offs); + delete [] jump_map_; } -jitoffs_t RelocLookup(JitWriter *jit, cell_t pcode_offs, bool relative) +JitFunction * +Compiler::emit(int *errp) { - if (jit->outptr) - { - CompData *data = (CompData *)jit->data; - if (relative) - { - /* The actual offset is EIP relative. We need to relocate it. - * Note that this assumes that we're pointing to the next op. - */ - pcode_offs += jit->get_inputpos(); - } - /* Offset must always be 1)positive and 2)less than or equal to the codesize */ - assert(pcode_offs >= 0 && (uint32_t)pcode_offs <= data->plugin->pcode_size); - /* Do the lookup in the native dictionary. */ -#if defined _DEBUG - if (jit->outbase != NULL) - { - assert(*(jitoffs_t *)(data->rebase + pcode_offs) != 0); - } + if (cip_ >= code_end_ || *cip_ != OP_PROC) { + *errp = SP_ERROR_INVALID_INSTRUCTION; + return NULL; + } + +#if !defined NDEBUG + g_engine1.GetDebugHook()->OnDebugSpew( + "Compiling function %s::%s\n", + plugin_->name, + GetFunctionName(plugin_, pcode_start_)); + + SpewOpcode(plugin_, code_start_, cip_); #endif - return *(jitoffs_t *)(data->rebase + pcode_offs); - } - else - { - return 0; - } + + cell_t *codeseg = reinterpret_cast(plugin_->pcode); + + cip_++; + if (!emitOp(OP_PROC)) { + *errp = (error_ == SP_ERROR_NONE) ? SP_ERROR_OUT_OF_MEMORY : error_; + return NULL; + } + + while (cip_ < code_end_) { + // If we reach the end of this function, or the beginning of a new + // procedure, then stop. + if (*cip_ == OP_PROC || *cip_ == OP_ENDPROC) + break; + +#if !defined NDEBUG + SpewOpcode(plugin_, code_start_, cip_); +#endif + + // We assume every instruction is a jump target, so before emitting + // an opcode, we bind its corresponding label. + __ bind(&jump_map_[cip_ - codeseg]); + + OPCODE op = (OPCODE)readCell(); + if (!emitOp(op) || error_ != SP_ERROR_NONE) { + *errp = (error_ == SP_ERROR_NONE) ? SP_ERROR_OUT_OF_MEMORY : error_; + return NULL; + } + } + + emitCallThunks(); + emitErrorPaths(); + + void *code = LinkCode(masm); + if (!code) { + *errp = SP_ERROR_OUT_OF_MEMORY; + return NULL; + } + + return new JitFunction(code, pcode_start_); } -void WriteErrorRoutines(CompData *data, JitWriter *jit) +bool +Compiler::emitOp(OPCODE op) { - AlignMe(jit); + switch (op) { + case OP_MOVE_PRI: + __ movl(pri, alt); + break; - data->jit_error_divzero = jit->get_outputpos(); - Write_SetError(jit, SP_ERROR_DIVIDE_BY_ZERO); + case OP_MOVE_ALT: + __ movl(alt, pri); + break; - data->jit_error_stacklow = jit->get_outputpos(); - Write_SetError(jit, SP_ERROR_STACKLOW); + case OP_XCHG: + __ xchgl(pri, alt); + break; - data->jit_error_stackmin = jit->get_outputpos(); - Write_SetError(jit, SP_ERROR_STACKMIN); + case OP_ZERO: + { + cell_t offset = readCell(); + __ movl(Operand(dat, offset), 0); + break; + } - data->jit_error_bounds = jit->get_outputpos(); - Write_SetError(jit, SP_ERROR_ARRAY_BOUNDS); + case OP_ZERO_S: + { + cell_t offset = readCell(); + __ movl(Operand(frm, offset), 0); + break; + } - data->jit_error_memaccess = jit->get_outputpos(); - Write_SetError(jit, SP_ERROR_MEMACCESS); + case OP_PUSH_PRI: + case OP_PUSH_ALT: + { + Register reg = (op == OP_PUSH_PRI) ? pri : alt; + __ movl(Operand(stk, -4), reg); + __ subl(stk, 4); + break; + } - data->jit_error_heaplow = jit->get_outputpos(); - Write_SetError(jit, SP_ERROR_HEAPLOW); + case OP_PUSH_C: + case OP_PUSH2_C: + case OP_PUSH3_C: + case OP_PUSH4_C: + case OP_PUSH5_C: + { + int n = 1; + if (op >= OP_PUSH2_C) + n = ((op - OP_PUSH2_C) / 4) + 2; - data->jit_error_heapmin = jit->get_outputpos(); - Write_SetError(jit, SP_ERROR_HEAPMIN); + int i = 1; + do { + cell_t val = readCell(); + __ movl(Operand(stk, -(4 * i)), val); + } while (i++ < n); + __ subl(stk, 4 * n); + break; + } - data->jit_extern_error = jit->get_outputpos(); - Write_GetError(jit); + case OP_PUSH_ADR: + case OP_PUSH2_ADR: + case OP_PUSH3_ADR: + case OP_PUSH4_ADR: + case OP_PUSH5_ADR: + { + int n = 1; + if (op >= OP_PUSH2_ADR) + n = ((op - OP_PUSH2_ADR) / 4) + 2; + + int i = 1; + + // We temporarily relocate FRM to be a local address instead of an + // absolute address. + __ subl(frm, dat); + do { + cell_t offset = readCell(); + __ lea(tmp, Operand(frm, offset)); + __ movl(Operand(stk, -(4 * i)), tmp); + } while (i++ < n); + __ subl(stk, 4 * n); + __ addl(frm, dat); + break; + } + + case OP_PUSH_S: + case OP_PUSH2_S: + case OP_PUSH3_S: + case OP_PUSH4_S: + case OP_PUSH5_S: + { + int n = 1; + if (op >= OP_PUSH2_S) + n = ((op - OP_PUSH2_S) / 4) + 2; + + int i = 1; + do { + cell_t offset = readCell(); + __ movl(tmp, Operand(frm, offset)); + __ movl(Operand(stk, -(4 * i)), tmp); + } while (i++ < n); + __ subl(stk, 4 * n); + break; + } + + case OP_PUSH: + case OP_PUSH2: + case OP_PUSH3: + case OP_PUSH4: + case OP_PUSH5: + { + int n = 1; + if (op >= OP_PUSH2) + n = ((op - OP_PUSH2) / 4) + 2; + + int i = 1; + do { + cell_t offset = readCell(); + __ movl(tmp, Operand(dat, offset)); + __ movl(Operand(stk, -(4 * i)), tmp); + } while (i++ < n); + __ subl(stk, 4 * n); + break; + } + + case OP_ZERO_PRI: + __ xorl(pri, pri); + break; + + case OP_ZERO_ALT: + __ xorl(alt, alt); + break; + + case OP_ADD: + __ addl(pri, alt); + break; + + case OP_SUB: + __ subl(pri, alt); + break; + + case OP_SUB_ALT: + __ movl(tmp, alt); + __ subl(tmp, pri); + __ movl(pri, tmp); + break; + + case OP_PROC: + // Push the old frame onto the stack. + __ movl(tmp, Operand(info, AMX_INFO_FRAME)); + __ movl(Operand(stk, -4), tmp); + __ subl(stk, 8); // extra unused slot for non-existant CIP + + // Get and store the new frame. + __ movl(tmp, stk); + __ movl(frm, stk); + __ subl(tmp, dat); + __ movl(Operand(info, AMX_INFO_FRAME), tmp); + break; + + case OP_IDXADDR_B: + { + cell_t val = readCell(); + __ shll(pri, val); + __ addl(pri, alt); + break; + } + + case OP_SHL: + __ movl(ecx, alt); + __ shll_cl(pri); + break; + + case OP_SHR: + __ movl(ecx, alt); + __ shrl_cl(pri); + break; + + case OP_SSHR: + __ movl(ecx, alt); + __ sarl_cl(pri); + break; + + case OP_SHL_C_PRI: + case OP_SHL_C_ALT: + { + Register reg = (op == OP_SHL_C_PRI) ? pri : alt; + cell_t val = readCell(); + __ shll(reg, val); + break; + } + + case OP_SHR_C_PRI: + case OP_SHR_C_ALT: + { + Register reg = (op == OP_SHR_C_PRI) ? pri : alt; + cell_t val = readCell(); + __ shrl(reg, val); + break; + } + + case OP_SMUL: + __ imull(pri, alt); + break; + + case OP_NOT: + __ testl(eax, eax); + __ movl(eax, 0); + __ set(zero, r8_al); + break; + + case OP_NEG: + __ negl(eax); + break; + + case OP_XOR: + __ xorl(pri, alt); + break; + + case OP_OR: + __ orl(pri, alt); + break; + + case OP_AND: + __ andl(pri, alt); + break; + + case OP_INVERT: + __ notl(pri); + break; + + case OP_ADD_C: + { + cell_t val = readCell(); + __ addl(pri, val); + break; + } + + case OP_SMUL_C: + { + cell_t val = readCell(); + __ imull(pri, pri, val); + break; + } + + case OP_EQ: + case OP_NEQ: + case OP_SLESS: + case OP_SLEQ: + case OP_SGRTR: + case OP_SGEQ: + { + ConditionCode cc = OpToCondition(op); + __ cmpl(pri, alt); + __ movl(pri, 0); + __ set(cc, r8_al); + break; + } + + case OP_EQ_C_PRI: + case OP_EQ_C_ALT: + { + Register reg = (op == OP_EQ_C_PRI) ? pri : alt; + cell_t val = readCell(); + __ cmpl(reg, val); + __ movl(pri, 0); + __ set(equal, r8_al); + break; + } + + case OP_INC_PRI: + case OP_INC_ALT: + { + Register reg = (OP_INC_PRI) ? pri : alt; + __ addl(reg, 1); + break; + } + + case OP_INC: + case OP_INC_S: + { + Register base = (op == OP_INC) ? dat : frm; + cell_t offset = readCell(); + __ addl(Operand(base, offset), 1); + break; + } + + case OP_INC_I: + __ addl(Operand(dat, pri, NoScale), 1); + break; + + case OP_DEC_PRI: + case OP_DEC_ALT: + { + Register reg = (op == OP_DEC_PRI) ? pri : alt; + __ subl(reg, 1); + break; + } + + case OP_DEC: + case OP_DEC_S: + { + Register base = (op == OP_DEC) ? dat : frm; + cell_t offset = readCell(); + __ subl(Operand(base, offset), 1); + break; + } + + case OP_DEC_I: + __ subl(Operand(dat, pri, NoScale), 1); + break; + + case OP_LOAD_PRI: + case OP_LOAD_ALT: + { + Register reg = (op == OP_LOAD_PRI) ? pri : alt; + cell_t offset = readCell(); + __ movl(reg, Operand(dat, offset)); + break; + } + + case OP_LOAD_BOTH: + { + cell_t offs1 = readCell(); + cell_t offs2 = readCell(); + __ movl(pri, Operand(dat, offs1)); + __ movl(alt, Operand(dat, offs2)); + break; + } + + case OP_LOAD_S_PRI: + case OP_LOAD_S_ALT: + { + Register reg = (op == OP_LOAD_S_PRI) ? pri : alt; + cell_t offset = readCell(); + __ movl(reg, Operand(frm, offset)); + break; + } + + case OP_LOAD_S_BOTH: + { + cell_t offs1 = readCell(); + cell_t offs2 = readCell(); + __ movl(pri, Operand(frm, offs1)); + __ movl(alt, Operand(frm, offs2)); + break; + } + + case OP_LREF_S_PRI: + case OP_LREF_S_ALT: + { + Register reg = (op == OP_LREF_S_PRI) ? pri : alt; + cell_t offset = readCell(); + __ movl(reg, Operand(frm, offset)); + __ movl(reg, Operand(dat, reg, NoScale)); + break; + } + + case OP_CONST_PRI: + case OP_CONST_ALT: + { + Register reg = (op == OP_CONST_PRI) ? pri : alt; + cell_t val = readCell(); + __ movl(reg, val); + break; + } + + case OP_ADDR_PRI: + case OP_ADDR_ALT: + { + Register reg = (op == OP_ADDR_PRI) ? pri : alt; + cell_t offset = readCell(); + __ movl(reg, Operand(info, AMX_INFO_FRAME)); + __ addl(reg, offset); + break; + } + + case OP_STOR_PRI: + case OP_STOR_ALT: + { + Register reg = (op == OP_STOR_PRI) ? pri : alt; + cell_t offset = readCell(); + __ movl(Operand(dat, offset), reg); + break; + } + + case OP_STOR_S_PRI: + case OP_STOR_S_ALT: + { + Register reg = (op == OP_STOR_S_PRI) ? pri : alt; + cell_t offset = readCell(); + __ movl(Operand(frm, offset), reg); + break; + } + + case OP_IDXADDR: + __ lea(pri, Operand(alt, pri, ScaleFour)); + break; + + case OP_SREF_S_PRI: + case OP_SREF_S_ALT: + { + Register reg = (op == OP_SREF_S_PRI) ? pri : alt; + cell_t offset = readCell(); + __ movl(tmp, Operand(frm, offset)); + __ movl(Operand(dat, tmp, NoScale), reg); + break; + } + + case OP_POP_PRI: + case OP_POP_ALT: + { + Register reg = (op == OP_POP_PRI) ? pri : alt; + __ movl(reg, Operand(stk, 0)); + __ addl(stk, 4); + break; + } + + case OP_SWAP_PRI: + case OP_SWAP_ALT: + { + Register reg = (op == OP_SWAP_PRI) ? pri : alt; + __ movl(tmp, Operand(stk, 0)); + __ movl(Operand(stk, 0), reg); + __ movl(reg, tmp); + break; + } + + case OP_LIDX: + __ lea(pri, Operand(alt, pri, ScaleFour)); + __ movl(pri, Operand(dat, pri, NoScale)); + break; + + case OP_LIDX_B: + { + cell_t val = readCell(); + if (val >= 0 && val <= 3) { + __ lea(pri, Operand(alt, pri, Scale(val))); + } else { + __ shll(pri, val); + __ addl(pri, alt); + } + emitCheckAddress(pri); + __ movl(pri, Operand(dat, pri, NoScale)); + break; + } + + case OP_CONST: + case OP_CONST_S: + { + Register base = (op == OP_CONST) ? dat : frm; + cell_t offset = readCell(); + cell_t val = readCell(); + __ movl(Operand(base, offset), val); + break; + } + + case OP_LOAD_I: + emitCheckAddress(pri); + __ movl(pri, Operand(dat, pri, NoScale)); + break; + + case OP_STOR_I: + emitCheckAddress(alt); + __ movl(Operand(dat, alt, NoScale), pri); + break; + + case OP_SDIV: + case OP_SDIV_ALT: + { + Register dividend = (op == OP_SDIV) ? pri : alt; + Register divisor = (op == OP_SDIV) ? alt : pri; + + // Guard against divide-by-zero. + __ testl(divisor, divisor); + __ j(zero, &error_divide_by_zero_); + + // A more subtle case; -INT_MIN / -1 yields an overflow exception. + Label ok; + __ cmpl(divisor, -1); + __ j(not_equal, &ok); + __ cmpl(dividend, 0x80000000); + __ j(equal, &error_integer_overflow_); + __ bind(&ok); + + // Now we can actually perform the divide. + __ movl(tmp, divisor); + if (op == OP_SDIV) + __ movl(edx, dividend); + else + __ movl(eax, dividend); + __ sarl(edx, 31); + __ idivl(tmp); + break; + } + + case OP_LODB_I: + { + cell_t val = readCell(); + emitCheckAddress(pri); + __ movl(pri, Operand(dat, pri, NoScale)); + if (val == 1) + __ andl(pri, 0xff); + else if (val == 2) + __ andl(pri, 0xffff); + break; + } + + case OP_STRB_I: + { + cell_t val = readCell(); + emitCheckAddress(alt); + if (val == 1) + __ movb(Operand(dat, alt, NoScale), pri); + else if (val == 2) + __ movw(Operand(dat, alt, NoScale), pri); + else if (val == 4) + __ movl(Operand(dat, alt, NoScale), pri); + break; + } + + case OP_RETN: + { + // Restore the old frame pointer. + __ movl(frm, Operand(stk, 4)); // get the old frm + __ addl(stk, 8); // pop stack + __ movl(Operand(info, AMX_INFO_FRAME), frm); // store back old frm + __ addl(frm, dat); // relocate + + // Remove parameters. + __ movl(tmp, Operand(stk, 0)); + __ lea(stk, Operand(stk, tmp, ScaleFour, 4)); + __ ret(); + break; + } + + case OP_MOVS: + { + cell_t val = readCell(); + unsigned dwords = val / 4; + unsigned bytes = val % 4; + + __ cld(); + __ push(esi); + __ push(edi); + __ lea(esi, Operand(dat, pri, NoScale)); + __ lea(edi, Operand(dat, alt, NoScale)); + if (dwords) { + __ movl(ecx, dwords); + __ rep_movsd(); + } + if (bytes) { + __ movl(ecx, bytes); + __ rep_movsb(); + } + __ pop(edi); + __ pop(esi); + break; + } + + case OP_FILL: + { + // eax/pri is used implicitly. + unsigned dwords = readCell() / 4; + __ push(edi); + __ lea(edi, Operand(dat, alt, NoScale)); + __ movl(ecx, dwords); + __ cld(); + __ rep_stosd(); + __ pop(edi); + break; + } + + case OP_STRADJUST_PRI: + __ addl(pri, 4); + __ sarl(pri, 2); + break; + + case OP_FABS: + __ movl(pri, Operand(stk, 0)); + __ andl(pri, 0x7fffffff); + __ addl(stk, 4); + break; + + case OP_FLOAT: + __ fild32(Operand(edi, 0)); + __ subl(esp, 4); + __ fstp32(Operand(esp, 0)); + __ pop(pri); + __ addl(stk, 4); + break; + + case OP_FLOATADD: + case OP_FLOATSUB: + case OP_FLOATMUL: + case OP_FLOATDIV: + __ subl(esp, 4); + __ fld32(Operand(edi, 0)); + + if (op == OP_FLOATADD) + __ fadd32(Operand(edi, 4)); + else if (op == OP_FLOATSUB) + __ fsub32(Operand(edi, 4)); + else if (op == OP_FLOATMUL) + __ fmul32(Operand(edi, 4)); + else if (op == OP_FLOATDIV) + __ fdiv32(Operand(edi, 4)); + + __ fstp32(Operand(esp, 0)); + __ pop(pri); + __ addl(stk, 8); + break; + + case OP_RND_TO_NEAREST: + { + static float kRoundToNearest = 0.5f; + // From http://wurstcaptures.untergrund.net/assembler_tricks.html#fastfloorf + __ fld32(Operand(edi, 0)); + __ fadd32(st0, st0); + __ fadd32(Operand(ExternalAddress(&kRoundToNearest))); + __ subl(esp, 4); + __ fistp32(Operand(esp, 0)); + __ pop(pri); + __ sarl(pri, 1); + __ addl(stk, 4); + break; + } + + case OP_RND_TO_CEIL: + { + static float kRoundToCeil = -0.5f; + // From http://wurstcaptures.untergrund.net/assembler_tricks.html#fastfloorf + __ fld32(Operand(edi, 0)); + __ fadd32(st0, st0); + __ fsubr32(Operand(ExternalAddress(&kRoundToCeil))); + __ subl(esp, 4); + __ fistp32(Operand(esp, 0)); + __ pop(pri); + __ sarl(pri, 1); + __ negl(pri); + __ addl(stk, 4); + break; + } + + case OP_RND_TO_ZERO: + __ fld32(Operand(edi, 0)); + __ subl(esp, 8); + __ fstcw(Operand(esp, 4)); + __ movl(Operand(esp, 0), 0xfff); + __ fldcw(Operand(esp, 0)); + __ fistp32(Operand(esp, 0)); + __ pop(pri); + __ fldcw(Operand(esp, 0)); + __ addl(esp, 4); + __ addl(stk, 4); + break; + + case OP_RND_TO_FLOOR: + __ fld32(Operand(stk, 0)); + __ subl(esp, 8); + __ fstcw(Operand(esp, 4)); + __ movl(Operand(esp, 0), 0x7ff); + __ fldcw(Operand(esp, 0)); + __ fistp32(Operand(esp, 0)); + __ pop(eax); + __ fldcw(Operand(esp, 0)); + __ addl(esp, 4); + __ addl(stk, 4); + break; + + case OP_FLOATCMP: + { + Label bl, ab, done; + __ fld32(Operand(edi, 0)); + __ fld32(Operand(edi, 4)); + __ fucomip(st1); + __ fstp(st0); + __ j(above, &ab); + __ j(below, &bl); + __ xorl(pri, pri); + __ jmp(&done); + __ bind(&ab); + __ movl(pri, -1); + __ jmp(&done); + __ bind(&bl); + __ movl(pri, 1); + __ bind(&done); + __ addl(stk, 8); + break; + } + + case OP_STACK: + { + cell_t amount = readCell(); + __ addl(stk, amount); + + if (amount > 0) { + // Check if the stack went beyond the stack top - usually a compiler error. + __ cmpl(stk, Operand(info, AMX_INFO_STACKTOP)); + __ j(not_below, &error_stack_min_); + } else { + // Check if the stack is going to collide with the heap. + __ movl(tmp, Operand(info, AMX_INFO_HEAP)); + __ lea(tmp, Operand(dat, ecx, NoScale, STACK_MARGIN)); + __ cmpl(stk, tmp); + __ j(below, &error_stack_low_); + } + break; + } + + case OP_HEAP: + { + cell_t amount = readCell(); + __ movl(alt, Operand(info, AMX_INFO_HEAP)); + __ addl(Operand(info, AMX_INFO_HEAP), amount); + + if (amount > 0) { + __ cmpl(Operand(info, AMX_INFO_HEAP), plugin_->data_size); + __ j(below, &error_heap_min_); + } else { + __ movl(tmp, Operand(info, AMX_INFO_HEAP)); + __ lea(tmp, Operand(dat, ecx, NoScale, STACK_MARGIN)); + __ cmpl(tmp, stk); + __ j(above, &error_heap_low_); + } + break; + } + + case OP_JUMP: + { + Label *target = labelAt(readCell()); + if (!target) + return false; + __ jmp(target); + break; + } + + case OP_JZER: + case OP_JNZ: + { + ConditionCode cc = (op == OP_JZER) ? zero : not_zero; + Label *target = labelAt(readCell()); + if (!target) + return false; + __ testl(pri, pri); + __ j(cc, target); + break; + } + + case OP_JEQ: + case OP_JNEQ: + case OP_JSLESS: + case OP_JSLEQ: + case OP_JSGRTR: + case OP_JSGEQ: + { + Label *target = labelAt(readCell()); + if (!target) + return false; + ConditionCode cc = OpToCondition(op); + __ cmpl(pri, alt); + __ j(cc, target); + break; + } + + case OP_TRACKER_PUSH_C: + { + cell_t amount = readCell(); + + // Save registers. + __ push(pri); + __ push(alt); + + // call JIT_VerifyorAllocateTracker + __ movl(eax, Operand(info, AMX_INFO_CONTEXT)); + __ push(eax); + __ call(ExternalAddress((void *)JIT_VerifyOrAllocateTracker)); + __ testl(eax, eax); + __ j(not_zero, &extern_error_); + __ pop(eax); + + // Push the value onto the stack and increment pCur. + __ movl(edx, Operand(eax, offsetof(sp_context_t, vm[JITVARS_TRACKER]))); + __ movl(ecx, Operand(edx, offsetof(tracker_t, pCur))); + __ addl(Operand(edx, offsetof(tracker_t, pCur)), 4); + __ movl(Operand(ecx, 0), amount * 4); + + __ pop(alt); + __ pop(pri); + break; + } + + case OP_TRACKER_POP_SETHEAP: + { + // Save registers. + __ push(pri); + __ push(alt); + + // Get the context pointer and call the sanity checker. + __ movl(eax, Operand(info, AMX_INFO_CONTEXT)); + __ push(eax); + __ call(ExternalAddress((void *)JIT_VerifyLowBoundTracker)); + __ testl(eax, eax); + __ j(not_zero, &extern_error_); + __ pop(eax); + + // Pop the value from the tracker stack and decrease the heap by it. + __ movl(edx, Operand(eax, offsetof(sp_context_t, vm[JITVARS_TRACKER]))); + __ movl(ecx, Operand(edx, offsetof(tracker_t, pCur))); + __ subl(ecx, 4); + __ movl(Operand(edx, offsetof(tracker_t, pCur)), eax); + __ movl(ecx, Operand(ecx, 0)); + __ subl(Operand(info, AMX_INFO_HEAP), ecx); + + // Check that we didn't underflow the heap. + __ cmpl(Operand(info, AMX_INFO_HEAP), plugin_->data_size); + __ j(below, &error_heap_min_); + + __ pop(alt); + __ pop(pri); + break; + } + + case OP_BREAK: + { + cell_t cip = uintptr_t(cip_ - 1) - uintptr_t(plugin_->pcode); + __ movl(Operand(info, AMX_INFO_CIP), cip); + break; + } + + case OP_HALT: + __ align(16); + __ movl(tmp, Operand(info, AMX_INFO_RETVAL)); + __ movl(Operand(ecx, 0), pri); + __ movl(pri, readCell()); + __ jmp(&extern_error_); + break; + + case OP_BOUNDS: + { + cell_t value = readCell(); + __ cmpl(eax, value); + __ j(above, &error_bounds_); + break; + } + + case OP_GENARRAY: + case OP_GENARRAY_Z: + emitGenArray(op == OP_GENARRAY_Z); + break; + + case OP_CALL: + if (!emitCall()) + return false; + break; + + case OP_SYSREQ_C: + case OP_SYSREQ_N: + if (!emitNativeCall(op)) + return false; + break; + + case OP_SWITCH: + if (!emitSwitch()) + return false; + break; + + case OP_CASETBL: + { + size_t ncases = readCell(); + + // Two cells per case, and one extra cell for the default address. + cip_ += (ncases * 2) + 1; + break; + } + + case OP_NOP: + break; + + default: + error_ = SP_ERROR_INVALID_INSTRUCTION; + return false; + } + + return true; +} + +Label * +Compiler::labelAt(size_t offset) +{ + if (offset % 4 != 0 || + offset > plugin_->pcode_size || + offset <= pcode_start_) + { + // If the jump target is misaligned, or out of pcode bounds, or is an + // address out of the function bounds, we abort. Unfortunately we can't + // test beyond the end of the function since we don't have a precursor + // pass (yet). + error_ = SP_ERROR_INSTRUCTION_PARAM; + return NULL; + } + + return &jump_map_[offset / sizeof(cell_t)]; +} + +static void +EmitTrackerPushReg(AssemblerX86 &masm, Register reg, Label *error) +{ + __ push(eax); + if (reg == ecx) + __ push(ecx); + __ push(edi); + __ movl(edi, reg); + __ shll(edi, 2); // Count in bytes, not cells. + + // Get the context pointer, push it and call the check. + __ movl(eax, Operand(info, AMX_INFO_CONTEXT)); + __ push(eax); + __ call(ExternalAddress((void *)JIT_VerifyOrAllocateTracker)); + + // Check for errors. + __ testl(eax, eax); + __ j(not_zero, error); + + __ pop(eax); + + // Push the register into the stack and increment pCur. + __ movl(edx, Operand(eax, offsetof(sp_context_t, vm[JITVARS_TRACKER]))); + __ movl(eax, Operand(edx, offsetof(tracker_t, pCur))); + __ addl(Operand(edx, offsetof(tracker_t, pCur)), 4); + __ movl(Operand(eax, 0), edi); + + // Restore pri, alt, stk. + __ pop(edi); + if (reg == ecx) + __ pop(ecx); + __ pop(eax); +} + +void +Compiler::emitCheckAddress(Register reg) +{ + // Check if we're in memory bounds. + __ cmpl(reg, plugin_->mem_size); + __ j(not_below, &error_memaccess_); + + // Check if we're in the invalid region between hp and sp. + Label done; + __ cmpl(reg, Operand(info, AMX_INFO_HEAP)); + __ j(below, &done); + __ lea(tmp, Operand(dat, reg, NoScale)); + __ cmpl(tmp, stk); + __ j(below, &error_memaccess_); + __ bind(&done); +} + +void +Compiler::emitGenArray(bool autozero) +{ + cell_t val = readCell(); + if (val == 1) + { + // flat array; we can generate this without indirection tables. + // Note that we can overwrite ALT because technically STACK should be destroying ALT + __ movl(alt, Operand(info, AMX_INFO_HEAP)); + __ movl(tmp, Operand(stk, 0)); + __ movl(Operand(stk, 0), alt); // store base of the array into the stack. + __ lea(alt, Operand(alt, tmp, ScaleFour)); + __ movl(Operand(info, AMX_INFO_HEAP), alt); + __ addl(alt, dat); + __ cmpl(alt, stk); + __ j(not_below, &error_heap_low_); + + EmitTrackerPushReg(masm, ecx, &extern_error_); + + if (autozero) { + __ push(eax); + __ push(edi); + __ xorl(eax, eax); + __ movl(edi, Operand(stk, 0)); + __ addl(edi, dat); + __ cld(); + __ rep_stosd(); + __ pop(edi); + __ pop(eax); + } + } else { + __ movl(tmp, val); + __ movl(edx, autozero ? 1 : 0); + __ call(g_Jit.GetGenArrayIntrinsic()); + } +} + +bool +Compiler::emitCall() +{ + cell_t offset = readCell(); + + // If this offset looks crappy, i.e. not aligned or out of bounds, we just + // abort. + if (offset % 4 != 0 || uint32_t(offset) >= plugin_->pcode_size) { + error_ = SP_ERROR_INSTRUCTION_PARAM; + return false; + } + + // eax = context + // ecx = rp + __ movl(eax, Operand(info, AMX_INFO_CONTEXT)); + __ movl(ecx, Operand(eax, offsetof(sp_context_t, rp))); + + // Check if the return stack is used up. + __ cmpl(ecx, SP_MAX_RETURN_STACK); + __ j(not_below, &error_stack_low_); + + // Add to the return stack. + uintptr_t cip = uintptr_t(cip_ - 2) - uintptr_t(plugin_->pcode); + __ movl(Operand(eax, ecx, ScaleFour, offsetof(sp_context_t, rstk_cips)), cip); + + // Increment the return stack pointer. + __ addl(Operand(eax, offsetof(sp_context_t, rp)), 1); + + // Store the CIP of the function we're about to call. + __ movl(Operand(info, AMX_INFO_CIP), offset); + + JitFunction *fun = rt_->GetJittedFunctionByOffset(offset); + if (!fun) { + // Need to emit a delayed thunk. + CallThunk *thunk = new CallThunk(offset); + __ call(&thunk->call); + if (!thunks_.append(thunk)) + return false; + } else { + // Function is already emitted, we can do a direct call. + __ call(ExternalAddress(fun->GetEntryAddress())); + } + + // Restore the last cip. + __ movl(Operand(info, AMX_INFO_CIP), cip); + + // Mark us as leaving the last frame. + __ movl(tmp, Operand(info, AMX_INFO_CONTEXT)); + __ subl(Operand(tmp, offsetof(sp_context_t, rp)), 1); + return true; +} + +void +Compiler::emitCallThunks() +{ + for (size_t i = 0; i < thunks_.length(); i++) { + CallThunk *thunk = thunks_[i]; + + Label error; + __ bind(&thunk->call); + // Huge hack - get the return address, since that is the call that we + // need to patch. + __ movl(eax, Operand(esp, 0)); + + // Align the stack. Unfortunately this is a pretty careful dance based + // on the number of words we push (4 args, 1 saved esp), and someday + // we should look into automating this. + __ movl(edx, esp); + __ andl(esp, 0xfffffff0); + __ subl(esp, 12); + __ push(edx); + + // Push arguments. + __ push(eax); + __ subl(esp, 4); + __ movl(Operand(esp, 0), esp); + __ push(thunk->pcode_offset); + __ push(intptr_t(rt_)); + __ call(ExternalAddress((void *)CompileFromThunk)); + __ movl(edx, Operand(esp, 8)); + __ movl(esp, Operand(esp, 16)); + __ testl(eax, eax); + __ j(not_zero, &error); + __ call(edx); + __ ret(); + + __ bind(&error); + __ movl(Operand(info, AMX_INFO_CIP), thunk->pcode_offset); + __ jmp(g_Jit.GetUniversalReturn()); + } +} + +cell_t +Compiler::readCell() +{ + if (cip_ >= code_end_) { + error_= SP_ERROR_INVALID_INSTRUCTION; + return 0; + } + return *cip_++; +} + +bool +Compiler::emitNativeCall(OPCODE op) +{ + uint32_t native_index = readCell(); + + if (native_index >= plugin_->num_natives) { + error_ = SP_ERROR_INSTRUCTION_PARAM; + return false; + } + + uint32_t num_params; + if (op == OP_SYSREQ_N) { + num_params = readCell(); + + // See if we can get a replacement opcode. If we can, then recursively + // call emitOp() to generate it. Note: it's important that we do this + // before generating any code for the SYSREQ.N. + unsigned replacement = rt_->GetNativeReplacement(native_index); + if (replacement != OP_NOP) + return emitOp((OPCODE)replacement); + + // Store the number of parameters. + __ movl(Operand(stk, -4), num_params); + __ subl(stk, 4); + } + + // Save registers. + __ push(edx); + + // Align the stack to 16 bytes. + __ push(ebx); + __ movl(ebx, esp); + __ andl(esp, 0xfffffff0); + __ subl(esp, 4); + + // Push the parameters for the C++ function. + __ push(stk); + __ push(native_index); + + // Relocate all our absolute junk to be dat-relative, and store it all back + // into the context. + __ movl(eax, Operand(info, AMX_INFO_CONTEXT)); + __ movl(ecx, Operand(info, AMX_INFO_HEAP)); + __ movl(Operand(eax, offsetof(sp_context_t, hp)), ecx); + __ subl(stk, dat); + __ movl(Operand(eax, offsetof(sp_context_t, sp)), stk); + __ movl(ecx, Operand(info, AMX_INFO_FRAME)); + __ movl(Operand(eax, offsetof(sp_context_t, frm)), ecx); + + // Push context and make the call. + __ push(eax); + __ call(ExternalAddress((void *)NativeCallback)); + + // Check for errors. + __ movl(ecx, Operand(info, AMX_INFO_CONTEXT)); + __ movl(ecx, Operand(ecx, offsetof(sp_context_t, n_err))); + __ testl(ecx, ecx); + __ j(not_zero, &extern_error_); + + // Restore local state. + __ movl(esp, ebx); + __ pop(ebx); + __ addl(stk, dat); + __ pop(edx); + + if (op == OP_SYSREQ_N) { + // Pop the stack. Do not check the margins. + __ addl(stk, (num_params + 1) * sizeof(cell_t)); + } + return true; +} + +bool +Compiler::emitSwitch() +{ + cell_t offset = readCell(); + if (!labelAt(offset)) + return false; + + cell_t *tbl = (cell_t *)((char *)plugin_->pcode + offset + sizeof(cell_t)); + + struct Entry { + cell_t val; + cell_t offset; + }; + + size_t ncases = *tbl++; + + Label *defaultCase = labelAt(*tbl); + if (!defaultCase) + return false; + + // Degenerate - 0 cases. + if (!ncases) { + __ jmp(defaultCase); + return true; + } + + Entry *cases = (Entry *)(tbl + 1); + + // Degenerate - 1 case. + if (ncases == 1) { + Label *maybe = labelAt(cases[0].offset); + if (!maybe) + return false; + __ cmpl(pri, cases[0].val); + __ j(equal, maybe); + __ jmp(defaultCase); + return true; + } + + // We have two or more cases, so let's generate a full switch. Decide + // whether we'll make an if chain, or a jump table, based on whether + // the numbers are strictly sequential. + bool sequential = true; + { + cell_t first = cases[0].val; + cell_t last = first; + for (size_t i = 1; i < ncases; i++) { + if (cases[i].val != ++last) { + sequential = false; + break; + } + } + } + + // First check whether the bounds are correct: if (a < LOW || a > HIGH); + // this check is valid whether or not we emit a sequential-optimized switch. + cell_t low = cases[0].val; + if (low != 0) { + // negate it so we'll get a lower bound of 0. + low = -low; + __ lea(tmp, Operand(pri, low)); + } else { + __ movl(tmp, pri); + } + + cell_t high = abs(cases[0].val - cases[ncases - 1].val); + __ cmpl(tmp, high); + __ j(above, defaultCase); + + if (sequential) { + // Optimized table version. The tomfoolery below is because we only have + // one free register... it seems unlikely pri or alt will be used given + // that we're at the end of a control-flow point, but we'll play it safe. + DataLabel table; + __ push(eax); + __ movl(eax, &table); + __ movl(ecx, Operand(eax, ecx, ScaleFour)); + __ pop(eax); + __ jmp(ecx); + + __ bind(&table); + for (size_t i = 0; i < ncases; i++) { + Label *label = labelAt(cases[i].offset); + if (!label) + return false; + __ emit_absolute_address(label); + } + } else { + // Slower version. Go through each case and generate a check. + for (size_t i = 0; i < ncases; i++) { + Label *label = labelAt(cases[i].offset); + if (!label) + return false; + __ cmpl(pri, cases[i].val); + __ j(equal, label); + } + __ jmp(defaultCase); + } + return true; +} + +void +Compiler::emitErrorPath(Label *dest, int code) +{ + if (dest->used()) { + __ bind(dest); + __ movl(eax, code); + __ jmp(g_Jit.GetUniversalReturn()); + } +} + +void +Compiler::emitErrorPaths() +{ + emitErrorPath(&error_divide_by_zero_, SP_ERROR_DIVIDE_BY_ZERO); + emitErrorPath(&error_stack_low_, SP_ERROR_STACKLOW); + emitErrorPath(&error_stack_min_, SP_ERROR_STACKMIN); + emitErrorPath(&error_bounds_, SP_ERROR_ARRAY_BOUNDS); + emitErrorPath(&error_memaccess_, SP_ERROR_MEMACCESS); + emitErrorPath(&error_heap_low_, SP_ERROR_HEAPLOW); + emitErrorPath(&error_heap_min_, SP_ERROR_HEAPMIN); + emitErrorPath(&error_integer_overflow_, SP_ERROR_INTEGER_OVERFLOW); + + if (extern_error_.used()) { + __ bind(&extern_error_); + __ movl(eax, Operand(info, AMX_INFO_CONTEXT)); + __ movl(eax, Operand(eax, offsetof(sp_context_t, n_err))); + __ jmp(g_Jit.GetUniversalReturn()); + } +} + +// Input dimension count is in ecx. +static void * +GenerateGenArrayIntrinsic(void *ret) +{ + AssemblerX86 masm; + + __ push(ebx); + __ push(eax); + __ push(edx); + __ push(ecx); // We reference this in the body of this routine. + + Label toobig; + + // Calculate how many cells will be needed. + __ movl(edx, Operand(stk, 0)); // Dimension's last count. + __ cmpl(edx, 0); + __ j(less, &toobig); + __ movl(eax, 1); // Position at second to last dimension. + + Label loop, done; + __ bind(&loop); + __ cmpl(eax, Operand(esp, 0)); // Compare to # of dimensions. + __ j(not_below, &done); // End loop if done. + __ movl(ecx, Operand(stk, eax, ScaleFour)); // Get dimension size. + __ cmpl(ecx, 0); + __ j(less, &toobig); + __ imull(edx, ecx); // Multiply by size. + __ j(overflow, &toobig); + __ addl(eax, 1); // Increment dimension cursor. + __ addl(edx, ecx); // Add indirection vector size. + __ j(overflow, &toobig); + __ jmp(&loop); + __ bind(&done); + + // Test if we have space for the size in edx. + __ movl(eax, Operand(info, AMX_INFO_HEAP)); + __ imull(edx, edx, 4); + __ j(overflow, &toobig); + __ addl(eax, edx); + __ j(overflow, &toobig); + __ cmpl(eax, Operand(info, AMX_INFO_DATASIZE)); + __ j(not_above, &toobig); + __ addl(eax, dat); + __ cmpl(eax, stk); + __ j(not_below, &toobig); + __ shrl(edx, 2); // Undo the imull. + + // Allocate on the plugin heap. + __ movl(eax, Operand(info, AMX_INFO_HEAP)); // Get heap pointer. + __ lea(ebx, Operand(eax, edx, ScaleFour)); // New heap pointer. + __ movl(Operand(info, AMX_INFO_HEAP), ebx); // Store back. + __ push(eax); // Save on the stack. + + Label extern_error; + EmitTrackerPushReg(masm, edx, &extern_error); + + // Call to C++ to generate indirection vectors. + __ lea(ebx, Operand(dat, eax, NoScale)); // relocate eax + __ push(Operand(esp, 8)); // push autozero + __ push(Operand(esp, 8)); // push dimension count + __ push(stk); // push dimension array + __ push(ebx); + __ call(ExternalAddress((void *)GenerateArrayIndirectionVectors)); + __ addl(esp, 4 * sizeof(void *)); + + __ pop(eax); // Restore array pointer. + __ pop(ecx); // Restore dimension count. + __ lea(stk, Operand(stk, ecx, ScaleFour, -4)); // Pop params off the stack. + __ movl(Operand(stk, 0), eax); // Store back array pointer. + __ pop(edx); + __ pop(eax); + __ pop(ebx); + __ ret(); + + __ bind(&toobig); + __ movl(eax, SP_ERROR_ARRAY_TOO_BIG); + __ jmp(ExternalAddress(ret)); + + __ bind(&extern_error); + __ jmp(ExternalAddress(ret)); + + return LinkCode(masm); +} + +static void * +GenerateEntry(void **retp) +{ + AssemblerX86 masm; + + // Variables we're passed in: + // void *vars[], void *entry + + __ push(ebp); + __ movl(ebp, esp); + + __ push(esi); + __ push(edi); + __ push(ebx); + + __ movl(esi, Operand(ebp, 8 + 4 * 0)); + __ movl(ecx, Operand(ebp, 8 + 4 * 1)); + __ movl(eax, Operand(esi, AMX_INFO_MEMORY)); + __ movl(edx, Operand(esi, AMX_INFO_CONTEXT)); + + // Set up run-time registers. + __ movl(edi, Operand(edx, offsetof(sp_context_t, sp))); + __ addl(edi, eax); + __ movl(ebp, eax); + __ movl(ebx, edi); + __ movl(Operand(esi, AMX_INFO_NSTACK), esp); + + // Call into plugin. + __ call(ecx); + + __ movl(ecx, Operand(info, AMX_INFO_RETVAL)); + __ movl(Operand(ecx, 0), pri); + __ movl(eax, SP_ERROR_NONE); + + // If stuff goes wrong, it'll jump directly to here. + Label error; + __ bind(&error); + __ movl(esp, Operand(info, AMX_INFO_NSTACK)); + __ movl(ecx, Operand(info, AMX_INFO_CONTEXT)); + __ subl(stk, dat); + __ movl(Operand(ecx, offsetof(sp_context_t, sp)), stk); + + __ pop(ebx); + __ pop(edi); + __ pop(esi); + __ pop(ebp); + __ ret(); + + void *code = LinkCode(masm); + if (!code) + return NULL; + + *retp = reinterpret_cast(code) + error.offset(); + return code; } ICompilation *JITX86::ApplyOptions(ICompilation *_IN, ICompilation *_OUT) { - if (_IN == NULL) - { - return _OUT; - } + if (_IN == NULL) + return _OUT; - CompData *_in = (CompData * )_IN; - CompData *_out = (CompData * )_OUT; + CompData *_in = (CompData * )_IN; + CompData *_out = (CompData * )_OUT; - _in->inline_level = _out->inline_level; - _in->profile = _out->profile; + _in->inline_level = _out->inline_level; + _in->profile = _out->profile; - _out->Abort(); - - return _in; + _out->Abort(); + return _in; } JITX86::JITX86() { - m_pJitEntry = NULL; - m_pJitReturn = NULL; - m_RoundTable[0] = -1; - m_RoundTable[1] = 0; - m_RoundTable[2] = 1; - m_pJitGenArray = NULL; + m_pJitEntry = NULL; + m_pJitGenArray = NULL; } bool JITX86::InitializeJIT() { - jitoffs_t offs; - JitWriter writer, *jit; + g_pCodeCache = KE_CreateCodeCache(); - g_pCodeCache = KE_CreateCodeCache(); + m_pJitEntry = GenerateEntry(&m_pJitReturn); + if (!m_pJitEntry) + return false; - jit = &writer; - - /* Build the entry point */ - jit->outbase = NULL; - jit->outptr = NULL; - Write_Execute_Function(jit); - m_pJitEntry = Knight::KE_AllocCode(g_pCodeCache, jit->get_outputpos()); - jit->outbase = (jitcode_t)m_pJitEntry; - jit->outptr = jit->outbase; - offs = Write_Execute_Function(jit); - m_pJitReturn = (uint8_t *)m_pJitEntry + offs; + m_pJitGenArray = GenerateGenArrayIntrinsic(m_pJitReturn); + if (!m_pJitGenArray) + return false; - /* Build the genarray intrinsic */ - writer = JitWriter(); - jit->outbase = NULL; - jit->outptr = NULL; - WriteIntrinsic_GenArray(jit); - m_pJitGenArray = Knight::KE_AllocCode(g_pCodeCache, jit->get_outputpos()); - jit->outbase = (jitcode_t)m_pJitGenArray; - jit->outptr = jit->outbase; - WriteIntrinsic_GenArray(jit); - - return true; + return true; } -void JITX86::ShutdownJIT() +void +JITX86::ShutdownJIT() { - KE_DestroyCodeCache(g_pCodeCache); + KE_DestroyCodeCache(g_pCodeCache); } -JitFunction *JITX86::CompileFunction(BaseRuntime *prt, cell_t pcode_offs, int *err) +JitFunction * +JITX86::CompileFunction(BaseRuntime *prt, cell_t pcode_offs, int *err) { - CompData *data = (CompData *)prt->m_pCo; - sp_plugin_t *plugin = data->plugin; - - uint8_t *code = plugin->pcode + pcode_offs; - uint8_t *end_code = plugin->pcode + plugin->pcode_size; - - assert(FuncLookup(data, pcode_offs) == 0); - - if (code >= end_code || *(cell_t *)code != OP_PROC) - { - *err = SP_ERROR_INVALID_INSTRUCTION; - return NULL; - } - -#if defined _DEBUG - g_engine1.GetDebugHook()->OnDebugSpew("Compiling function %s::%s", prt->m_pPlugin->name, find_func_name(prt->m_pPlugin, pcode_offs)); -#endif - - code += sizeof(cell_t); - - OPCODE op; - uint32_t code_size; - cell_t *cip, *end_cip; - JitWriter writer, *jit; - - jit = &writer; - cip = (cell_t *)code; - end_cip = (cell_t *)end_code; - writer.data = data; - writer.inbase = cip; - writer.outptr = NULL; - writer.outbase = NULL; - data->cur_func = pcode_offs; - -jit_rewind: - data->num_thunks = 0; - writer.inptr = writer.inbase; - - WriteOp_Proc(jit); - - /* Actual code generation! */ - if (writer.outbase == NULL) - { - /* First Pass - find codesize and resolve relocation */ - jitoffs_t jpcode_offs; - jitoffs_t native_offs; - - for (; writer.inptr < end_cip;) - { - op = (OPCODE)writer.peek_cell(); - - /* If we hit another function, we must stop. */ - if (op == OP_PROC || op == OP_ENDPROC) - { - break; - } - - /* Store the native offset into the rebase memory. - * This large chunk of memory lets us do an instant lookup - * based on an original pcode offset. - */ - jpcode_offs = (jitoffs_t)((uint8_t *)writer.inptr - plugin->pcode); - native_offs = jit->get_outputpos(); - *((jitoffs_t *)(data->rebase + jpcode_offs)) = native_offs; - - /* Read past the opcode. */ - writer.read_cell(); - - /* Patch the floating point natives with our opcodes */ - if (op == OP_SYSREQ_N) - { - cell_t idx = writer.read_cell(); - if (data->jit_float_table[idx].found) - { - writer.inptr -= 2; - *(writer.inptr++) = data->jit_float_table[idx].index; - *(writer.inptr++) = OP_NOP; - *(writer.inptr++) = OP_NOP; - op = (OPCODE)data->jit_float_table[idx].index; - } - else - { - writer.inptr--; - } - } - switch (op) - { - #include "opcode_switch.inc" - } - /* Check for errors. This should only happen in the first pass. */ - if (data->error_set != SP_ERROR_NONE) - { - *err = data->error_set; - return NULL; - } - } - - /* Write these last because error jumps should be predicted forwardly (not taken) */ - WriteErrorRoutines(data, jit); - - AlignMe(jit); - data->jit_sysreq_c = jit->get_outputpos(); - WriteOp_Sysreq_C_Function(jit); - - /* Build thunk tables */ - if (data->num_thunks > data->max_thunks) - { - data->max_thunks = data->num_thunks; - data->thunks = (call_thunk_t *)realloc( - data->thunks, - data->max_thunks * sizeof(call_thunk_t)); - } - - /* Write the thunk offsets. - * :TODO: we can emit all but one call to Write_CallThunk(). - */ - for (unsigned int i = 0; i < data->num_thunks; i++) - { - data->thunks[i].thunk_addr = jit->get_outputpos(); - Write_CallThunk(jit, 0, 0); - } - - /** - * I don't understand the purpose of this code. - * Why do we want to know about the last opcode? - * It should already have gotten written. - */ - #if 0 - /* Write the final CIP to the last position in the reloc array */ - pcode_offs = (jitoffs_t)((uint8_t *)writer.inptr - code); - native_offs = jit->get_outputpos(); - *((jitoffs_t *)(data->rebase + pcode_offs)) = native_offs; - #endif - - /* the total codesize is now known! */ - code_size = writer.get_outputpos(); - writer.outbase = (jitcode_t)Knight::KE_AllocCode(g_pCodeCache, code_size); - writer.outptr = writer.outbase; - - /* go back for second pass */ - goto jit_rewind; - } - else - { - /******* - * SECOND PASS - write opcode info - *******/ - for (; writer.inptr < end_cip;) - { - op = (OPCODE)writer.read_cell(); - - /* If we hit another function, we must stop. */ - if (op == OP_PROC || op == OP_ENDPROC) - { - break; - } - - switch (op) - { - #include "opcode_switch.inc" - } - } - - /* Write these last because error jumps should be predicted as not taken (forward) */ - WriteErrorRoutines(data, jit); - - AlignMe(jit); - data->jit_sysreq_c = jit->get_outputpos(); - WriteOp_Sysreq_C_Function(jit); - - /* Write the thunk offsets. */ - for (unsigned int i = 0; i < data->num_thunks; i++) - { - Write_CallThunk(jit, data->thunks[i].patch_addr, data->thunks[i].pcode_offs); - } - } - - *err = SP_ERROR_NONE; - - JitFunction *fn; - uint32_t func_idx; - - fn = new JitFunction(writer.outbase, pcode_offs); - func_idx = prt->AddJittedFunction(fn); - *(cell_t *)(data->rebase + pcode_offs) = func_idx; - - return fn; + Compiler cc(prt, pcode_offs); + JitFunction *fun = cc.emit(err); + if (!fun) + return NULL; + prt->AddJittedFunction(fun); + return fun; } -void JITX86::SetupContextVars(BaseRuntime *runtime, BaseContext *pCtx, sp_context_t *ctx) +void +JITX86::SetupContextVars(BaseRuntime *runtime, BaseContext *pCtx, sp_context_t *ctx) { - tracker_t *trk = new tracker_t; + tracker_t *trk = new tracker_t; - ctx->vm[JITVARS_TRACKER] = trk; - ctx->vm[JITVARS_BASECTX] = pCtx; /* GetDefaultContext() is not constructed yet */ - ctx->vm[JITVARS_PROFILER] = g_engine2.GetProfiler(); - ctx->vm[JITVARS_PLUGIN] = runtime->m_pPlugin; + ctx->vm[JITVARS_TRACKER] = trk; + ctx->vm[JITVARS_BASECTX] = pCtx; /* GetDefaultContext() is not constructed yet */ + ctx->vm[JITVARS_PROFILER] = g_engine2.GetProfiler(); + ctx->vm[JITVARS_PLUGIN] = const_cast(runtime->plugin()); - trk->pBase = (ucell_t *)malloc(1024); - trk->pCur = trk->pBase; - trk->size = 1024 / sizeof(cell_t); + trk->pBase = (ucell_t *)malloc(1024); + trk->pCur = trk->pBase; + trk->size = 1024 / sizeof(cell_t); } -SPVM_NATIVE_FUNC JITX86::CreateFakeNative(SPVM_FAKENATIVE_FUNC callback, void *pData) +SPVM_NATIVE_FUNC +JITX86::CreateFakeNative(SPVM_FAKENATIVE_FUNC callback, void *pData) { - JitWriter jw; - JitWriter *jit = &jw; + AssemblerX86 masm; - jw.outbase = NULL; - jw.outptr = NULL; - jw.data = NULL; + __ push(ebx); + __ push(edi); + __ push(esi); + __ movl(edi, Operand(esp, 16)); // store ctx + __ movl(esi, Operand(esp, 20)); // store params + __ movl(ebx, esp); + __ andl(esp, 0xfffffff0); + __ subl(esp, 4); - /* First pass, calculate size */ -rewind: - /* Align the stack to 16 bytes */ - //push ebx - //push edi - //push esi - //mov edi, [esp+16] ;store ctx - //mov esi, [esp+20] ;store params - //mov ebx, esp - //and esp, 0xFFFFFF0 - //sub esp, 4 - IA32_Push_Reg(jit, REG_EBX); - IA32_Push_Reg(jit, REG_EDI); - IA32_Push_Reg(jit, REG_ESI); - IA32_Mov_Reg_Esp_Disp8(jit, REG_EDI, 16); - IA32_Mov_Reg_Esp_Disp8(jit, REG_ESI, 20); - 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(intptr_t(pData)); + __ push(esi); + __ push(edi); + __ call(ExternalAddress((void *)callback)); + __ movl(esp, ebx); + __ pop(esi); + __ pop(edi); + __ pop(ebx); + __ ret(); - //push pData ;push pData - //push esi ;push params - //push edi ;push ctx - //call [callback] ;invoke the meta-callback - //mov esp, ebx ;restore the stack - //pop esi ;restore esi - //pop edi ;restore edi - //pop ebx ;restore ebx - //ret ;return - IA32_Push_Imm32(jit, (jit_int32_t)pData); - IA32_Push_Reg(jit, REG_ESI); - IA32_Push_Reg(jit, REG_EDI); - uint32_t call = IA32_Call_Imm32(jit, 0); - IA32_Write_Jump32_Abs(jit, call, (void *)callback); - IA32_Mov_Reg_Rm(jit, REG_ESP, REG_EBX, MOD_REG); - IA32_Pop_Reg(jit, REG_ESI); - IA32_Pop_Reg(jit, REG_EDI); - IA32_Pop_Reg(jit, REG_EBX); - IA32_Return(jit); - - if (jw.outbase == NULL) - { - /* Second pass: Actually write */ - jw.outbase = (jitcode_t)KE_AllocCode(g_pCodeCache, jw.get_outputpos()); - if (!jw.outbase) - { - return NULL; - } - jw.outptr = jw.outbase; - - goto rewind; - } - - return (SPVM_NATIVE_FUNC)jw.outbase; + return (SPVM_NATIVE_FUNC)LinkCode(masm); } void JITX86::DestroyFakeNative(SPVM_NATIVE_FUNC func) { - KE_FreeCode(g_pCodeCache, (void *)func); + KE_FreeCode(g_pCodeCache, (void *)func); } ICompilation *JITX86::StartCompilation() { - CompData *data = new CompData; - - data->jit_float_table = NULL; - - return data; -} - -void CompData::SetRuntime(BaseRuntime *runtime) -{ - plugin = runtime->m_pPlugin; - - uint32_t max_natives = plugin->num_natives; - - this->runtime = runtime; - this->plugin = runtime->m_pPlugin; - - inline_level = JIT_INLINE_ERRORCHECKS|JIT_INLINE_NATIVES; - error_set = SP_ERROR_NONE; - - jit_float_table = new floattbl_t[max_natives]; - for (uint32_t i=0; inatives[i].name; - if (!strcmp(name, "FloatAbs")) - { - jit_float_table[i].found = true; - jit_float_table[i].index = OP_FABS; - } - else if (!strcmp(name, "FloatAdd")) - { - jit_float_table[i].found = true; - jit_float_table[i].index = OP_FLOATADD; - } - else if (!strcmp(name, "FloatSub")) - { - jit_float_table[i].found = true; - jit_float_table[i].index = OP_FLOATSUB; - } - else if (!strcmp(name, "FloatMul")) - { - jit_float_table[i].found = true; - jit_float_table[i].index = OP_FLOATMUL; - } - else if (!strcmp(name, "FloatDiv")) - { - jit_float_table[i].found = true; - jit_float_table[i].index = OP_FLOATDIV; - } - else if (!strcmp(name, "float")) - { - jit_float_table[i].found = true; - jit_float_table[i].index = OP_FLOAT; - } - else if (!strcmp(name, "FloatCompare")) - { - jit_float_table[i].found = true; - jit_float_table[i].index = OP_FLOATCMP; - } - else if (!strcmp(name, "RoundToZero")) - { - jit_float_table[i].found = true; - jit_float_table[i].index = OP_RND_TO_ZERO; - } - else if (!strcmp(name, "RoundToCeil")) - { - jit_float_table[i].found = true; - jit_float_table[i].index = OP_RND_TO_CEIL; - } - else if (!strcmp(name, "RoundToFloor")) - { - jit_float_table[i].found = true; - jit_float_table[i].index = OP_RND_TO_FLOOR; - } - else if (!strcmp(name, "RoundToNearest")) - { - jit_float_table[i].found = true; - jit_float_table[i].index = OP_RND_TO_NEAREST; - } - } - - /* We need a relocation table. This is the relocation table we'll use for jumps - * and calls alike. One extra cell for final CIP. - */ - this->rebase = (uint8_t *)engine->BaseAlloc(plugin->pcode_size + sizeof(cell_t)); - memset(this->rebase, 0, plugin->pcode_size + sizeof(cell_t)); + return new CompData; } ICompilation *JITX86::StartCompilation(BaseRuntime *runtime) { - CompData *data = new CompData; - - data->SetRuntime(runtime); - - return data; + return new CompData; } void CompData::Abort() { - if (rebase) - { - engine->BaseFree(rebase); - } - free(thunks); - delete [] jit_float_table; - delete this; + delete this; } void JITX86::FreeContextVars(sp_context_t *ctx) { - free(((tracker_t *)(ctx->vm[JITVARS_TRACKER]))->pBase); - delete (tracker_t *)ctx->vm[JITVARS_TRACKER]; + free(((tracker_t *)(ctx->vm[JITVARS_TRACKER]))->pBase); + delete (tracker_t *)ctx->vm[JITVARS_TRACKER]; } bool CompData::SetOption(const char *key, const char *val) { - if (strcmp(key, SP_JITCONF_DEBUG) == 0) - { - return true; - } - else if (strcmp(key, SP_JITCONF_PROFILE) == 0) - { - profile = atoi(val); + if (strcmp(key, SP_JITCONF_DEBUG) == 0) + return true; + if (strcmp(key, SP_JITCONF_PROFILE) == 0) { + profile = atoi(val); - /** Callbacks must be profiled to profile functions! */ - if ((profile & SP_PROF_FUNCTIONS) == SP_PROF_FUNCTIONS) - { - profile |= SP_PROF_CALLBACKS; - } + /** Callbacks must be profiled to profile functions! */ + if ((profile & SP_PROF_FUNCTIONS) == SP_PROF_FUNCTIONS) + profile |= SP_PROF_CALLBACKS; - return true; - } + return true; + } - return false; -} - -void *JITX86::GetGenArrayIntrinsic() -{ - return m_pJitGenArray; -} - -void *JITX86::GetReturnPoint() -{ - return m_pJitReturn; -} - -void *JITX86::GetRoundingTable() -{ - return m_RoundTable; + return false; } typedef int (*JIT_EXECUTE)(cell_t *vars, void *addr); int JITX86::InvokeFunction(BaseRuntime *runtime, JitFunction *fn, cell_t *result) { - int err; - JIT_EXECUTE pfn; - sp_context_t *ctx; - cell_t vars[AMX_NUM_INFO_VARS]; + int err; + JIT_EXECUTE pfn; + sp_context_t *ctx; + cell_t vars[AMX_NUM_INFO_VARS]; - ctx = runtime->GetBaseContext()->GetCtx(); + ctx = runtime->GetBaseContext()->GetCtx(); - vars[0] = ctx->sp; - vars[1] = ctx->hp; - vars[2] = (cell_t)result; - vars[3] = (cell_t)ctx; - vars[4] = (cell_t)(runtime->m_pPlugin->memory + runtime->m_pPlugin->mem_size); - vars[5] = fn->GetPCodeAddress(); - vars[6] = runtime->m_pPlugin->data_size; - vars[7] = (cell_t)(runtime->m_pPlugin->memory); - /* vars[8] will be set to ESP */ + vars[0] = ctx->sp; + vars[1] = ctx->hp; + vars[2] = (cell_t)result; + vars[3] = (cell_t)ctx; + vars[4] = (cell_t)(runtime->plugin()->memory + runtime->plugin()->mem_size); + vars[5] = fn->GetPCodeAddress(); + vars[6] = runtime->plugin()->data_size; + vars[7] = (cell_t)(runtime->plugin()->memory); + /* vars[8] will be set to ESP */ - pfn = (JIT_EXECUTE)m_pJitEntry; - err = pfn(vars, fn->GetEntryAddress()); + pfn = (JIT_EXECUTE)m_pJitEntry; + err = pfn(vars, fn->GetEntryAddress()); - ctx->hp = vars[1]; - ctx->err_cip = vars[5]; + ctx->hp = vars[1]; + ctx->err_cip = vars[5]; - return err; + return err; } void *JITX86::AllocCode(size_t size) { - return Knight::KE_AllocCode(g_pCodeCache, size); + return Knight::KE_AllocCode(g_pCodeCache, size); } void JITX86::FreeCode(void *code) { - KE_FreeCode(g_pCodeCache, code); + KE_FreeCode(g_pCodeCache, code); } diff --git a/sourcepawn/jit/x86/jit_x86.h b/sourcepawn/jit/x86/jit_x86.h index b30e4cc2..a59fc8a3 100644 --- a/sourcepawn/jit/x86/jit_x86.h +++ b/sourcepawn/jit/x86/jit_x86.h @@ -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 #include #include -#include "jit_helpers.h" +#include +#include #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 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; diff --git a/sourcepawn/jit/x86/opcode_helpers.cpp b/sourcepawn/jit/x86/opcode_helpers.cpp deleted file mode 100644 index cf42433b..00000000 --- a/sourcepawn/jit/x86/opcode_helpers.cpp +++ /dev/null @@ -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 . - * - * 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 . - * - * Version: $Id$ - */ - -#include -#include -#include -#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, - //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], - //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 , - //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 , [esi+info.heap] - //jb :continue - //lea ecx, [ebp+] - //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+] - // 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+] - // 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], - //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+] - // 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, [*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; iwrite_ubyte(IA32_INT3); - } - } -} diff --git a/sourcepawn/jit/x86/opcode_helpers.h b/sourcepawn/jit/x86/opcode_helpers.h deleted file mode 100644 index 37d91955..00000000 --- a/sourcepawn/jit/x86/opcode_helpers.h +++ /dev/null @@ -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 . - * - * 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 . - * - * 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_ diff --git a/sourcepawn/jit/x86/opcode_switch.inc b/sourcepawn/jit/x86/opcode_switch.inc deleted file mode 100644 index 9eb759fc..00000000 --- a/sourcepawn/jit/x86/opcode_switch.inc +++ /dev/null @@ -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 . - * - * 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 . - * - * 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; - } diff --git a/sourcepawn/jit/x86/ungen_opcode_switch.inc b/sourcepawn/jit/x86/ungen_opcode_switch.inc deleted file mode 100644 index dedd6c2e..00000000 --- a/sourcepawn/jit/x86/ungen_opcode_switch.inc +++ /dev/null @@ -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 . - * - * 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 . - * - * 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; - } \ No newline at end of file diff --git a/sourcepawn/jit/x86/ungen_opcodes.h b/sourcepawn/jit/x86/ungen_opcodes.h deleted file mode 100644 index 50a95c8c..00000000 --- a/sourcepawn/jit/x86/ungen_opcodes.h +++ /dev/null @@ -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 . - * - * 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 . - * - * 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, - 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, - 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, - 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 ;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 - 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 - 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 - 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 - 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_