Merge branch 'rm-interpreter'
This commit is contained in:
		
						commit
						afbcdc8a20
					
				| @ -42,7 +42,6 @@ library.sources += [ | |||||||
|   'environment.cpp', |   'environment.cpp', | ||||||
|   'scripted-invoker.cpp', |   'scripted-invoker.cpp', | ||||||
|   'opcodes.cpp', |   'opcodes.cpp', | ||||||
|   'interpreter.cpp', |  | ||||||
|   'watchdog_timer.cpp', |   'watchdog_timer.cpp', | ||||||
|   'x86/code-stubs-x86.cpp', |   'x86/code-stubs-x86.cpp', | ||||||
|   'x86/jit_x86.cpp', |   'x86/jit_x86.cpp', | ||||||
|  | |||||||
| @ -90,7 +90,6 @@ class Environment : public ISourcePawnEnvironment | |||||||
|   void DisableProfiling(); |   void DisableProfiling(); | ||||||
| 
 | 
 | ||||||
|   void SetJitEnabled(bool enabled) { |   void SetJitEnabled(bool enabled) { | ||||||
|     jit_enabled_ = enabled; |  | ||||||
|   } |   } | ||||||
|   bool IsJitEnabled() const { |   bool IsJitEnabled() const { | ||||||
|     return jit_enabled_; |     return jit_enabled_; | ||||||
|  | |||||||
| @ -1,857 +0,0 @@ | |||||||
| // vim: set ts=8 sts=2 sw=2 tw=99 et:
 |  | ||||||
| //
 |  | ||||||
| // 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/>.
 |  | ||||||
| #include <limits.h> |  | ||||||
| #include <string.h> |  | ||||||
| #include "interpreter.h" |  | ||||||
| #include "opcodes.h" |  | ||||||
| #include "watchdog_timer.h" |  | ||||||
| #include "environment.h" |  | ||||||
| 
 |  | ||||||
| #define STACK_MARGIN 64 |  | ||||||
| 
 |  | ||||||
| using namespace sp; |  | ||||||
| using namespace SourcePawn; |  | ||||||
| 
 |  | ||||||
| static inline bool |  | ||||||
| IsValidOffset(uint32_t cip) |  | ||||||
| { |  | ||||||
|   return cip % 4 == 0; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static inline cell_t |  | ||||||
| Read(const sp_plugin_t *plugin, cell_t offset) |  | ||||||
| { |  | ||||||
|   return *reinterpret_cast<cell_t *>(plugin->memory + offset); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static inline void |  | ||||||
| Write(const sp_plugin_t *plugin, cell_t offset, cell_t value) |  | ||||||
| { |  | ||||||
|   *reinterpret_cast<cell_t *>(plugin->memory + offset) = value; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static inline cell_t * |  | ||||||
| Jump(const sp_plugin_t *plugin, cell_t target) |  | ||||||
| { |  | ||||||
|   if (!IsValidOffset(target) || uint32_t(target) >= plugin->pcode_size) |  | ||||||
|     return NULL; |  | ||||||
|   return reinterpret_cast<cell_t *>(plugin->pcode + target); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static inline cell_t * |  | ||||||
| JumpTarget(const sp_plugin_t *plugin, cell_t *cip, bool cond, int *errp) |  | ||||||
| { |  | ||||||
|   if (!cond) |  | ||||||
|     return cip + 1; |  | ||||||
| 
 |  | ||||||
|   cell_t target = *cip; |  | ||||||
|   if (!IsValidOffset(target) || uint32_t(target) >= plugin->pcode_size) { |  | ||||||
|     *errp = SP_ERROR_INVALID_INSTRUCTION; |  | ||||||
|     return NULL; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   cell_t *next = reinterpret_cast<cell_t *>(plugin->pcode + target); |  | ||||||
|   if (next < cip && !Environment::get()->watchdog()->HandleInterrupt()) { |  | ||||||
|     *errp = SP_ERROR_TIMEOUT; |  | ||||||
|     return NULL; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   return next; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| int |  | ||||||
| Interpret(PluginRuntime *rt, uint32_t aCodeStart, cell_t *rval) |  | ||||||
| { |  | ||||||
|   const sp_plugin_t *plugin = rt->plugin(); |  | ||||||
|   cell_t *code = reinterpret_cast<cell_t *>(plugin->pcode); |  | ||||||
|   cell_t *codeend = reinterpret_cast<cell_t *>(plugin->pcode + plugin->pcode_size); |  | ||||||
| 
 |  | ||||||
|   if (!IsValidOffset(aCodeStart) || aCodeStart > plugin->pcode_size) |  | ||||||
|     return SP_ERROR_INVALID_INSTRUCTION; |  | ||||||
| 
 |  | ||||||
|   PluginContext *cx = rt->GetBaseContext(); |  | ||||||
| 
 |  | ||||||
|   int err = SP_ERROR_NONE; |  | ||||||
| 
 |  | ||||||
|   // Save the original frm. BaseContext won't, and if we error, we won't hit
 |  | ||||||
|   // the stack unwinding code.
 |  | ||||||
|   cell_t orig_frm = cx->frm(); |  | ||||||
| 
 |  | ||||||
|   cell_t &frm = *cx->addressOfFrm(); |  | ||||||
|   cell_t &sp = *cx->addressOfSp(); |  | ||||||
| 
 |  | ||||||
|   cell_t pri = 0; |  | ||||||
|   cell_t alt = 0; |  | ||||||
|   cell_t *cip = code + (aCodeStart / 4); |  | ||||||
|   cell_t *stk = reinterpret_cast<cell_t *>(plugin->memory + sp); |  | ||||||
| 
 |  | ||||||
|   for (;;) { |  | ||||||
|     if (cip >= codeend) { |  | ||||||
|       err = SP_ERROR_INVALID_INSTRUCTION; |  | ||||||
|       goto error; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
| #if 0 |  | ||||||
|     SpewOpcode(plugin, reinterpret_cast<cell_t *>(plugin->pcode + aCodeStart), cip); |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
|     OPCODE op = (OPCODE)*cip++; |  | ||||||
| 
 |  | ||||||
|     switch (op) { |  | ||||||
|       case OP_MOVE_PRI: |  | ||||||
|         pri = alt; |  | ||||||
|         break; |  | ||||||
|       case OP_MOVE_ALT: |  | ||||||
|         alt = pri; |  | ||||||
|         break; |  | ||||||
| 
 |  | ||||||
|       case OP_XCHG: |  | ||||||
|       { |  | ||||||
|         cell_t tmp = pri; |  | ||||||
|         pri = alt; |  | ||||||
|         alt = tmp; |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
| 
 |  | ||||||
|       case OP_ZERO: |  | ||||||
|         Write(plugin, *cip++, 0); |  | ||||||
|         break; |  | ||||||
| 
 |  | ||||||
|       case OP_ZERO_S: |  | ||||||
|         Write(plugin, frm + *cip++, 0); |  | ||||||
|         break; |  | ||||||
| 
 |  | ||||||
|       case OP_PUSH_PRI: |  | ||||||
|         *--stk = pri; |  | ||||||
|         break; |  | ||||||
|       case OP_PUSH_ALT: |  | ||||||
|         *--stk = alt; |  | ||||||
|         break; |  | ||||||
| 
 |  | ||||||
|       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; |  | ||||||
| 
 |  | ||||||
|         int i = 1; |  | ||||||
|         do { |  | ||||||
|           *--stk = *cip++; |  | ||||||
|         } while (i++ < n); |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
| 
 |  | ||||||
|       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; |  | ||||||
| 
 |  | ||||||
|         do { |  | ||||||
|           cell_t addr = frm + *cip++; |  | ||||||
|           *--stk = addr; |  | ||||||
|         } while (i++ < n); |  | ||||||
|         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 value = Read(plugin, frm + *cip++); |  | ||||||
|           *--stk = value; |  | ||||||
|         } while (i++ < 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 value = Read(plugin, *cip++); |  | ||||||
|           *--stk = value; |  | ||||||
|         } while (i++ < n); |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
| 
 |  | ||||||
|       case OP_ZERO_PRI: |  | ||||||
|         pri = 0; |  | ||||||
|         break; |  | ||||||
|       case OP_ZERO_ALT: |  | ||||||
|         alt = 0; |  | ||||||
|         break; |  | ||||||
| 
 |  | ||||||
|       case OP_ADD: |  | ||||||
|         pri += alt; |  | ||||||
|         break; |  | ||||||
| 
 |  | ||||||
|       case OP_SUB: |  | ||||||
|         pri -= alt; |  | ||||||
|         break; |  | ||||||
| 
 |  | ||||||
|       case OP_SUB_ALT: |  | ||||||
|         pri = alt - pri; |  | ||||||
|         break; |  | ||||||
| 
 |  | ||||||
|       case OP_PROC: |  | ||||||
|       { |  | ||||||
|         *--stk = frm; |  | ||||||
|         *--stk = 0; |  | ||||||
|         frm = uintptr_t(stk) - uintptr_t(plugin->memory); |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
| 
 |  | ||||||
|       case OP_IDXADDR_B: |  | ||||||
|         pri <<= *cip++; |  | ||||||
|         pri += alt; |  | ||||||
|         break; |  | ||||||
| 
 |  | ||||||
|       case OP_SHL: |  | ||||||
|         pri <<= alt; |  | ||||||
|         break; |  | ||||||
| 
 |  | ||||||
|       case OP_SHR: |  | ||||||
|         pri = unsigned(pri) >> unsigned(alt); |  | ||||||
|         break; |  | ||||||
| 
 |  | ||||||
|       case OP_SSHR: |  | ||||||
|         pri >>= alt; |  | ||||||
|         break; |  | ||||||
| 
 |  | ||||||
|       case OP_SHL_C_PRI: |  | ||||||
|         pri <<= *cip++; |  | ||||||
|         break; |  | ||||||
|       case OP_SHL_C_ALT: |  | ||||||
|         alt <<= *cip++; |  | ||||||
|         break; |  | ||||||
| 
 |  | ||||||
|       case OP_SHR_C_PRI: |  | ||||||
|         pri >>= *cip++; |  | ||||||
|         break; |  | ||||||
|       case OP_SHR_C_ALT: |  | ||||||
|         alt >>= *cip++; |  | ||||||
|         break; |  | ||||||
| 
 |  | ||||||
|       case OP_SMUL: |  | ||||||
|         pri *= alt; |  | ||||||
|         break; |  | ||||||
| 
 |  | ||||||
|       case OP_NOT: |  | ||||||
|         pri = pri ? 0 : 1; |  | ||||||
|         break; |  | ||||||
| 
 |  | ||||||
|       case OP_NEG: |  | ||||||
|         pri = -pri; |  | ||||||
|         break; |  | ||||||
| 
 |  | ||||||
|       case OP_XOR: |  | ||||||
|         pri ^= alt; |  | ||||||
|         break; |  | ||||||
| 
 |  | ||||||
|       case OP_OR: |  | ||||||
|         pri |= alt; |  | ||||||
|         break; |  | ||||||
| 
 |  | ||||||
|       case OP_AND: |  | ||||||
|         pri &= alt; |  | ||||||
|         break; |  | ||||||
| 
 |  | ||||||
|       case OP_INVERT: |  | ||||||
|         pri = ~pri; |  | ||||||
|         break; |  | ||||||
| 
 |  | ||||||
|       case OP_ADD_C: |  | ||||||
|         pri += *cip++; |  | ||||||
|         break; |  | ||||||
| 
 |  | ||||||
|       case OP_SMUL_C: |  | ||||||
|         pri *= *cip++; |  | ||||||
|         break; |  | ||||||
| 
 |  | ||||||
|       case OP_EQ: |  | ||||||
|         pri = pri == alt; |  | ||||||
|         break; |  | ||||||
| 
 |  | ||||||
|       case OP_NEQ: |  | ||||||
|         pri = pri != alt; |  | ||||||
|         break; |  | ||||||
| 
 |  | ||||||
|       case OP_SLESS: |  | ||||||
|         pri = pri < alt; |  | ||||||
|         break; |  | ||||||
| 
 |  | ||||||
|       case OP_SLEQ: |  | ||||||
|         pri = pri <= alt; |  | ||||||
|         break; |  | ||||||
| 
 |  | ||||||
|       case OP_SGRTR: |  | ||||||
|         pri = pri > alt; |  | ||||||
|         break; |  | ||||||
|          |  | ||||||
|       case OP_SGEQ: |  | ||||||
|         pri = pri >= alt; |  | ||||||
|         break; |  | ||||||
| 
 |  | ||||||
|       case OP_EQ_C_PRI: |  | ||||||
|         pri = pri == *cip++; |  | ||||||
|         break; |  | ||||||
|       case OP_EQ_C_ALT: |  | ||||||
|         pri = alt == *cip++; |  | ||||||
|         break; |  | ||||||
| 
 |  | ||||||
|       case OP_INC_PRI: |  | ||||||
|         pri++; |  | ||||||
|         break; |  | ||||||
|       case OP_INC_ALT: |  | ||||||
|         alt++; |  | ||||||
|         break; |  | ||||||
| 
 |  | ||||||
|       case OP_INC: |  | ||||||
|       { |  | ||||||
|         cell_t offset = *cip++; |  | ||||||
|         Write(plugin, offset, Read(plugin, offset) + 1); |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
| 
 |  | ||||||
|       case OP_INC_S: |  | ||||||
|       { |  | ||||||
|         cell_t offset = *cip++; |  | ||||||
|         cell_t value = Read(plugin, frm + offset); |  | ||||||
|         Write(plugin, frm + offset, value + 1); |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
| 
 |  | ||||||
|       case OP_INC_I: |  | ||||||
|         if (!cx->checkAddress(stk, pri)) { |  | ||||||
|           err = SP_ERROR_MEMACCESS; |  | ||||||
|           goto error; |  | ||||||
|         } |  | ||||||
|         Write(plugin, pri, Read(plugin, pri) + 1); |  | ||||||
|         break; |  | ||||||
| 
 |  | ||||||
|       case OP_DEC_PRI: |  | ||||||
|         pri--; |  | ||||||
|         break; |  | ||||||
|       case OP_DEC_ALT: |  | ||||||
|         alt--; |  | ||||||
|         break; |  | ||||||
| 
 |  | ||||||
|       case OP_DEC: |  | ||||||
|       { |  | ||||||
|         cell_t offset = *cip++; |  | ||||||
|         Write(plugin, offset, Read(plugin, offset) - 1); |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
| 
 |  | ||||||
|       case OP_DEC_S: |  | ||||||
|       { |  | ||||||
|         cell_t offset = *cip++; |  | ||||||
|         cell_t value = Read(plugin, frm + offset); |  | ||||||
|         Write(plugin, frm + offset, value - 1); |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
| 
 |  | ||||||
|       case OP_DEC_I: |  | ||||||
|         if (!cx->checkAddress(stk, pri)) { |  | ||||||
|           err = SP_ERROR_MEMACCESS; |  | ||||||
|           goto error; |  | ||||||
|         } |  | ||||||
|         Write(plugin, pri, Read(plugin, pri) - 1); |  | ||||||
|         break; |  | ||||||
| 
 |  | ||||||
|       case OP_LOAD_PRI: |  | ||||||
|         pri = Read(plugin, *cip++); |  | ||||||
|         break; |  | ||||||
|       case OP_LOAD_ALT: |  | ||||||
|         alt = Read(plugin, *cip++); |  | ||||||
|         break; |  | ||||||
| 
 |  | ||||||
|       case OP_LOAD_S_PRI: |  | ||||||
|         pri = Read(plugin, frm + *cip++); |  | ||||||
|         break; |  | ||||||
|       case OP_LOAD_S_ALT: |  | ||||||
|         alt = Read(plugin, frm + *cip++); |  | ||||||
|         break; |  | ||||||
| 
 |  | ||||||
|       case OP_LOAD_S_BOTH: |  | ||||||
|         pri = Read(plugin, frm + *cip++); |  | ||||||
|         alt = Read(plugin, frm + *cip++); |  | ||||||
|         break; |  | ||||||
| 
 |  | ||||||
|       case OP_LREF_S_PRI: |  | ||||||
|       { |  | ||||||
|         pri = Read(plugin, frm + *cip++); |  | ||||||
|         pri = Read(plugin, pri); |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
| 
 |  | ||||||
|       case OP_LREF_S_ALT: |  | ||||||
|       { |  | ||||||
|         alt = Read(plugin, frm + *cip++); |  | ||||||
|         alt = Read(plugin, alt); |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
| 
 |  | ||||||
|       case OP_CONST_PRI: |  | ||||||
|         pri = *cip++; |  | ||||||
|         break; |  | ||||||
|       case OP_CONST_ALT: |  | ||||||
|         alt = *cip++; |  | ||||||
|         break; |  | ||||||
| 
 |  | ||||||
|       case OP_ADDR_PRI: |  | ||||||
|         pri = frm + *cip++; |  | ||||||
|         break; |  | ||||||
|       case OP_ADDR_ALT: |  | ||||||
|         alt = frm + *cip++; |  | ||||||
|         break; |  | ||||||
| 
 |  | ||||||
|       case OP_STOR_PRI: |  | ||||||
|         Write(plugin, *cip++, pri); |  | ||||||
|         break; |  | ||||||
|       case OP_STOR_ALT: |  | ||||||
|         Write(plugin, *cip++, alt); |  | ||||||
|         break; |  | ||||||
| 
 |  | ||||||
|       case OP_STOR_S_PRI: |  | ||||||
|         Write(plugin, frm + *cip++, pri); |  | ||||||
|         break; |  | ||||||
|       case OP_STOR_S_ALT: |  | ||||||
|         Write(plugin, frm +*cip++, alt); |  | ||||||
|         break; |  | ||||||
| 
 |  | ||||||
|       case OP_IDXADDR: |  | ||||||
|         pri = alt + pri * 4; |  | ||||||
|         break; |  | ||||||
| 
 |  | ||||||
|       case OP_SREF_S_PRI: |  | ||||||
|       { |  | ||||||
|         cell_t offset = *cip++; |  | ||||||
|         cell_t addr = Read(plugin, frm + offset); |  | ||||||
|         Write(plugin, addr, pri); |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
| 
 |  | ||||||
|       case OP_SREF_S_ALT: |  | ||||||
|       { |  | ||||||
|         cell_t offset = *cip++; |  | ||||||
|         cell_t addr = Read(plugin, frm + offset); |  | ||||||
|         Write(plugin, addr, alt); |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
| 
 |  | ||||||
|       case OP_POP_PRI: |  | ||||||
|         pri = *stk++; |  | ||||||
|         break; |  | ||||||
|       case OP_POP_ALT: |  | ||||||
|         alt = *stk++; |  | ||||||
|         break; |  | ||||||
| 
 |  | ||||||
|       case OP_SWAP_PRI: |  | ||||||
|       case OP_SWAP_ALT: |  | ||||||
|       { |  | ||||||
|         cell_t reg = (op == OP_SREF_S_PRI) ? pri : alt; |  | ||||||
|         cell_t temp = *stk; |  | ||||||
|         *stk = reg; |  | ||||||
|         reg = temp; |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
| 
 |  | ||||||
|       case OP_LIDX: |  | ||||||
|         pri = alt + pri * 4; |  | ||||||
|         if (!cx->checkAddress(stk, pri)) { |  | ||||||
|           err = SP_ERROR_MEMACCESS; |  | ||||||
|           goto error; |  | ||||||
|         } |  | ||||||
|         pri = Read(plugin, pri); |  | ||||||
|         break; |  | ||||||
| 
 |  | ||||||
|       case OP_LIDX_B: |  | ||||||
|       { |  | ||||||
|         cell_t val = *cip++; |  | ||||||
|         pri = alt + (pri << val); |  | ||||||
|         if (!cx->checkAddress(stk, pri)) { |  | ||||||
|           err = SP_ERROR_MEMACCESS; |  | ||||||
|           goto error; |  | ||||||
|         } |  | ||||||
|         pri = Read(plugin, pri); |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
| 
 |  | ||||||
|       case OP_CONST: |  | ||||||
|       { |  | ||||||
|         cell_t offset = *cip++; |  | ||||||
|         cell_t value = *cip++; |  | ||||||
|         Write(plugin, offset, value); |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
| 
 |  | ||||||
|       case OP_CONST_S: |  | ||||||
|       { |  | ||||||
|         cell_t offset = *cip++; |  | ||||||
|         cell_t value = *cip++; |  | ||||||
|         Write(plugin, frm + offset, value); |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
| 
 |  | ||||||
|       case OP_LOAD_I: |  | ||||||
|         if (!cx->checkAddress(stk, pri)) { |  | ||||||
|           err = SP_ERROR_MEMACCESS; |  | ||||||
|           goto error; |  | ||||||
|         } |  | ||||||
|         pri = Read(plugin, pri); |  | ||||||
|         break; |  | ||||||
| 
 |  | ||||||
|       case OP_STOR_I: |  | ||||||
|         if (!cx->checkAddress(stk, alt)) { |  | ||||||
|           err = SP_ERROR_MEMACCESS; |  | ||||||
|           goto error; |  | ||||||
|         } |  | ||||||
|         Write(plugin, alt, pri); |  | ||||||
|         break; |  | ||||||
| 
 |  | ||||||
|       case OP_SDIV: |  | ||||||
|       case OP_SDIV_ALT: |  | ||||||
|       { |  | ||||||
|         cell_t dividend = (op == OP_SDIV) ? pri : alt; |  | ||||||
|         cell_t divisor = (op == OP_SDIV) ? alt : pri; |  | ||||||
|         if (divisor == 0) { |  | ||||||
|           err = SP_ERROR_DIVIDE_BY_ZERO; |  | ||||||
|           goto error; |  | ||||||
|         } |  | ||||||
|         if (dividend == INT_MIN && divisor == -1) { |  | ||||||
|           err = SP_ERROR_INTEGER_OVERFLOW; |  | ||||||
|           goto error; |  | ||||||
|         } |  | ||||||
|         pri = dividend / divisor; |  | ||||||
|         alt = dividend % divisor; |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
|        |  | ||||||
|       case OP_LODB_I: |  | ||||||
|       { |  | ||||||
|         cell_t val = *cip++; |  | ||||||
|         if (!cx->checkAddress(stk, pri)) { |  | ||||||
|           err = SP_ERROR_MEMACCESS; |  | ||||||
|           goto error; |  | ||||||
|         } |  | ||||||
|         pri = Read(plugin, pri); |  | ||||||
|         if (val == 1) |  | ||||||
|           pri &= 0xff; |  | ||||||
|         else if (val == 2) |  | ||||||
|           pri &= 0xffff; |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
| 
 |  | ||||||
|       case OP_STRB_I: |  | ||||||
|       { |  | ||||||
|         cell_t val = *cip++; |  | ||||||
|         if (!cx->checkAddress(stk, alt)) { |  | ||||||
|           err = SP_ERROR_MEMACCESS; |  | ||||||
|           goto error; |  | ||||||
|         } |  | ||||||
|         if (val == 1) |  | ||||||
|           *reinterpret_cast<int8_t *>(plugin->memory + alt) = pri; |  | ||||||
|         else if (val == 2) |  | ||||||
|           *reinterpret_cast<int16_t *>(plugin->memory + alt) = pri; |  | ||||||
|         else if (val == 4) |  | ||||||
|           *reinterpret_cast<int32_t *>(plugin->memory + alt) = pri; |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
| 
 |  | ||||||
|       case OP_RETN: |  | ||||||
|       { |  | ||||||
|         stk++; |  | ||||||
|         frm = *stk++; |  | ||||||
|         stk += *stk + 1; |  | ||||||
|         *rval = pri; |  | ||||||
|         err = SP_ERROR_NONE; |  | ||||||
|         goto done; |  | ||||||
|       } |  | ||||||
| 
 |  | ||||||
|       case OP_MOVS: |  | ||||||
|       { |  | ||||||
|         uint8_t *src = plugin->memory + pri; |  | ||||||
|         uint8_t *dest = plugin->memory + alt; |  | ||||||
|         memcpy(dest, src, *cip++); |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
| 
 |  | ||||||
|       case OP_FILL: |  | ||||||
|       { |  | ||||||
|         uint8_t *dest = plugin->memory + alt; |  | ||||||
|         memset(dest, pri, *cip++); |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
| 
 |  | ||||||
|       case OP_STRADJUST_PRI: |  | ||||||
|         pri += 4; |  | ||||||
|         pri >>= 2; |  | ||||||
|         break; |  | ||||||
| 
 |  | ||||||
|       case OP_STACK: |  | ||||||
|       { |  | ||||||
|         cell_t amount = *cip++; |  | ||||||
|         if (!IsValidOffset(amount)) { |  | ||||||
|           err = SP_ERROR_INVALID_INSTRUCTION; |  | ||||||
|           goto error; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         stk += amount / 4; |  | ||||||
|         if (amount > 0) { |  | ||||||
|           if (uintptr_t(stk) >= uintptr_t(plugin->memory + plugin->mem_size)) { |  | ||||||
|             err = SP_ERROR_STACKMIN; |  | ||||||
|             goto error; |  | ||||||
|           } |  | ||||||
|         } else { |  | ||||||
|           if (uintptr_t(stk) < uintptr_t(plugin->memory + cx->hp() + STACK_MARGIN)) { |  | ||||||
|             err = SP_ERROR_STACKLOW; |  | ||||||
|             goto error; |  | ||||||
|           } |  | ||||||
|         } |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
| 
 |  | ||||||
|       case OP_HEAP: |  | ||||||
|       { |  | ||||||
|         cell_t amount = *cip++; |  | ||||||
| 
 |  | ||||||
|         alt = cx->hp(); |  | ||||||
|         *cx->addressOfHp() += amount; |  | ||||||
| 
 |  | ||||||
|         if (amount > 0) { |  | ||||||
|           if (uintptr_t(plugin->memory + cx->hp()) > uintptr_t(stk)) { |  | ||||||
|             err = SP_ERROR_HEAPLOW; |  | ||||||
|             goto error; |  | ||||||
|           } |  | ||||||
|         } else { |  | ||||||
|           if (uint32_t(cx->hp()) < plugin->data_size) { |  | ||||||
|             err = SP_ERROR_HEAPMIN; |  | ||||||
|             goto error; |  | ||||||
|           } |  | ||||||
|         } |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
| 
 |  | ||||||
|       case OP_JUMP: |  | ||||||
|         if ((cip = JumpTarget(plugin, cip, true, &err)) == NULL) |  | ||||||
|           goto error; |  | ||||||
|         break; |  | ||||||
| 
 |  | ||||||
|       case OP_JZER: |  | ||||||
|         if ((cip = JumpTarget(plugin, cip, pri == 0, &err)) == NULL) |  | ||||||
|           goto error; |  | ||||||
|         break; |  | ||||||
|       case OP_JNZ: |  | ||||||
|         if ((cip = JumpTarget(plugin, cip, pri != 0, &err)) == NULL) |  | ||||||
|           goto error; |  | ||||||
|         break; |  | ||||||
| 
 |  | ||||||
|       case OP_JEQ: |  | ||||||
|         if ((cip = JumpTarget(plugin, cip, pri == alt, &err)) == NULL) |  | ||||||
|           goto error; |  | ||||||
|         break; |  | ||||||
|       case OP_JNEQ: |  | ||||||
|         if ((cip = JumpTarget(plugin, cip, pri != alt, &err)) == NULL) |  | ||||||
|           goto error; |  | ||||||
|         break; |  | ||||||
|       case OP_JSLESS: |  | ||||||
|         if ((cip = JumpTarget(plugin, cip, pri < alt, &err)) == NULL) |  | ||||||
|           goto error; |  | ||||||
|         break; |  | ||||||
|       case OP_JSLEQ: |  | ||||||
|         if ((cip = JumpTarget(plugin, cip, pri <= alt, &err)) == NULL) |  | ||||||
|           goto error; |  | ||||||
|         break; |  | ||||||
|       case OP_JSGRTR: |  | ||||||
|         if ((cip = JumpTarget(plugin, cip, pri > alt, &err)) == NULL) |  | ||||||
|           goto error; |  | ||||||
|         break; |  | ||||||
|       case OP_JSGEQ: |  | ||||||
|         if ((cip = JumpTarget(plugin, cip, pri >= alt, &err)) == NULL) |  | ||||||
|           goto error; |  | ||||||
|         break; |  | ||||||
| 
 |  | ||||||
|       case OP_TRACKER_PUSH_C: |  | ||||||
|       { |  | ||||||
|         cell_t amount = *cip++; |  | ||||||
|         int error = cx->pushTracker(amount * 4); |  | ||||||
|         if (error != SP_ERROR_NONE) { |  | ||||||
|           err = error; |  | ||||||
|           goto error; |  | ||||||
|         } |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
| 
 |  | ||||||
|       case OP_TRACKER_POP_SETHEAP: |  | ||||||
|       { |  | ||||||
|         int error = cx->popTrackerAndSetHeap(); |  | ||||||
|         if (error != SP_ERROR_NONE) { |  | ||||||
|           err = error; |  | ||||||
|           goto error; |  | ||||||
|         } |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
| 
 |  | ||||||
|       case OP_BREAK: |  | ||||||
|         *cx->addressOfCip() = uintptr_t(cip - 1) - uintptr_t(plugin->pcode); |  | ||||||
|         break; |  | ||||||
| 
 |  | ||||||
|       case OP_BOUNDS: |  | ||||||
|       { |  | ||||||
|         cell_t value = *cip++; |  | ||||||
|         if (uint32_t(pri) > uint32_t(value)) { |  | ||||||
|           err = SP_ERROR_ARRAY_BOUNDS; |  | ||||||
|           goto error; |  | ||||||
|         } |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
| 
 |  | ||||||
|       case OP_CALL: |  | ||||||
|       { |  | ||||||
|         cell_t offset = *cip++; |  | ||||||
| 
 |  | ||||||
|         if (!IsValidOffset(offset) || uint32_t(offset) >= plugin->pcode_size) { |  | ||||||
|           err = SP_ERROR_INSTRUCTION_PARAM; |  | ||||||
|           goto error; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         // For debugging.
 |  | ||||||
|         uintptr_t rcip = uintptr_t(cip - 2) - uintptr_t(plugin->pcode); |  | ||||||
|         if (!cx->pushReturnCip(rcip)) { |  | ||||||
|           err = SP_ERROR_STACKLOW; |  | ||||||
|           goto error; |  | ||||||
|         } |  | ||||||
|         *cx->addressOfCip() = offset; |  | ||||||
|         sp = uintptr_t(stk) - uintptr_t(plugin->memory); |  | ||||||
| 
 |  | ||||||
|         int err = Interpret(rt, offset, &pri); |  | ||||||
| 
 |  | ||||||
|         stk = reinterpret_cast<cell_t *>(plugin->memory + sp); |  | ||||||
|         *cx->addressOfCip() = rcip; |  | ||||||
|         cx->popReturnCip(); |  | ||||||
| 
 |  | ||||||
|         if (err != SP_ERROR_NONE) |  | ||||||
|           goto error; |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
| 
 |  | ||||||
|       case OP_GENARRAY: |  | ||||||
|       case OP_GENARRAY_Z: |  | ||||||
|       { |  | ||||||
|         cell_t val = *cip++; |  | ||||||
|         if ((err = cx->generateArray(val, stk, op == OP_GENARRAY_Z)) != SP_ERROR_NONE) |  | ||||||
|           goto error; |  | ||||||
| 
 |  | ||||||
|         stk += (val - 1) * 4; |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
| 
 |  | ||||||
|       case OP_SYSREQ_C: |  | ||||||
|       case OP_SYSREQ_N: |  | ||||||
|       { |  | ||||||
|         uint32_t native_index = *cip++; |  | ||||||
| 
 |  | ||||||
|         if (native_index >= plugin->num_natives) { |  | ||||||
|           err = SP_ERROR_INSTRUCTION_PARAM; |  | ||||||
|           goto error; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         uint32_t num_params; |  | ||||||
|         if (op == OP_SYSREQ_N) { |  | ||||||
|           num_params = *cip++; |  | ||||||
|           *--stk = num_params; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         sp = uintptr_t(stk) - uintptr_t(plugin->memory); |  | ||||||
|         pri = cx->invokeNative(native_index, stk); |  | ||||||
|         if (cx->GetLastNativeError() != SP_ERROR_NONE) { |  | ||||||
|           err = cx->GetLastNativeError(); |  | ||||||
|           goto error; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         if (op == OP_SYSREQ_N) |  | ||||||
|           stk += num_params + 1; |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
| 
 |  | ||||||
|       case OP_SWITCH: |  | ||||||
|       { |  | ||||||
|         cell_t offset = *cip++; |  | ||||||
|         cell_t *table = reinterpret_cast<cell_t *>(plugin->pcode + offset + sizeof(cell_t)); |  | ||||||
| 
 |  | ||||||
|         size_t ncases = *table++; |  | ||||||
|         cell_t target = *table++;   // default case
 |  | ||||||
| 
 |  | ||||||
|         for (size_t i = 0; i < ncases; i++) { |  | ||||||
|           if (table[i * 2] == pri) { |  | ||||||
|             target = table[i * 2 + 1]; |  | ||||||
|             break; |  | ||||||
|           } |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         if ((cip = Jump(plugin, target)) == NULL) { |  | ||||||
|           err = SP_ERROR_INVALID_INSTRUCTION; |  | ||||||
|           goto error; |  | ||||||
|         } |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
| 
 |  | ||||||
|       default: |  | ||||||
|       { |  | ||||||
|         err = SP_ERROR_INVALID_INSTRUCTION; |  | ||||||
|         goto error; |  | ||||||
|       } |  | ||||||
|     } // switch
 |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|  done: |  | ||||||
|   assert(orig_frm == frm); |  | ||||||
|   sp = uintptr_t(stk) - uintptr_t(plugin->memory); |  | ||||||
|   return err; |  | ||||||
| 
 |  | ||||||
|  error: |  | ||||||
|   frm = orig_frm; |  | ||||||
|   goto done; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| @ -1,27 +0,0 @@ | |||||||
| // vim: set ts=8 sts=2 sw=2 tw=99 et:
 |  | ||||||
| //
 |  | ||||||
| // 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_interpreter_h_ |  | ||||||
| #define _include_sourcepawn_interpreter_h_ |  | ||||||
| 
 |  | ||||||
| #include <sp_vm_types.h> |  | ||||||
| #include <sp_vm_api.h> |  | ||||||
| #include "plugin-runtime.h" |  | ||||||
| #include "plugin-context.h" |  | ||||||
| 
 |  | ||||||
| int Interpret(PluginRuntime *rt, uint32_t aCodeStart, cell_t *rval); |  | ||||||
| 
 |  | ||||||
| #endif // _include_sourcepawn_interpreter_h_
 |  | ||||||
| @ -18,7 +18,6 @@ | |||||||
| #include "plugin-context.h" | #include "plugin-context.h" | ||||||
| #include "watchdog_timer.h" | #include "watchdog_timer.h" | ||||||
| #include "x86/jit_x86.h" | #include "x86/jit_x86.h" | ||||||
| #include "interpreter.h" |  | ||||||
| #include "environment.h" | #include "environment.h" | ||||||
| 
 | 
 | ||||||
| using namespace SourcePawn; | using namespace SourcePawn; | ||||||
| @ -593,10 +592,7 @@ PluginContext::Execute2(IPluginFunction *function, const cell_t *params, unsigne | |||||||
| 
 | 
 | ||||||
|   // Enter the execution engine.
 |   // Enter the execution engine.
 | ||||||
|   Environment *env = Environment::get(); |   Environment *env = Environment::get(); | ||||||
|   if (env->IsJitEnabled()) |  | ||||||
|   ir = env->Invoke(m_pRuntime, fn, result); |   ir = env->Invoke(m_pRuntime, fn, result); | ||||||
|   else |  | ||||||
|     ir = Interpret(m_pRuntime, cfun->Public()->code_offs, result); |  | ||||||
| 
 | 
 | ||||||
|   /* Restore some states, stop the frame tracer */ |   /* Restore some states, stop the frame tracer */ | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -32,17 +32,11 @@ IsPointerCellAligned(void *p) | |||||||
| 
 | 
 | ||||||
| PluginRuntime::PluginRuntime() | PluginRuntime::PluginRuntime() | ||||||
|   : m_Debug(&m_plugin), |   : m_Debug(&m_plugin), | ||||||
|     m_pCtx(NULL),  |  | ||||||
|     m_PubFuncs(NULL), |     m_PubFuncs(NULL), | ||||||
|     m_CompSerial(0) |     m_CompSerial(0) | ||||||
| { | { | ||||||
|   memset(&m_plugin, 0, sizeof(m_plugin)); |   memset(&m_plugin, 0, sizeof(m_plugin)); | ||||||
| 
 | 
 | ||||||
|   m_MaxFuncs = 0; |  | ||||||
|   m_NumFuncs = 0; |  | ||||||
|   float_table_ = NULL; |  | ||||||
|   alt_pcode_ = NULL; |  | ||||||
|    |  | ||||||
|   memset(m_CodeHash, 0, sizeof(m_CodeHash)); |   memset(m_CodeHash, 0, sizeof(m_CodeHash)); | ||||||
|   memset(m_DataHash, 0, sizeof(m_DataHash)); |   memset(m_DataHash, 0, sizeof(m_DataHash)); | ||||||
| 
 | 
 | ||||||
| @ -63,14 +57,10 @@ PluginRuntime::~PluginRuntime() | |||||||
|   for (uint32_t i = 0; i < m_plugin.num_publics; i++) |   for (uint32_t i = 0; i < m_plugin.num_publics; i++) | ||||||
|     delete m_PubFuncs[i]; |     delete m_PubFuncs[i]; | ||||||
|   delete [] m_PubFuncs; |   delete [] m_PubFuncs; | ||||||
|   delete [] float_table_; |  | ||||||
|   delete [] alt_pcode_; |  | ||||||
| 
 | 
 | ||||||
|   for (size_t i = 0; i < m_JitFunctions.length(); i++) |   for (size_t i = 0; i < m_JitFunctions.length(); i++) | ||||||
|     delete m_JitFunctions[i]; |     delete m_JitFunctions[i]; | ||||||
| 
 | 
 | ||||||
|   delete m_pCtx; |  | ||||||
| 
 |  | ||||||
|   free(m_plugin.base); |   free(m_plugin.base); | ||||||
|   delete [] m_plugin.memory; |   delete [] m_plugin.memory; | ||||||
|   delete [] m_plugin.publics; |   delete [] m_plugin.publics; | ||||||
|  | |||||||
| @ -107,10 +107,8 @@ class PluginRuntime | |||||||
| 
 | 
 | ||||||
|  private: |  private: | ||||||
|   sp_plugin_t m_plugin; |   sp_plugin_t m_plugin; | ||||||
|   uint8_t *alt_pcode_; |   ke::AutoArray<uint8_t> alt_pcode_; | ||||||
|   unsigned int m_NumFuncs; |   ke::AutoArray<floattbl_t> float_table_; | ||||||
|   unsigned int m_MaxFuncs; |  | ||||||
|   floattbl_t *float_table_; |  | ||||||
| 
 | 
 | ||||||
|   struct FunctionMapPolicy { |   struct FunctionMapPolicy { | ||||||
|     static inline uint32_t hash(ucell_t value) { |     static inline uint32_t hash(ucell_t value) { | ||||||
| @ -127,7 +125,7 @@ class PluginRuntime | |||||||
| 
 | 
 | ||||||
|  public: |  public: | ||||||
|   DebugInfo m_Debug; |   DebugInfo m_Debug; | ||||||
|   PluginContext *m_pCtx; |   ke::AutoPtr<PluginContext> m_pCtx; | ||||||
|   ScriptedInvoker **m_PubFuncs; |   ScriptedInvoker **m_PubFuncs; | ||||||
| 
 | 
 | ||||||
|  public: |  public: | ||||||
|  | |||||||
| @ -36,7 +36,6 @@ | |||||||
| #include "plugin-runtime.h" | #include "plugin-runtime.h" | ||||||
| #include "plugin-context.h" | #include "plugin-context.h" | ||||||
| #include "watchdog_timer.h" | #include "watchdog_timer.h" | ||||||
| #include "interpreter.h" |  | ||||||
| #include "environment.h" | #include "environment.h" | ||||||
| #include "code-stubs.h" | #include "code-stubs.h" | ||||||
| #include "x86-utils.h" | #include "x86-utils.h" | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user