210 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			210 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
// 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_JIT_X86_H_
 | 
						|
#define _INCLUDE_SOURCEPAWN_JIT_X86_H_
 | 
						|
 | 
						|
#include <sp_vm_types.h>
 | 
						|
#include <sp_vm_api.h>
 | 
						|
#include <KeCodeAllocator.h>
 | 
						|
#include <macro-assembler-x86.h>
 | 
						|
#include <am-vector.h>
 | 
						|
#include "jit_shared.h"
 | 
						|
#include "BaseRuntime.h"
 | 
						|
#include "sp_vm_basecontext.h"
 | 
						|
#include "jit_function.h"
 | 
						|
#include "opcodes.h"
 | 
						|
#include <am-thread-utils.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 JITVARS_PROFILER        2    //profiler
 | 
						|
 | 
						|
#define sDIMEN_MAX              5    //this must mirror what the compiler has.
 | 
						|
 | 
						|
typedef struct funcinfo_s
 | 
						|
{
 | 
						|
  unsigned int magic;
 | 
						|
  unsigned int index;
 | 
						|
} funcinfo_t;
 | 
						|
 | 
						|
typedef struct functracker_s
 | 
						|
{
 | 
						|
  unsigned int num_functions;
 | 
						|
  unsigned int code_size;
 | 
						|
} functracker_t;
 | 
						|
 | 
						|
struct CallThunk
 | 
						|
{
 | 
						|
  Label call;
 | 
						|
  cell_t pcode_offset;
 | 
						|
 | 
						|
  CallThunk(cell_t pcode_offset)
 | 
						|
    : pcode_offset(pcode_offset)
 | 
						|
  {
 | 
						|
  }
 | 
						|
};
 | 
						|
 | 
						|
class CompData : public ICompilation
 | 
						|
{
 | 
						|
public:
 | 
						|
  CompData() 
 | 
						|
  : profile(0),
 | 
						|
    inline_level(0)
 | 
						|
  {
 | 
						|
  };
 | 
						|
  bool SetOption(const char *key, const char *val);
 | 
						|
  void Abort();
 | 
						|
public:
 | 
						|
  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();
 | 
						|
 | 
						|
  ExternalAddress cipAddr() {
 | 
						|
    sp_context_t *ctx = rt_->GetBaseContext()->GetCtx();
 | 
						|
    return ExternalAddress(&ctx->cip);
 | 
						|
  }
 | 
						|
  ExternalAddress hpAddr() {
 | 
						|
    sp_context_t *ctx = rt_->GetBaseContext()->GetCtx();
 | 
						|
    return ExternalAddress(&ctx->hp);
 | 
						|
  }
 | 
						|
  ExternalAddress frmAddr() {
 | 
						|
    sp_context_t *ctx = rt_->GetBaseContext()->GetCtx();
 | 
						|
    return ExternalAddress(&ctx->frm);
 | 
						|
  }
 | 
						|
 | 
						|
 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_;
 | 
						|
  ke::Vector<size_t> backward_jumps_;
 | 
						|
 | 
						|
  // Errors
 | 
						|
  Label error_bounds_;
 | 
						|
  Label error_heap_low_;
 | 
						|
  Label error_heap_min_;
 | 
						|
  Label error_stack_low_;
 | 
						|
  Label error_stack_min_;
 | 
						|
  Label error_divide_by_zero_;
 | 
						|
  Label error_memaccess_;
 | 
						|
  Label error_integer_overflow_;
 | 
						|
  Label extern_error_;
 | 
						|
 | 
						|
  ke::Vector<CallThunk *> thunks_; //:TODO: free
 | 
						|
};
 | 
						|
 | 
						|
class JITX86
 | 
						|
{
 | 
						|
 public:
 | 
						|
  JITX86();
 | 
						|
 | 
						|
 public:
 | 
						|
  bool InitializeJIT();
 | 
						|
  void ShutdownJIT();
 | 
						|
  ICompilation *StartCompilation(BaseRuntime *runtime);
 | 
						|
  ICompilation *StartCompilation();
 | 
						|
  void SetupContextVars(BaseRuntime *runtime, BaseContext *pCtx, sp_context_t *ctx);
 | 
						|
  void FreeContextVars(sp_context_t *ctx);
 | 
						|
  SPVM_NATIVE_FUNC CreateFakeNative(SPVM_FAKENATIVE_FUNC callback, void *pData);
 | 
						|
  void DestroyFakeNative(SPVM_NATIVE_FUNC func);
 | 
						|
  JitFunction *CompileFunction(BaseRuntime *runtime, cell_t pcode_offs, int *err);
 | 
						|
  ICompilation *ApplyOptions(ICompilation *_IN, ICompilation *_OUT);
 | 
						|
  int InvokeFunction(BaseRuntime *runtime, JitFunction *fn, cell_t *result);
 | 
						|
 | 
						|
  void RegisterRuntime(BaseRuntime *rt);
 | 
						|
  void DeregisterRuntime(BaseRuntime *rt);
 | 
						|
  void PatchAllJumpsForTimeout();
 | 
						|
  void UnpatchAllJumpsFromTimeout();
 | 
						|
  
 | 
						|
 public:
 | 
						|
  ExternalAddress GetUniversalReturn() {
 | 
						|
    return ExternalAddress(m_pJitReturn);
 | 
						|
  }
 | 
						|
  void *AllocCode(size_t size);
 | 
						|
  void FreeCode(void *code);
 | 
						|
 | 
						|
  uintptr_t FrameId() const {
 | 
						|
    return frame_id_;
 | 
						|
  }
 | 
						|
  bool RunningCode() const {
 | 
						|
    return level_ != 0;
 | 
						|
  }
 | 
						|
  ke::Mutex *Mutex() {
 | 
						|
    return &mutex_;
 | 
						|
  }
 | 
						|
 | 
						|
 private:
 | 
						|
  void *m_pJitEntry;         /* Entry function */
 | 
						|
  void *m_pJitReturn;        /* Universal return address */
 | 
						|
  void *m_pJitTimeout;       /* Universal timeout address */
 | 
						|
  ke::InlineList<BaseRuntime> runtimes_;
 | 
						|
  uintptr_t frame_id_;
 | 
						|
  uintptr_t level_;
 | 
						|
  ke::Mutex mutex_;
 | 
						|
};
 | 
						|
 | 
						|
const Register pri = eax;
 | 
						|
const Register alt = edx;
 | 
						|
const Register stk = edi;
 | 
						|
const Register dat = esi;
 | 
						|
const Register tmp = ecx;
 | 
						|
const Register frm = ebx;
 | 
						|
 | 
						|
extern Knight::KeCodeCache *g_pCodeCache;
 | 
						|
extern JITX86 g_Jit;
 | 
						|
 | 
						|
#endif //_INCLUDE_SOURCEPAWN_JIT_X86_H_
 | 
						|
 |