JitCache.cs 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. using ARMeilleure.CodeGen;
  2. using ARMeilleure.Memory;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Runtime.InteropServices;
  6. namespace ARMeilleure.Translation
  7. {
  8. static class JitCache
  9. {
  10. private const int PageSize = 4 * 1024;
  11. private const int PageMask = PageSize - 1;
  12. private const int CodeAlignment = 4; // Bytes
  13. private const int CacheSize = 512 * 1024 * 1024;
  14. private static IntPtr _basePointer;
  15. private static int _offset;
  16. private static List<JitCacheEntry> _cacheEntries;
  17. private static object _lock;
  18. static JitCache()
  19. {
  20. _basePointer = MemoryManagement.Allocate(CacheSize);
  21. if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
  22. {
  23. JitUnwindWindows.InstallFunctionTableHandler(_basePointer, CacheSize);
  24. // The first page is used for the table based SEH structs.
  25. _offset = PageSize;
  26. }
  27. _cacheEntries = new List<JitCacheEntry>();
  28. _lock = new object();
  29. }
  30. public static IntPtr Map(CompiledFunction func)
  31. {
  32. byte[] code = func.Code;
  33. lock (_lock)
  34. {
  35. int funcOffset = Allocate(code.Length);
  36. IntPtr funcPtr = _basePointer + funcOffset;
  37. Marshal.Copy(code, 0, funcPtr, code.Length);
  38. ReprotectRange(funcOffset, code.Length);
  39. Add(new JitCacheEntry(funcOffset, code.Length, func.UnwindInfo));
  40. return funcPtr;
  41. }
  42. }
  43. private static void ReprotectRange(int offset, int size)
  44. {
  45. // Map pages that are already full as RX.
  46. // Map pages that are not full yet as RWX.
  47. // On unix, the address must be page aligned.
  48. int endOffs = offset + size;
  49. int pageStart = offset & ~PageMask;
  50. int pageEnd = endOffs & ~PageMask;
  51. int fullPagesSize = pageEnd - pageStart;
  52. if (fullPagesSize != 0)
  53. {
  54. IntPtr funcPtr = _basePointer + pageStart;
  55. MemoryManagement.Reprotect(funcPtr, (ulong)fullPagesSize, MemoryProtection.ReadAndExecute);
  56. }
  57. int remaining = endOffs - pageEnd;
  58. if (remaining != 0)
  59. {
  60. IntPtr funcPtr = _basePointer + pageEnd;
  61. MemoryManagement.Reprotect(funcPtr, (ulong)remaining, MemoryProtection.ReadWriteExecute);
  62. }
  63. }
  64. private static int Allocate(int codeSize)
  65. {
  66. codeSize = checked(codeSize + (CodeAlignment - 1)) & ~(CodeAlignment - 1);
  67. int allocOffset = _offset;
  68. _offset += codeSize;
  69. if ((ulong)(uint)_offset > CacheSize)
  70. {
  71. throw new OutOfMemoryException();
  72. }
  73. return allocOffset;
  74. }
  75. private static void Add(JitCacheEntry entry)
  76. {
  77. _cacheEntries.Add(entry);
  78. }
  79. public static bool TryFind(int offset, out JitCacheEntry entry)
  80. {
  81. lock (_lock)
  82. {
  83. foreach (JitCacheEntry cacheEntry in _cacheEntries)
  84. {
  85. int endOffset = cacheEntry.Offset + cacheEntry.Size;
  86. if (offset >= cacheEntry.Offset && offset < endOffset)
  87. {
  88. entry = cacheEntry;
  89. return true;
  90. }
  91. }
  92. }
  93. entry = default(JitCacheEntry);
  94. return false;
  95. }
  96. }
  97. }