1.1 --- a/sourcepawn/jit/x86/jit_x86.cpp Wed Aug 14 17:18:02 2013 -0400
1.2 +++ b/sourcepawn/jit/x86/jit_x86.cpp Wed Aug 14 23:54:25 2013 -0700
1.3 @@ -37,6 +37,7 @@
1.4 #include "../engine2.h"
1.5 #include "../BaseRuntime.h"
1.6 #include "../sp_vm_basecontext.h"
1.7 +#include "watchdog_timer.h"
1.8
1.9 using namespace Knight;
1.10
1.11 @@ -50,7 +51,7 @@
1.12 KeCodeCache *g_pCodeCache = NULL;
1.13 ISourcePawnEngine *engine = &g_engine1;
1.14
1.15 -static inline void *
1.16 +static inline uint8_t *
1.17 LinkCode(AssemblerX86 &masm)
1.18 {
1.19 if (masm.outOfMemory())
1.20 @@ -61,7 +62,7 @@
1.21 return NULL;
1.22
1.23 masm.emitToExecutableMemory(code);
1.24 - return code;
1.25 + return reinterpret_cast<uint8_t *>(code);
1.26 }
1.27
1.28 static inline ConditionCode
1.29 @@ -249,7 +250,7 @@
1.30 return err;
1.31
1.32 cell_t *base = reinterpret_cast<cell_t *>(rt->plugin()->memory + ctx->hp);
1.33 - cell_t offs = GenerateArrayIndirectionVectors(base, argv, argc, autozero);
1.34 + cell_t offs = GenerateArrayIndirectionVectors(base, argv, argc, !!autozero);
1.35 assert(size_t(offs) == cells);
1.36
1.37 argv[argc - 1] = ctx->hp;
1.38 @@ -314,6 +315,12 @@
1.39 static int
1.40 CompileFromThunk(BaseRuntime *runtime, cell_t pcode_offs, void **addrp, char *pc)
1.41 {
1.42 + // If the watchdog timer has declared a timeout, we must process it now,
1.43 + // and possibly refuse to compile, since otherwise we will compile a
1.44 + // function that is not patched for timeouts.
1.45 + if (!g_WatchdogTimer.HandleInterrupt())
1.46 + return SP_ERROR_TIMEOUT;
1.47 +
1.48 JitFunction *fn = runtime->GetJittedFunctionByOffset(pcode_offs);
1.49 if (!fn) {
1.50 int err;
1.51 @@ -452,13 +459,19 @@
1.52 emitCallThunks();
1.53 emitErrorPaths();
1.54
1.55 - void *code = LinkCode(masm);
1.56 + uint8_t *code = LinkCode(masm);
1.57 if (!code) {
1.58 *errp = SP_ERROR_OUT_OF_MEMORY;
1.59 return NULL;
1.60 }
1.61
1.62 - return new JitFunction(code, pcode_start_);
1.63 + LoopEdge *edges = new LoopEdge[backward_jumps_.length()];
1.64 + for (size_t i = 0; i < backward_jumps_.length(); i++) {
1.65 + edges[i].offset = backward_jumps_[i];
1.66 + edges[i].disp32 = *reinterpret_cast<int32_t *>(code + edges[i].offset - 4);
1.67 + }
1.68 +
1.69 + return new JitFunction(code, pcode_start_, edges, backward_jumps_.length());
1.70 }
1.71
1.72 bool
1.73 @@ -1228,7 +1241,12 @@
1.74 Label *target = labelAt(readCell());
1.75 if (!target)
1.76 return false;
1.77 - __ jmp(target);
1.78 + if (target->bound()) {
1.79 + __ jmp32(target);
1.80 + backward_jumps_.append(masm.pc());
1.81 + } else {
1.82 + __ jmp(target);
1.83 + }
1.84 break;
1.85 }
1.86
1.87 @@ -1240,7 +1258,12 @@
1.88 if (!target)
1.89 return false;
1.90 __ testl(pri, pri);
1.91 - __ j(cc, target);
1.92 + if (target->bound()) {
1.93 + __ j32(cc, target);
1.94 + backward_jumps_.append(masm.pc());
1.95 + } else {
1.96 + __ j(cc, target);
1.97 + }
1.98 break;
1.99 }
1.100
1.101 @@ -1256,7 +1279,12 @@
1.102 return false;
1.103 ConditionCode cc = OpToCondition(op);
1.104 __ cmpl(pri, alt);
1.105 - __ j(cc, target);
1.106 + if (target->bound()) {
1.107 + __ j32(cc, target);
1.108 + backward_jumps_.append(masm.pc());
1.109 + } else {
1.110 + __ j(cc, target);
1.111 + }
1.112 break;
1.113 }
1.114
1.115 @@ -1755,7 +1783,7 @@
1.116 typedef int (*JIT_EXECUTE)(sp_context_t *ctx, uint8_t *memory, void *code);
1.117
1.118 static void *
1.119 -GenerateEntry(void **retp)
1.120 +GenerateEntry(void **retp, void **timeoutp)
1.121 {
1.122 AssemblerX86 masm;
1.123
1.124 @@ -1813,11 +1841,17 @@
1.125 __ movl(ecx, Operand(ebp, 8 + 4 * 0)); // ret-path expects ecx = ctx
1.126 __ jmp(&ret);
1.127
1.128 + Label timeout;
1.129 + __ bind(&timeout);
1.130 + __ movl(eax, SP_ERROR_TIMEOUT);
1.131 + __ jmp(&error);
1.132 +
1.133 void *code = LinkCode(masm);
1.134 if (!code)
1.135 return NULL;
1.136
1.137 *retp = reinterpret_cast<uint8_t *>(code) + error.offset();
1.138 + *timeoutp = reinterpret_cast<uint8_t *>(code) + timeout.offset();
1.139 return code;
1.140 }
1.141
1.142 @@ -1841,11 +1875,12 @@
1.143 m_pJitEntry = NULL;
1.144 }
1.145
1.146 -bool JITX86::InitializeJIT()
1.147 +bool
1.148 +JITX86::InitializeJIT()
1.149 {
1.150 g_pCodeCache = KE_CreateCodeCache();
1.151
1.152 - m_pJitEntry = GenerateEntry(&m_pJitReturn);
1.153 + m_pJitEntry = GenerateEntry(&m_pJitReturn, &m_pJitTimeout);
1.154 if (!m_pJitEntry)
1.155 return false;
1.156
1.157 @@ -1873,6 +1908,11 @@
1.158 JitFunction *fun = cc.emit(err);
1.159 if (!fun)
1.160 return NULL;
1.161 +
1.162 + // Grab the lock before linking code in, since the watchdog timer will look
1.163 + // at this list on another thread.
1.164 + ke::AutoLock lock(g_Jit.Mutex());
1.165 +
1.166 prt->AddJittedFunction(fun);
1.167 return fun;
1.168 }
1.169 @@ -1919,33 +1959,39 @@
1.170 return (SPVM_NATIVE_FUNC)LinkCode(masm);
1.171 }
1.172
1.173 -void JITX86::DestroyFakeNative(SPVM_NATIVE_FUNC func)
1.174 +void
1.175 +JITX86::DestroyFakeNative(SPVM_NATIVE_FUNC func)
1.176 {
1.177 KE_FreeCode(g_pCodeCache, (void *)func);
1.178 }
1.179
1.180 -ICompilation *JITX86::StartCompilation()
1.181 +ICompilation *
1.182 +JITX86::StartCompilation()
1.183 {
1.184 return new CompData;
1.185 }
1.186
1.187 -ICompilation *JITX86::StartCompilation(BaseRuntime *runtime)
1.188 +ICompilation *
1.189 +JITX86::StartCompilation(BaseRuntime *runtime)
1.190 {
1.191 return new CompData;
1.192 }
1.193
1.194 -void CompData::Abort()
1.195 +void
1.196 +CompData::Abort()
1.197 {
1.198 delete this;
1.199 }
1.200
1.201 -void JITX86::FreeContextVars(sp_context_t *ctx)
1.202 +void
1.203 +JITX86::FreeContextVars(sp_context_t *ctx)
1.204 {
1.205 free(((tracker_t *)(ctx->vm[JITVARS_TRACKER]))->pBase);
1.206 delete (tracker_t *)ctx->vm[JITVARS_TRACKER];
1.207 }
1.208
1.209 -bool CompData::SetOption(const char *key, const char *val)
1.210 +bool
1.211 +CompData::SetOption(const char *key, const char *val)
1.212 {
1.213 if (strcmp(key, SP_JITCONF_DEBUG) == 0)
1.214 return true;
1.215 @@ -1962,7 +2008,8 @@
1.216 return false;
1.217 }
1.218
1.219 -int JITX86::InvokeFunction(BaseRuntime *runtime, JitFunction *fn, cell_t *result)
1.220 +int
1.221 +JITX86::InvokeFunction(BaseRuntime *runtime, JitFunction *fn, cell_t *result)
1.222 {
1.223 sp_context_t *ctx = runtime->GetBaseContext()->GetCtx();
1.224
1.225 @@ -1970,18 +2017,75 @@
1.226 ctx->cip = fn->GetPCodeAddress();
1.227
1.228 JIT_EXECUTE pfn = (JIT_EXECUTE)m_pJitEntry;
1.229 +
1.230 + if (level_++ == 0)
1.231 + frame_id_++;
1.232 int err = pfn(ctx, runtime->plugin()->memory, fn->GetEntryAddress());
1.233 + level_--;
1.234
1.235 *result = ctx->rval;
1.236 return err;
1.237 }
1.238
1.239 -void *JITX86::AllocCode(size_t size)
1.240 +void *
1.241 +JITX86::AllocCode(size_t size)
1.242 {
1.243 return Knight::KE_AllocCode(g_pCodeCache, size);
1.244 }
1.245
1.246 -void JITX86::FreeCode(void *code)
1.247 +void
1.248 +JITX86::FreeCode(void *code)
1.249 {
1.250 KE_FreeCode(g_pCodeCache, code);
1.251 }
1.252 +
1.253 +void
1.254 +JITX86::RegisterRuntime(BaseRuntime *rt)
1.255 +{
1.256 + mutex_.AssertCurrentThreadOwns();
1.257 + runtimes_.insert(rt);
1.258 +}
1.259 +
1.260 +void
1.261 +JITX86::DeregisterRuntime(BaseRuntime *rt)
1.262 +{
1.263 + mutex_.AssertCurrentThreadOwns();
1.264 + runtimes_.erase(rt);
1.265 +}
1.266 +
1.267 +void
1.268 +JITX86::PatchAllJumpsForTimeout()
1.269 +{
1.270 + mutex_.AssertCurrentThreadOwns();
1.271 + for (InlineList<BaseRuntime>::iterator iter = runtimes_.begin(); iter != runtimes_.end(); iter++) {
1.272 + BaseRuntime *rt = *iter;
1.273 + for (size_t i = 0; i < rt->NumJitFunctions(); i++) {
1.274 + JitFunction *fun = rt->GetJitFunction(i);
1.275 + uint8_t *base = reinterpret_cast<uint8_t *>(fun->GetEntryAddress());
1.276 +
1.277 + for (size_t j = 0; j < fun->NumLoopEdges(); j++) {
1.278 + const LoopEdge &e = fun->GetLoopEdge(j);
1.279 + int32_t diff = intptr_t(m_pJitTimeout) - intptr_t(base + e.offset);
1.280 + *reinterpret_cast<int32_t *>(base + e.offset - 4) = diff;
1.281 + }
1.282 + }
1.283 + }
1.284 +}
1.285 +
1.286 +void
1.287 +JITX86::UnpatchAllJumpsFromTimeout()
1.288 +{
1.289 + mutex_.AssertCurrentThreadOwns();
1.290 + for (InlineList<BaseRuntime>::iterator iter = runtimes_.begin(); iter != runtimes_.end(); iter++) {
1.291 + BaseRuntime *rt = *iter;
1.292 + for (size_t i = 0; i < rt->NumJitFunctions(); i++) {
1.293 + JitFunction *fun = rt->GetJitFunction(i);
1.294 + uint8_t *base = reinterpret_cast<uint8_t *>(fun->GetEntryAddress());
1.295 +
1.296 + for (size_t j = 0; j < fun->NumLoopEdges(); j++) {
1.297 + const LoopEdge &e = fun->GetLoopEdge(j);
1.298 + *reinterpret_cast<int32_t *>(base + e.offset - 4) = e.disp32;
1.299 + }
1.300 + }
1.301 + }
1.302 +}