Browse Source

Merge pull request #2374 from chfast/pr/smartvm

Smart VM
cl-refactor
Gav Wood 10 years ago
parent
commit
7e3fe9bb68
  1. 3
      CodingStandards.txt
  2. 42
      alethzero/Main.ui
  3. 54
      alethzero/MainWin.cpp
  4. 9
      alethzero/MainWin.h
  5. 22
      eth/main.cpp
  6. 22
      ethvm/main.cpp
  7. 7
      evmjit/include/evmjit/JIT.h
  8. 92
      evmjit/libevmjit/JIT.cpp
  9. 82
      libevm/SmartVM.cpp
  10. 26
      neth/main.cpp
  11. 20
      test/TestHelper.cpp

3
CodingStandards.txt

@ -196,7 +196,7 @@ a. Prefer 'using' to 'typedef'. e.g. using ints = std::vector<int>; rather than
b. Generally avoid shortening a standard form that already includes all important information: b. Generally avoid shortening a standard form that already includes all important information:
- e.g. stick to shared_ptr<X> rather than shortening to ptr<X>. - e.g. stick to shared_ptr<X> rather than shortening to ptr<X>.
c. Where there are exceptions to this (due to excessive use and clear meaning), note the change prominently and use it consistently. c. Where there are exceptions to this (due to excessive use and clear meaning), note the change prominently and use it consistently.
- e.g. using Guard = boost::lock_guard<std::mutex>; ///< Guard is used throughout the codebase since it's clear in meaning and used commonly. - e.g. using Guard = std::lock_guard<std::mutex>; ///< Guard is used throughout the codebase since it's clear in meaning and used commonly.
d. In general expressions should be roughly as important/semantically meaningful as the space they occupy. d. In general expressions should be roughly as important/semantically meaningful as the space they occupy.
@ -226,4 +226,3 @@ a. Includes should go in order of lower level (STL -> boost -> libdevcore -> lib
#include <libethereum/Defaults.h> #include <libethereum/Defaults.h>
b. The only exception to the above rule is the top of a .cpp file where its corresponding header should be located. b. The only exception to the above rule is the top of a .cpp file where its corresponding header should be located.

42
alethzero/Main.ui

@ -132,7 +132,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>1617</width> <width>1617</width>
<height>24</height> <height>25</height>
</rect> </rect>
</property> </property>
<widget class="QMenu" name="menu_File"> <widget class="QMenu" name="menu_File">
@ -192,8 +192,11 @@
<addaction name="injectBlock"/> <addaction name="injectBlock"/>
<addaction name="forceMining"/> <addaction name="forceMining"/>
<addaction name="separator"/> <addaction name="separator"/>
<addaction name="vmInterpreter"/>
<addaction name="vmJIT"/>
<addaction name="vmSmart"/>
<addaction name="separator"/>
<addaction name="usePrivate"/> <addaction name="usePrivate"/>
<addaction name="jitvm"/>
<addaction name="retryUnknown"/> <addaction name="retryUnknown"/>
<addaction name="confirm"/> <addaction name="confirm"/>
</widget> </widget>
@ -1697,17 +1700,6 @@ font-size: 14pt</string>
<string>&amp;Clear Pending</string> <string>&amp;Clear Pending</string>
</property> </property>
</action> </action>
<action name="jitvm">
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>false</bool>
</property>
<property name="text">
<string>Use &amp;LLVM-EVM</string>
</property>
</action>
<action name="killAccount"> <action name="killAccount">
<property name="text"> <property name="text">
<string>&amp;Kill Account</string> <string>&amp;Kill Account</string>
@ -1783,6 +1775,30 @@ font-size: 14pt</string>
<string>&amp;Gas Prices...</string> <string>&amp;Gas Prices...</string>
</property> </property>
</action> </action>
<action name="vmInterpreter">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Interpreter</string>
</property>
</action>
<action name="vmJIT">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>JIT</string>
</property>
</action>
<action name="vmSmart">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Smart</string>
</property>
</action>
<action name="sentinel"> <action name="sentinel">
<property name="text"> <property name="text">
<string>&amp;Sentinel...</string> <string>&amp;Sentinel...</string>

54
alethzero/MainWin.cpp

@ -239,6 +239,21 @@ Main::Main(QWidget *parent) :
ethereum()->setDefault(LatestBlock); ethereum()->setDefault(LatestBlock);
m_vmSelectionGroup = new QActionGroup{ui->menu_Debug};
m_vmSelectionGroup->addAction(ui->vmInterpreter);
m_vmSelectionGroup->addAction(ui->vmJIT);
m_vmSelectionGroup->addAction(ui->vmSmart);
m_vmSelectionGroup->setExclusive(true);
#if ETH_EVMJIT
ui->vmSmart->setChecked(true); // Default when JIT enabled
on_vmSmart_triggered();
#else
ui->vmInterpreter->setChecked(true);
ui->vmJIT->setEnabled(false);
ui->vmSmart->setEnabled(false);
#endif
readSettings(); readSettings();
m_transact = new Transact(this, this); m_transact = new Transact(this, this);
@ -247,10 +262,6 @@ Main::Main(QWidget *parent) :
#if !ETH_FATDB #if !ETH_FATDB
removeDockWidget(ui->dockWidget_accounts); removeDockWidget(ui->dockWidget_accounts);
#endif
#if !ETH_EVMJIT
ui->jitvm->setEnabled(false);
ui->jitvm->setChecked(false);
#endif #endif
installWatches(); installWatches();
startTimer(100); startTimer(100);
@ -731,7 +742,8 @@ void Main::writeSettings()
s.setValue("url", ui->urlEdit->text()); s.setValue("url", ui->urlEdit->text());
s.setValue("privateChain", m_privateChain); s.setValue("privateChain", m_privateChain);
s.setValue("verbosity", ui->verbosity->value()); s.setValue("verbosity", ui->verbosity->value());
s.setValue("jitvm", ui->jitvm->isChecked()); if (auto vm = m_vmSelectionGroup->checkedAction())
s.setValue("vm", vm->text());
bytes d = m_webThree->saveNetwork(); bytes d = m_webThree->saveNetwork();
if (!d.empty()) if (!d.empty())
@ -822,8 +834,28 @@ void Main::readSettings(bool _skipGeometry)
m_privateChain = s.value("privateChain", "").toString(); m_privateChain = s.value("privateChain", "").toString();
ui->usePrivate->setChecked(m_privateChain.size()); ui->usePrivate->setChecked(m_privateChain.size());
ui->verbosity->setValue(s.value("verbosity", 1).toInt()); ui->verbosity->setValue(s.value("verbosity", 1).toInt());
ui->jitvm->setChecked(s.value("jitvm", true).toBool());
on_jitvm_triggered(); #if ETH_EVMJIT // We care only if JIT is enabled. Otherwise it can cause misconfiguration.
auto vmName = s.value("vm").toString();
if (!vmName.isEmpty())
{
if (vmName == ui->vmInterpreter->text())
{
ui->vmInterpreter->setChecked(true);
on_vmInterpreter_triggered();
}
else if (vmName == ui->vmJIT->text())
{
ui->vmJIT->setChecked(true);
on_vmJIT_triggered();
}
else if (vmName == ui->vmSmart->text())
{
ui->vmSmart->setChecked(true);
on_vmSmart_triggered();
}
}
#endif
ui->urlEdit->setText(s.value("url", "about:blank").toString()); //http://gavwood.com/gavcoin.html ui->urlEdit->setText(s.value("url", "about:blank").toString()); //http://gavwood.com/gavcoin.html
on_urlEdit_returnPressed(); on_urlEdit_returnPressed();
@ -1000,11 +1032,9 @@ void Main::on_usePrivate_triggered()
on_killBlockchain_triggered(); on_killBlockchain_triggered();
} }
void Main::on_jitvm_triggered() void Main::on_vmInterpreter_triggered() { VMFactory::setKind(VMKind::Interpreter); }
{ void Main::on_vmJIT_triggered() { VMFactory::setKind(VMKind::JIT); }
bool jit = ui->jitvm->isChecked(); void Main::on_vmSmart_triggered() { VMFactory::setKind(VMKind::Smart); }
VMFactory::setKind(jit ? VMKind::JIT : VMKind::Interpreter);
}
void Main::on_urlEdit_returnPressed() void Main::on_urlEdit_returnPressed()
{ {

9
alethzero/MainWin.h

@ -44,6 +44,7 @@
#include "Connect.h" #include "Connect.h"
class QListWidgetItem; class QListWidgetItem;
class QActionGroup;
namespace Ui { namespace Ui {
class Main; class Main;
@ -182,8 +183,10 @@ private slots:
void on_forceMining_triggered(); void on_forceMining_triggered();
void on_usePrivate_triggered(); void on_usePrivate_triggered();
void on_turboMining_triggered(); void on_turboMining_triggered();
void on_jitvm_triggered();
void on_retryUnknown_triggered(); void on_retryUnknown_triggered();
void on_vmInterpreter_triggered();
void on_vmJIT_triggered();
void on_vmSmart_triggered();
// Debugger // Debugger
void on_debugCurrent_triggered(); void on_debugCurrent_triggered();
@ -272,6 +275,8 @@ private:
dev::Address m_nameReg; dev::Address m_nameReg;
dev::Address m_beneficiary; dev::Address m_beneficiary;
QActionGroup* m_vmSelectionGroup = nullptr;
QList<QPair<QString, QString>> m_consoleHistory; QList<QPair<QString, QString>> m_consoleHistory;
QMutex m_logLock; QMutex m_logLock;
QString m_logHistory; QString m_logHistory;
@ -287,6 +292,6 @@ private:
std::unique_ptr<DappHost> m_dappHost; std::unique_ptr<DappHost> m_dappHost;
DappLoader* m_dappLoader; DappLoader* m_dappLoader;
QWebEnginePage* m_webPage; QWebEnginePage* m_webPage;
Connect m_connect; Connect m_connect;
}; };

22
eth/main.cpp

@ -194,7 +194,7 @@ void help()
<< "General Options:" << endl << "General Options:" << endl
<< " -d,--db-path <path> Load database from path (default: " << getDataDir() << ")" << endl << " -d,--db-path <path> Load database from path (default: " << getDataDir() << ")" << endl
#if ETH_EVMJIT || !ETH_TRUE #if ETH_EVMJIT || !ETH_TRUE
<< " -J,--jit Enable EVM JIT (default: off)." << endl << " --vm <vm-kind> Select VM. Options are: interpreter, jit, smart. (default: interpreter)" << endl
#endif #endif
<< " -v,--verbosity <0 - 9> Set the log verbosity from 0 to 9 (default: 8)." << endl << " -v,--verbosity <0 - 9> Set the log verbosity from 0 to 9 (default: 8)." << endl
<< " -V,--version Show the version and exit." << endl << " -V,--version Show the version and exit." << endl
@ -1441,8 +1441,21 @@ int main(int argc, char** argv)
} }
} }
#if ETH_EVMJIT #if ETH_EVMJIT
else if (arg == "-J" || arg == "--jit") else if (arg == "--vm" && i + 1 < argc)
jit = true; {
string vmKind = argv[++i];
if (vmKind == "interpreter")
VMFactory::setKind(VMKind::Interpreter);
else if (vmKind == "jit")
VMFactory::setKind(VMKind::JIT);
else if (vmKind == "smart")
VMFactory::setKind(VMKind::Smart);
else
{
cerr << "Unknown VM kind: " << vmKind << endl;
return -1;
}
}
#endif #endif
else if (arg == "-h" || arg == "--help") else if (arg == "-h" || arg == "--help")
help(); help();
@ -1479,7 +1492,7 @@ int main(int argc, char** argv)
g_logPost = [&](std::string const& a, char const*){ g_logPost = [&](std::string const& a, char const*){
static SpinLock s_lock; static SpinLock s_lock;
SpinGuard l(s_lock); SpinGuard l(s_lock);
if (g_silence) if (g_silence)
logbuf += a + "\n"; logbuf += a + "\n";
else else
@ -1764,4 +1777,3 @@ int main(int argc, char** argv)
writeFile((dbPath.size() ? dbPath : getDataDir()) + "/network.rlp", netData); writeFile((dbPath.size() ? dbPath : getDataDir()) + "/network.rlp", netData);
return 0; return 0;
} }

22
ethvm/main.cpp

@ -46,8 +46,7 @@ void help()
#if ETH_EVMJIT || !ETH_TRUE #if ETH_EVMJIT || !ETH_TRUE
<< endl << endl
<< "VM options:" << endl << "VM options:" << endl
<< " -J,--jit Enable LLVM VM (default: off)." << endl << " --vm <vm-kind> Select VM. Options are: interpreter, jit, smart. (default: interpreter)" << endl
<< " --smart Enable smart VM (default: off)." << endl
#endif #endif
<< endl << endl
<< "Options for trace:" << endl << "Options for trace:" << endl
@ -97,10 +96,21 @@ int main(int argc, char** argv)
else if (arg == "-V" || arg == "--version") else if (arg == "-V" || arg == "--version")
version(); version();
#if ETH_EVMJIT #if ETH_EVMJIT
else if (arg == "-J" || arg == "--jit") else if (arg == "--vm" && i + 1 < argc)
VMFactory::setKind(VMKind::JIT); {
else if (arg == "--smart") string vmKind = argv[++i];
VMFactory::setKind(VMKind::Smart); if (vmKind == "interpreter")
VMFactory::setKind(VMKind::Interpreter);
else if (vmKind == "jit")
VMFactory::setKind(VMKind::JIT);
else if (vmKind == "smart")
VMFactory::setKind(VMKind::Smart);
else
{
cerr << "Unknown VM kind: " << vmKind << endl;
return -1;
}
}
#endif #endif
else if (arg == "--mnemonics") else if (arg == "--mnemonics")
st.setShowMnemonics(); st.setShowMnemonics();

7
evmjit/include/evmjit/JIT.h

@ -107,9 +107,7 @@ enum class ReturnCode
Rejected = -5, ///< Input data (code, gas, block info, etc.) does not meet JIT requirement and execution request has been rejected Rejected = -5, ///< Input data (code, gas, block info, etc.) does not meet JIT requirement and execution request has been rejected
// Internal error codes // Internal error codes
LLVMConfigError = -101, LLVMError = -101,
LLVMCompileError = -102,
LLVMLinkError = -103,
UnexpectedException = -111, UnexpectedException = -111,
@ -155,6 +153,9 @@ public:
/// \param _codeHash The Keccak hash of the EVM code. /// \param _codeHash The Keccak hash of the EVM code.
EXPORT static bool isCodeReady(h256 const& _codeHash); EXPORT static bool isCodeReady(h256 const& _codeHash);
/// Compile the given EVM code to machine code and make available for execution.
EXPORT static void compile(byte const* _code, uint64_t _codeSize, h256 const& _codeHash);
EXPORT static ReturnCode exec(ExecutionContext& _context); EXPORT static ReturnCode exec(ExecutionContext& _context);
}; };

92
evmjit/libevmjit/JIT.cpp

@ -1,6 +1,7 @@
#include "evmjit/JIT.h" #include "evmjit/JIT.h"
#include <array> #include <array>
#include <mutex>
#include "preprocessor/llvm_includes_start.h" #include "preprocessor/llvm_includes_start.h"
#include <llvm/IR/Module.h> #include <llvm/IR/Module.h>
@ -82,6 +83,7 @@ void parseOptions()
class JITImpl class JITImpl
{ {
std::unique_ptr<llvm::ExecutionEngine> m_engine; std::unique_ptr<llvm::ExecutionEngine> m_engine;
mutable std::mutex x_codeMap;
std::unordered_map<h256, ExecFunc> m_codeMap; std::unordered_map<h256, ExecFunc> m_codeMap;
public: public:
@ -97,6 +99,8 @@ public:
ExecFunc getExecFunc(h256 const& _codeHash) const; ExecFunc getExecFunc(h256 const& _codeHash) const;
void mapExecFunc(h256 _codeHash, ExecFunc _funcAddr); void mapExecFunc(h256 _codeHash, ExecFunc _funcAddr);
ExecFunc compile(byte const* _code, uint64_t _codeSize, h256 const& _codeHash);
}; };
JITImpl::JITImpl() JITImpl::JITImpl()
@ -134,6 +138,7 @@ JITImpl::JITImpl()
ExecFunc JITImpl::getExecFunc(h256 const& _codeHash) const ExecFunc JITImpl::getExecFunc(h256 const& _codeHash) const
{ {
std::lock_guard<std::mutex> lock{x_codeMap};
auto it = m_codeMap.find(_codeHash); auto it = m_codeMap.find(_codeHash);
if (it != m_codeMap.end()) if (it != m_codeMap.end())
return it->second; return it->second;
@ -142,9 +147,37 @@ ExecFunc JITImpl::getExecFunc(h256 const& _codeHash) const
void JITImpl::mapExecFunc(h256 _codeHash, ExecFunc _funcAddr) void JITImpl::mapExecFunc(h256 _codeHash, ExecFunc _funcAddr)
{ {
std::lock_guard<std::mutex> lock{x_codeMap};
m_codeMap.emplace(std::move(_codeHash), _funcAddr); m_codeMap.emplace(std::move(_codeHash), _funcAddr);
} }
ExecFunc JITImpl::compile(byte const* _code, uint64_t _codeSize, h256 const& _codeHash)
{
auto name = hash2str(_codeHash);
auto module = Cache::getObject(name);
if (!module)
{
// TODO: Listener support must be redesigned. These should be a feature of JITImpl
//listener->stateChanged(ExecState::Compilation);
assert(_code || !_codeSize); //TODO: Is it good idea to execute empty code?
module = Compiler{{}}.compile(_code, _code + _codeSize, name);
if (g_optimize)
{
//listener->stateChanged(ExecState::Optimization);
optimize(*module);
}
prepare(*module);
}
if (g_dump)
module->dump();
m_engine->addModule(std::move(module));
//listener->stateChanged(ExecState::CodeGen);
return (ExecFunc)m_engine->getFunctionAddress(name);
}
} // anonymous namespace } // anonymous namespace
bool JIT::isCodeReady(h256 const& _codeHash) bool JIT::isCodeReady(h256 const& _codeHash)
@ -152,62 +185,41 @@ bool JIT::isCodeReady(h256 const& _codeHash)
return JITImpl::instance().getExecFunc(_codeHash) != nullptr; return JITImpl::instance().getExecFunc(_codeHash) != nullptr;
} }
ReturnCode JIT::exec(ExecutionContext& _context) void JIT::compile(byte const* _code, uint64_t _codeSize, h256 const& _codeHash)
{ {
auto& jit = JITImpl::instance(); auto& jit = JITImpl::instance();
auto execFunc = jit.compile(_code, _codeSize, _codeHash);
if (execFunc) // FIXME: What with error?
jit.mapExecFunc(_codeHash, execFunc);
}
std::unique_ptr<ExecStats> listener{new ExecStats}; ReturnCode JIT::exec(ExecutionContext& _context)
listener->stateChanged(ExecState::Started); {
//std::unique_ptr<ExecStats> listener{new ExecStats};
//listener->stateChanged(ExecState::Started);
//static StatsCollector statsCollector;
auto code = _context.code(); auto& jit = JITImpl::instance();
auto codeSize = _context.codeSize();
auto codeHash = _context.codeHash(); auto codeHash = _context.codeHash();
static StatsCollector statsCollector;
auto mainFuncName = hash2str(codeHash);
// TODO: Remove cast
auto execFunc = jit.getExecFunc(codeHash); auto execFunc = jit.getExecFunc(codeHash);
if (!execFunc) if (!execFunc)
{ {
auto module = Cache::getObject(mainFuncName); execFunc = jit.compile(_context.code(), _context.codeSize(), codeHash);
if (!module) if (!execFunc)
{ return ReturnCode::LLVMError;
listener->stateChanged(ExecState::Compilation);
assert(code || !codeSize); //TODO: Is it good idea to execute empty code?
module = Compiler{{}}.compile(code, code + codeSize, mainFuncName);
if (g_optimize)
{
listener->stateChanged(ExecState::Optimization);
optimize(*module);
}
prepare(*module);
}
if (g_dump)
module->dump();
jit.engine().addModule(std::move(module));
listener->stateChanged(ExecState::CodeGen);
execFunc = (ExecFunc)jit.engine().getFunctionAddress(mainFuncName);
if (!CHECK(execFunc))
return ReturnCode::LLVMLinkError;
jit.mapExecFunc(codeHash, execFunc); jit.mapExecFunc(codeHash, execFunc);
} }
listener->stateChanged(ExecState::Execution); //listener->stateChanged(ExecState::Execution);
auto returnCode = execFunc(&_context); auto returnCode = execFunc(&_context);
listener->stateChanged(ExecState::Return); //listener->stateChanged(ExecState::Return);
if (returnCode == ReturnCode::Return) if (returnCode == ReturnCode::Return)
_context.returnData = _context.getReturnData(); // Save reference to return data _context.returnData = _context.getReturnData(); // Save reference to return data
listener->stateChanged(ExecState::Finished); //listener->stateChanged(ExecState::Finished);
// if (g_stats)
if (g_stats) // statsCollector.stats.push_back(std::move(listener));
statsCollector.stats.push_back(std::move(listener));
return returnCode; return returnCode;
} }

82
libevm/SmartVM.cpp

@ -20,8 +20,13 @@
#include "SmartVM.h" #include "SmartVM.h"
#include <unordered_map> #include <unordered_map>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <queue>
#include <libdevcore/Log.h> #include <libdevcore/Log.h>
#include <libdevcore/SHA3.h> #include <libdevcore/SHA3.h>
#include <libdevcore/Guards.h>
#include <evmjit/JIT.h> #include <evmjit/JIT.h>
#include <evmjit/libevmjit-cpp/Utils.h> #include <evmjit/libevmjit-cpp/Utils.h>
#include "VMFactory.h" #include "VMFactory.h"
@ -32,6 +37,8 @@ namespace eth
{ {
namespace namespace
{ {
struct JitInfo: LogChannel { static const char* name() { return "JIT"; }; static const int verbosity = 11; };
using HitMap = std::unordered_map<h256, uint64_t>; using HitMap = std::unordered_map<h256, uint64_t>;
HitMap& getHitMap() HitMap& getHitMap()
@ -39,30 +46,93 @@ namespace
static HitMap s_hitMap; static HitMap s_hitMap;
return s_hitMap; return s_hitMap;
} }
struct JitTask
{
bytes code;
h256 codeHash;
};
class JitWorker
{
bool m_finished = false;
std::mutex x_mutex;
std::condition_variable m_cv;
std::thread m_worker;
std::queue<JitTask> m_queue;
bool pop(JitTask& o_task)
{
std::unique_lock<std::mutex> lock{x_mutex};
m_cv.wait(lock, [this]{ return m_finished || !m_queue.empty(); });
if (m_finished)
return false;
assert(!m_queue.empty());
o_task = std::move(m_queue.front());
m_queue.pop();
return true;
}
void work()
{
clog(JitInfo) << "JIT worker started.";
JitTask task;
while (pop(task))
{
clog(JitInfo) << "Compilation... " << task.codeHash;
evmjit::JIT::compile(task.code.data(), task.code.size(), eth2jit(task.codeHash));
clog(JitInfo) << " ...finished " << task.codeHash;
}
clog(JitInfo) << "JIT worker finished.";
}
public:
JitWorker() noexcept: m_worker([this]{ work(); })
{}
~JitWorker()
{
DEV_GUARDED(x_mutex)
m_finished = true;
m_cv.notify_one();
m_worker.join();
}
void push(JitTask&& _task)
{
DEV_GUARDED(x_mutex)
m_queue.push(std::move(_task));
m_cv.notify_one();
}
};
} }
bytesConstRef SmartVM::execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp) bytesConstRef SmartVM::execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp)
{ {
auto codeHash = sha3(_ext.code); auto codeHash = _ext.codeHash;
auto vmKind = VMKind::Interpreter; // default VM auto vmKind = VMKind::Interpreter; // default VM
// Jitted EVM code already in memory? // Jitted EVM code already in memory?
if (evmjit::JIT::isCodeReady(eth2jit(codeHash))) if (evmjit::JIT::isCodeReady(eth2jit(codeHash)))
{ {
cnote << "Jitted"; clog(JitInfo) << "JIT: " << codeHash;
vmKind = VMKind::JIT; vmKind = VMKind::JIT;
} }
else else
{ {
static JitWorker s_worker;
// Check EVM code hit count // Check EVM code hit count
static const uint64_t c_hitTreshold = 1; static const uint64_t c_hitTreshold = 2;
auto& hits = getHitMap()[codeHash]; auto& hits = getHitMap()[codeHash];
++hits; ++hits;
if (hits > c_hitTreshold) if (hits == c_hitTreshold)
{ {
cnote << "JIT selected"; clog(JitInfo) << "Schedule: " << codeHash;
vmKind = VMKind::JIT; s_worker.push({_ext.code, codeHash});
} }
clog(JitInfo) << "Interpreter: " << codeHash;
} }
// TODO: Selected VM must be kept only because it returns reference to its internal memory. // TODO: Selected VM must be kept only because it returns reference to its internal memory.

26
neth/main.cpp

@ -101,7 +101,7 @@ void help()
<< " -x,--peers <number> Attempt to connect to given number of peers (default: 5)." << endl << " -x,--peers <number> Attempt to connect to given number of peers (default: 5)." << endl
<< " -V,--version Show the version and exit." << endl << " -V,--version Show the version and exit." << endl
#if ETH_EVMJIT #if ETH_EVMJIT
<< " --jit Use EVM JIT (default: off)." << endl << " --vm <vm-kind> Select VM. Options are: interpreter, jit, smart. (default: interpreter)" << endl
#endif #endif
; ;
exit(0); exit(0);
@ -514,15 +514,23 @@ int main(int argc, char** argv)
return -1; return -1;
} }
} }
else if (arg == "--jit")
{
#if ETH_EVMJIT #if ETH_EVMJIT
jit = true; else if (arg == "--vm" && i + 1 < argc)
#else {
cerr << "EVM JIT not enabled" << endl; string vmKind = argv[++i];
return -1; if (vmKind == "interpreter")
#endif VMFactory::setKind(VMKind::Interpreter);
else if (vmKind == "jit")
VMFactory::setKind(VMKind::JIT);
else if (vmKind == "smart")
VMFactory::setKind(VMKind::Smart);
else
{
cerr << "Unknown VM kind: " << vmKind << endl;
return -1;
}
} }
#endif
else if (arg == "-h" || arg == "--help") else if (arg == "-h" || arg == "--help")
help(); help();
else if (arg == "-V" || arg == "--version") else if (arg == "-V" || arg == "--version")
@ -551,7 +559,7 @@ int main(int argc, char** argv)
mode == NodeMode::Full ? set<string>{"eth", "shh"} : set<string>(), mode == NodeMode::Full ? set<string>{"eth", "shh"} : set<string>(),
netPrefs, netPrefs,
&nodesState); &nodesState);
web3.setIdealPeerCount(peers); web3.setIdealPeerCount(peers);
std::shared_ptr<eth::BasicGasPricer> gasPricer = make_shared<eth::BasicGasPricer>(u256(double(ether / 1000) / etherPrice), u256(blockFees * 1000)); std::shared_ptr<eth::BasicGasPricer> gasPricer = make_shared<eth::BasicGasPricer>(u256(double(ether / 1000) / etherPrice), u256(blockFees * 1000));
eth::Client* c = mode == NodeMode::Full ? web3.ethereum() : nullptr; eth::Client* c = mode == NodeMode::Full ? web3.ethereum() : nullptr;

20
test/TestHelper.cpp

@ -235,7 +235,7 @@ void ImportTest::importState(json_spirit::mObject& _o, State& _state)
} }
void ImportTest::importTransaction(json_spirit::mObject& _o) void ImportTest::importTransaction(json_spirit::mObject& _o)
{ {
if (_o.count("secretKey") > 0) if (_o.count("secretKey") > 0)
{ {
assert(_o.count("nonce") > 0); assert(_o.count("nonce") > 0);
@ -728,10 +728,20 @@ Options::Options()
for (auto i = 0; i < argc; ++i) for (auto i = 0; i < argc; ++i)
{ {
auto arg = std::string{argv[i]}; auto arg = std::string{argv[i]};
if (arg == "--jit") if (arg == "--vm" && i + 1 < argc)
eth::VMFactory::setKind(eth::VMKind::JIT); {
else if (arg == "--vm=smart") string vmKind = argv[++i];
eth::VMFactory::setKind(eth::VMKind::Smart); if (vmKind == "interpreter")
VMFactory::setKind(VMKind::Interpreter);
else if (vmKind == "jit")
VMFactory::setKind(VMKind::JIT);
else if (vmKind == "smart")
VMFactory::setKind(VMKind::Smart);
else
cerr << "Unknown VM kind: " << vmKind << endl;
}
else if (arg == "--jit") // TODO: Remove deprecated option "--jit"
VMFactory::setKind(VMKind::JIT);
else if (arg == "--vmtrace") else if (arg == "--vmtrace")
vmtrace = true; vmtrace = true;
else if (arg == "--filltests") else if (arg == "--filltests")

Loading…
Cancel
Save