sourcepawn/jit/x86/jit_x86.cpp
changeset 4013 6201c1180e0e
parent 3993 d06d6dacfa18
child 4022 9c0a32892063
     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 +}