Fabcoin Core  0.16.2
P2P Digital Currency
Cache.cpp
Go to the documentation of this file.
1 #include "Cache.h"
2 
3 #include <mutex>
4 
6 #include <llvm/IR/Module.h>
7 #include <llvm/IR/LLVMContext.h>
8 #include <llvm/IR/Instructions.h>
9 #include <llvm/ExecutionEngine/ExecutionEngine.h>
10 #include <llvm/Support/Path.h>
11 #include <llvm/Support/FileSystem.h>
12 #include <llvm/Support/raw_os_ostream.h>
14 
15 #include "ExecStats.h"
16 #include "Utils.h"
17 
18 namespace dev
19 {
20 namespace evmjit
21 {
22 
23 namespace
24 {
28  const auto c_internalABIVersion = 4;
29 
30  using Guard = std::lock_guard<std::mutex>;
31  std::mutex x_cacheMutex;
32  CacheMode g_mode;
33  std::unique_ptr<llvm::MemoryBuffer> g_lastObject;
34  JITListener* g_listener;
35 
36  std::string getVersionedCacheDir()
37  {
38  llvm::SmallString<256> path;
39  llvm::sys::path::user_cache_directory(path, "ethereum", "evmjit",
40  std::to_string(c_internalABIVersion));
41  return path.str();
42  }
43 
44 }
45 
47 {
48  DLOG(cache) << "Cache dir: " << getVersionedCacheDir() << "\n";
49 
50  Guard g{x_cacheMutex};
51 
52  g_mode = _mode;
53  g_listener = _listener;
54 
55  if (g_mode == CacheMode::clear)
56  {
57  Cache::clear();
58  g_mode = CacheMode::off;
59  }
60 
61  if (g_mode != CacheMode::off)
62  {
63  static ObjectCache objectCache;
64  return &objectCache;
65  }
66  return nullptr;
67 }
68 
70 {
71  Guard g{x_cacheMutex};
72 
73  auto cachePath = getVersionedCacheDir();
74  std::error_code err;
75  for (auto it = llvm::sys::fs::directory_iterator{cachePath, err}; it != decltype(it){}; it.increment(err))
76  llvm::sys::fs::remove(it->path());
77 }
78 
79 void Cache::preload(llvm::ExecutionEngine& _ee, std::unordered_map<std::string, uint64_t>& _funcCache,
80  llvm::LLVMContext& _llvmContext)
81 {
82  Guard g{x_cacheMutex};
83 
84  // Disable listener
85  auto listener = g_listener;
86  g_listener = nullptr;
87 
88  auto cachePath = getVersionedCacheDir();
89  std::error_code err;
90  for (auto it = llvm::sys::fs::directory_iterator{cachePath, err}; it != decltype(it){}; it.increment(err))
91  {
92  auto name = it->path().substr(cachePath.size() + 1);
93  if (auto module = getObject(name, _llvmContext))
94  {
95  DLOG(cache) << "Preload: " << name << "\n";
96  _ee.addModule(std::move(module));
97  auto addr = _ee.getFunctionAddress(name);
98  assert(addr);
99  _funcCache[std::move(name)] = addr;
100  }
101  }
102 
103  g_listener = listener;
104 }
105 
106 std::unique_ptr<llvm::Module> Cache::getObject(std::string const& id, llvm::LLVMContext& _llvmContext)
107 {
108  Guard g{x_cacheMutex};
109 
110  if (g_mode != CacheMode::on && g_mode != CacheMode::read)
111  return nullptr;
112 
113  // TODO: Disabled because is not thread-safe.
114  //if (g_listener)
115  // g_listener->stateChanged(ExecState::CacheLoad);
116 
117  DLOG(cache) << id << ": search\n";
118  if (!CHECK(!g_lastObject))
119  g_lastObject = nullptr;
120 
121  llvm::SmallString<256> cachePath{getVersionedCacheDir()};
122  llvm::sys::path::append(cachePath, id);
123 
124  if (auto r = llvm::MemoryBuffer::getFile(cachePath, -1, false))
125  g_lastObject = llvm::MemoryBuffer::getMemBufferCopy(r.get()->getBuffer());
126  else if (r.getError() != std::make_error_code(std::errc::no_such_file_or_directory))
127  DLOG(cache) << r.getError().message(); // TODO: Add warning log
128 
129  if (g_lastObject) // if object found create fake module
130  {
131  DLOG(cache) << id << ": found\n";
132  auto module = llvm::make_unique<llvm::Module>(id, _llvmContext);
133  auto mainFuncType = llvm::FunctionType::get(llvm::Type::getVoidTy(_llvmContext), {}, false);
134  auto mainFunc = llvm::Function::Create(mainFuncType, llvm::Function::ExternalLinkage, id, module.get());
135  auto bb = llvm::BasicBlock::Create(_llvmContext, {}, mainFunc);
136  bb->getInstList().push_back(new llvm::UnreachableInst{_llvmContext});
137  return module;
138  }
139  DLOG(cache) << id << ": not found\n";
140  return nullptr;
141 }
142 
143 
144 void ObjectCache::notifyObjectCompiled(llvm::Module const* _module, llvm::MemoryBufferRef _object)
145 {
146  Guard g{x_cacheMutex};
147 
148  // Only in "on" and "write" mode
149  if (g_mode != CacheMode::on && g_mode != CacheMode::write)
150  return;
151 
152  // TODO: Disabled because is not thread-safe.
153  // if (g_listener)
154  // g_listener->stateChanged(ExecState::CacheWrite);
155 
156  auto&& id = _module->getModuleIdentifier();
157  llvm::SmallString<256> cachePath{getVersionedCacheDir()};
158  if (auto err = llvm::sys::fs::create_directories(cachePath))
159  {
160  DLOG(cache) << "Cannot create cache dir " << cachePath.str().str() << " (error: " << err.message() << "\n";
161  return;
162  }
163 
164  llvm::sys::path::append(cachePath, id);
165 
166  DLOG(cache) << id << ": write\n";
167  std::error_code error;
168  llvm::raw_fd_ostream cacheFile(cachePath, error, llvm::sys::fs::F_None);
169  cacheFile << _object.getBuffer();
170 }
171 
172 std::unique_ptr<llvm::MemoryBuffer> ObjectCache::getObject(llvm::Module const* _module)
173 {
174  Guard g{x_cacheMutex};
175 
176  DLOG(cache) << _module->getModuleIdentifier() << ": use\n";
177  return std::move(g_lastObject);
178 }
179 
180 }
181 }
#define CHECK(expr)
Definition: Utils.h:12
Adapted from code found on http://stackoverflow.com/questions/180947/base64-decode-snippet-in-c Origi...
Definition: Arith256.cpp:15
bool error(const char *fmt, const Args &...args)
Definition: util.h:178
static void preload(llvm::ExecutionEngine &_ee, std::unordered_map< std::string, uint64_t > &_funcCache, llvm::LLVMContext &_llvmContext)
Loads all available cached objects to ExecutionEngine.
Definition: Cache.cpp:79
#define g(i)
Definition: sha.cpp:735
#define DLOG(CHANNEL)
Definition: Utils.h:18
virtual std::unique_ptr< llvm::MemoryBuffer > getObject(llvm::Module const *_module) finaloverride
getObjectCopy - Returns a pointer to a newly allocated MemoryBuffer that contains the object which co...
Definition: Cache.cpp:172
assert(len-trim+(2 *lenIndices)<=WIDTH)
static void clear()
Clears cache storage.
Definition: Cache.cpp:69
static std::unique_ptr< llvm::Module > getObject(std::string const &id, llvm::LLVMContext &_llvmContext)
Definition: Cache.cpp:106
std::lock_guard< std::mutex > Guard
Definition: Guards.h:41
const char * name
Definition: rest.cpp:36
static ObjectCache * init(CacheMode _mode, JITListener *_listener)
Definition: Cache.cpp:46
virtual void notifyObjectCompiled(llvm::Module const *_module, llvm::MemoryBufferRef _object) finaloverride
notifyObjectCompiled - Provides a pointer to compiled code for Module M.
Definition: Cache.cpp:144