mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-22 04:36:42 +00:00
codegen for LOG instructions [Delivers #81700490]
This commit is contained in:
parent
cdcbb6be12
commit
c907c71f8a
8 changed files with 178 additions and 12 deletions
|
|
@ -31,9 +31,12 @@ void parseProgramOptions(int _argc, char** _argv, boost::program_options::variab
|
||||||
("gas,g", opt::value<size_t>(), "set initial gas for execution")
|
("gas,g", opt::value<size_t>(), "set initial gas for execution")
|
||||||
("disassemble,d", "dissassemble the code")
|
("disassemble,d", "dissassemble the code")
|
||||||
("dump-cfg", "dump control flow graph to graphviz file")
|
("dump-cfg", "dump control flow graph to graphviz file")
|
||||||
("optimize-stack,os", "optimize stack use between basic blocks")
|
("dont-optimize", "turn off optimizations")
|
||||||
|
("optimize-stack", "optimize stack use between basic blocks (default: on)")
|
||||||
|
("rewrite-switch", "rewrite LLVM switch to branches (default: on)")
|
||||||
("output-ll", opt::value<std::string>(), "dump generated LLVM IR to file")
|
("output-ll", opt::value<std::string>(), "dump generated LLVM IR to file")
|
||||||
("output-bc", opt::value<std::string>(), "dump generated LLVM bitcode to file")
|
("output-bc", opt::value<std::string>(), "dump generated LLVM bitcode to file")
|
||||||
|
("show-logs", "output LOG statements to stderr")
|
||||||
("verbose,V", "enable verbose output");
|
("verbose,V", "enable verbose output");
|
||||||
|
|
||||||
opt::options_description implicitOpts("Input files");
|
opt::options_description implicitOpts("Input files");
|
||||||
|
|
@ -118,7 +121,9 @@ int main(int argc, char** argv)
|
||||||
|
|
||||||
eth::jit::Compiler::Options compilerOptions;
|
eth::jit::Compiler::Options compilerOptions;
|
||||||
compilerOptions.dumpCFG = options.count("dump-cfg") > 0;
|
compilerOptions.dumpCFG = options.count("dump-cfg") > 0;
|
||||||
compilerOptions.optimizeStack = options.count("optimize-stack") > 0;
|
bool optimize = options.count("dont-optimize") == 0;
|
||||||
|
compilerOptions.optimizeStack = optimize || options.count("optimize-stack") > 0;
|
||||||
|
compilerOptions.rewriteSwitchToBranches = optimize || options.count("rewrite-switch") > 0;
|
||||||
|
|
||||||
auto compiler = eth::jit::Compiler(compilerOptions);
|
auto compiler = eth::jit::Compiler(compilerOptions);
|
||||||
auto module = compiler.compile({bytecode.data(), bytecode.size()});
|
auto module = compiler.compile({bytecode.data(), bytecode.size()});
|
||||||
|
|
@ -156,7 +161,6 @@ int main(int argc, char** argv)
|
||||||
ofs.close();
|
ofs.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (options.count("verbose"))
|
if (options.count("verbose"))
|
||||||
{
|
{
|
||||||
std::cerr << "*** Compilation time: "
|
std::cerr << "*** Compilation time: "
|
||||||
|
|
@ -168,7 +172,7 @@ int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
auto engine = eth::jit::ExecutionEngine();
|
auto engine = eth::jit::ExecutionEngine();
|
||||||
u256 gas = initialGas;
|
u256 gas = initialGas;
|
||||||
auto result = engine.run(std::move(module), gas);
|
auto result = engine.run(std::move(module), gas, options.count("show-logs") > 0);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -508,7 +508,11 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytesConstRef _bytecod
|
||||||
|
|
||||||
case Instruction::POP:
|
case Instruction::POP:
|
||||||
{
|
{
|
||||||
stack.pop();
|
auto val = stack.pop();
|
||||||
|
static_cast<void>(val);
|
||||||
|
// Generate a dummy use of val to make sure that a get(0) will be emitted at this point,
|
||||||
|
// so that StackTooSmall will be thrown
|
||||||
|
// m_builder.CreateICmpEQ(val, val, "dummy");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -791,6 +795,25 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytesConstRef _bytecod
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case Instruction::LOG0:
|
||||||
|
case Instruction::LOG1:
|
||||||
|
case Instruction::LOG2:
|
||||||
|
case Instruction::LOG3:
|
||||||
|
case Instruction::LOG4:
|
||||||
|
{
|
||||||
|
auto beginIdx = stack.pop();
|
||||||
|
auto numBytes = stack.pop();
|
||||||
|
_memory.require(beginIdx, numBytes);
|
||||||
|
|
||||||
|
std::array<llvm::Value*,4> topics;
|
||||||
|
auto numTopics = static_cast<size_t>(inst) - static_cast<size_t>(Instruction::LOG0);
|
||||||
|
for (size_t i = 0; i < numTopics; ++i)
|
||||||
|
topics[i] = stack.pop();
|
||||||
|
|
||||||
|
_ext.log(beginIdx, numBytes, numTopics, topics);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default: // Invalid instruction - runtime exception
|
default: // Invalid instruction - runtime exception
|
||||||
{
|
{
|
||||||
_runtimeManager.raiseException(ReturnCode::BadInstruction);
|
_runtimeManager.raiseException(ReturnCode::BadInstruction);
|
||||||
|
|
|
||||||
|
|
@ -37,10 +37,9 @@ namespace jit
|
||||||
|
|
||||||
ExecutionEngine::ExecutionEngine()
|
ExecutionEngine::ExecutionEngine()
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int ExecutionEngine::run(std::unique_ptr<llvm::Module> _module, u256& _gas, ExtVMFace* _ext)
|
int ExecutionEngine::run(std::unique_ptr<llvm::Module> _module, u256& _gas, bool _outputLogs, ExtVMFace* _ext)
|
||||||
{
|
{
|
||||||
auto module = _module.get(); // Keep ownership of the module in _module
|
auto module = _module.get(); // Keep ownership of the module in _module
|
||||||
|
|
||||||
|
|
@ -110,7 +109,7 @@ int ExecutionEngine::run(std::unique_ptr<llvm::Module> _module, u256& _gas, ExtV
|
||||||
|
|
||||||
ReturnCode returnCode;
|
ReturnCode returnCode;
|
||||||
std::jmp_buf buf;
|
std::jmp_buf buf;
|
||||||
Runtime runtime(_gas, *_ext, buf);
|
Runtime runtime(_gas, *_ext, buf, _outputLogs);
|
||||||
auto r = setjmp(buf);
|
auto r = setjmp(buf);
|
||||||
if (r == 0)
|
if (r == 0)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ class ExecutionEngine
|
||||||
public:
|
public:
|
||||||
ExecutionEngine();
|
ExecutionEngine();
|
||||||
|
|
||||||
int run(std::unique_ptr<llvm::Module> module, u256& _gas, ExtVMFace* _ext = nullptr);
|
int run(std::unique_ptr<llvm::Module> module, u256& _gas, bool _outputLogs, ExtVMFace* _ext = nullptr);
|
||||||
|
|
||||||
bytes returnData;
|
bytes returnData;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -59,6 +59,11 @@ Ext::Ext(RuntimeManager& _runtimeManager):
|
||||||
m_exp = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 4}, false), Linkage::ExternalLinkage, "ext_exp", module);
|
m_exp = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 4}, false), Linkage::ExternalLinkage, "ext_exp", module);
|
||||||
m_codeAt = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, {argsTypes, 2}, false), Linkage::ExternalLinkage, "ext_codeAt", module);
|
m_codeAt = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, {argsTypes, 2}, false), Linkage::ExternalLinkage, "ext_codeAt", module);
|
||||||
m_codesizeAt = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 3}, false), Linkage::ExternalLinkage, "ext_codesizeAt", module);
|
m_codesizeAt = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 3}, false), Linkage::ExternalLinkage, "ext_codesizeAt", module);
|
||||||
|
m_log0 = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 3}, false), Linkage::ExternalLinkage, "ext_log0", module);
|
||||||
|
m_log1 = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 4}, false), Linkage::ExternalLinkage, "ext_log1", module);
|
||||||
|
m_log2 = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 5}, false), Linkage::ExternalLinkage, "ext_log2", module);
|
||||||
|
m_log3 = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 6}, false), Linkage::ExternalLinkage, "ext_log3", module);
|
||||||
|
m_log4 = llvm::Function::Create(llvm::FunctionType::get(Type::Void, {argsTypes, 7}, false), Linkage::ExternalLinkage, "ext_log4", module);
|
||||||
}
|
}
|
||||||
|
|
||||||
llvm::Value* Ext::store(llvm::Value* _index)
|
llvm::Value* Ext::store(llvm::Value* _index)
|
||||||
|
|
@ -160,6 +165,21 @@ llvm::Value* Ext::codesizeAt(llvm::Value* _addr)
|
||||||
return m_builder.CreateLoad(m_args[1]);
|
return m_builder.CreateLoad(m_args[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Ext::log(llvm::Value* _memIdx, llvm::Value* _numBytes, size_t _numTopics, std::array<llvm::Value*,4> const& _topics)
|
||||||
|
{
|
||||||
|
static llvm::Value* args[] = {nullptr, m_args[0], m_args[1], m_arg2, m_arg3, m_arg4, m_arg5};
|
||||||
|
static llvm::Value* funcs[] = {m_log0, m_log1, m_log2, m_log3, m_log4};
|
||||||
|
|
||||||
|
args[0] = getRuntimeManager().getRuntimePtr();
|
||||||
|
m_builder.CreateStore(_memIdx, m_args[0]);
|
||||||
|
m_builder.CreateStore(_numBytes, m_args[1]);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < _numTopics; ++i)
|
||||||
|
m_builder.CreateStore(_topics[i], args[i + 3]);
|
||||||
|
|
||||||
|
m_builder.CreateCall(funcs[_numTopics], llvm::ArrayRef<llvm::Value*>(args, _numTopics + 3));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -289,6 +309,111 @@ extern "C"
|
||||||
*o_ret = eth2llvm(u256(code.size()));
|
*o_ret = eth2llvm(u256(code.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ext_show_bytes(bytesConstRef _bytes)
|
||||||
|
{
|
||||||
|
for (auto b : _bytes)
|
||||||
|
std::cerr << std::hex << std::setw(2) << std::setfill('0') << static_cast<unsigned>(b) << " ";
|
||||||
|
std::cerr << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPORT void ext_log0(Runtime* _rt, i256* _memIdx, i256* _numBytes)
|
||||||
|
{
|
||||||
|
auto&& ext = _rt->getExt();
|
||||||
|
|
||||||
|
auto memIdx = static_cast<size_t>(llvm2eth(*_memIdx));
|
||||||
|
auto numBytes = static_cast<size_t>(llvm2eth(*_numBytes));
|
||||||
|
|
||||||
|
auto dataRef = bytesConstRef(_rt->getMemory().data() + memIdx, numBytes);
|
||||||
|
ext.log({}, dataRef);
|
||||||
|
|
||||||
|
if (_rt->outputLogs())
|
||||||
|
{
|
||||||
|
std::cerr << "LOG: ";
|
||||||
|
ext_show_bytes(dataRef);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPORT void ext_log1(Runtime* _rt, i256* _memIdx, i256* _numBytes, i256* _topic1)
|
||||||
|
{
|
||||||
|
auto&& ext = _rt->getExt();
|
||||||
|
|
||||||
|
auto memIdx = static_cast<size_t>(llvm2eth(*_memIdx));
|
||||||
|
auto numBytes = static_cast<size_t>(llvm2eth(*_numBytes));
|
||||||
|
|
||||||
|
auto topic1 = llvm2eth(*_topic1);
|
||||||
|
|
||||||
|
auto dataRef = bytesConstRef(_rt->getMemory().data() + memIdx, numBytes);
|
||||||
|
ext.log({topic1}, dataRef);
|
||||||
|
|
||||||
|
if (_rt->outputLogs())
|
||||||
|
{
|
||||||
|
std::cerr << "LOG [" << topic1 << "]: ";
|
||||||
|
ext_show_bytes(dataRef);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPORT void ext_log2(Runtime* _rt, i256* _memIdx, i256* _numBytes, i256* _topic1, i256* _topic2)
|
||||||
|
{
|
||||||
|
auto&& ext = _rt->getExt();
|
||||||
|
|
||||||
|
auto memIdx = static_cast<size_t>(llvm2eth(*_memIdx));
|
||||||
|
auto numBytes = static_cast<size_t>(llvm2eth(*_numBytes));
|
||||||
|
|
||||||
|
auto topic1 = llvm2eth(*_topic1);
|
||||||
|
auto topic2 = llvm2eth(*_topic2);
|
||||||
|
|
||||||
|
auto dataRef = bytesConstRef(_rt->getMemory().data() + memIdx, numBytes);
|
||||||
|
ext.log({topic1, topic2}, dataRef);
|
||||||
|
|
||||||
|
if (_rt->outputLogs())
|
||||||
|
{
|
||||||
|
std::cerr << "LOG [" << topic1 << "][" << topic2 << "]: ";
|
||||||
|
ext_show_bytes(dataRef);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPORT void ext_log3(Runtime* _rt, i256* _memIdx, i256* _numBytes, i256* _topic1, i256* _topic2, i256* _topic3)
|
||||||
|
{
|
||||||
|
auto&& ext = _rt->getExt();
|
||||||
|
|
||||||
|
auto memIdx = static_cast<size_t>(llvm2eth(*_memIdx));
|
||||||
|
auto numBytes = static_cast<size_t>(llvm2eth(*_numBytes));
|
||||||
|
|
||||||
|
auto topic1 = llvm2eth(*_topic1);
|
||||||
|
auto topic2 = llvm2eth(*_topic2);
|
||||||
|
auto topic3 = llvm2eth(*_topic3);
|
||||||
|
|
||||||
|
auto dataRef = bytesConstRef(_rt->getMemory().data() + memIdx, numBytes);
|
||||||
|
ext.log({topic1, topic2, topic3}, dataRef);
|
||||||
|
|
||||||
|
if (_rt->outputLogs())
|
||||||
|
{
|
||||||
|
std::cerr << "LOG [" << topic1 << "][" << topic2 << "][" << topic3 << "]: ";
|
||||||
|
ext_show_bytes(dataRef);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPORT void ext_log4(Runtime* _rt, i256* _memIdx, i256* _numBytes, i256* _topic1, i256* _topic2, i256* _topic3, i256* _topic4)
|
||||||
|
{
|
||||||
|
auto&& ext = _rt->getExt();
|
||||||
|
|
||||||
|
auto memIdx = static_cast<size_t>(llvm2eth(*_memIdx));
|
||||||
|
auto numBytes = static_cast<size_t>(llvm2eth(*_numBytes));
|
||||||
|
|
||||||
|
auto topic1 = llvm2eth(*_topic1);
|
||||||
|
auto topic2 = llvm2eth(*_topic2);
|
||||||
|
auto topic3 = llvm2eth(*_topic3);
|
||||||
|
auto topic4 = llvm2eth(*_topic4);
|
||||||
|
|
||||||
|
auto dataRef = bytesConstRef(_rt->getMemory().data() + memIdx, numBytes);
|
||||||
|
ext.log({topic1, topic2, topic3, topic4}, dataRef);
|
||||||
|
|
||||||
|
if (_rt->outputLogs())
|
||||||
|
{
|
||||||
|
std::cerr << "LOG [" << topic1 << "][" << topic2 << "][" << topic3 << "][" << topic4 << "]: ";
|
||||||
|
ext_show_bytes(dataRef);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,8 +31,10 @@ public:
|
||||||
llvm::Value* codeAt(llvm::Value* _addr);
|
llvm::Value* codeAt(llvm::Value* _addr);
|
||||||
llvm::Value* codesizeAt(llvm::Value* _addr);
|
llvm::Value* codesizeAt(llvm::Value* _addr);
|
||||||
|
|
||||||
|
void log(llvm::Value* _memIdx, llvm::Value* _numBytes, size_t _numTopics, std::array<llvm::Value*,4> const& _topics);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
llvm::Value* m_args[2];
|
llvm::Value* m_args[2];
|
||||||
llvm::Value* m_arg2;
|
llvm::Value* m_arg2;
|
||||||
llvm::Value* m_arg3;
|
llvm::Value* m_arg3;
|
||||||
|
|
@ -53,6 +55,11 @@ private:
|
||||||
llvm::Function* m_exp;
|
llvm::Function* m_exp;
|
||||||
llvm::Function* m_codeAt;
|
llvm::Function* m_codeAt;
|
||||||
llvm::Function* m_codesizeAt;
|
llvm::Function* m_codesizeAt;
|
||||||
|
llvm::Function* m_log0;
|
||||||
|
llvm::Function* m_log1;
|
||||||
|
llvm::Function* m_log2;
|
||||||
|
llvm::Function* m_log3;
|
||||||
|
llvm::Function* m_log4;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -58,8 +58,9 @@ llvm::Twine getName(RuntimeData::Index _index)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Runtime::Runtime(u256 _gas, ExtVMFace& _ext, jmp_buf _jmpBuf):
|
Runtime::Runtime(u256 _gas, ExtVMFace& _ext, jmp_buf _jmpBuf, bool _outputLogs):
|
||||||
m_ext(_ext)
|
m_ext(_ext),
|
||||||
|
m_outputLogs(_outputLogs)
|
||||||
{
|
{
|
||||||
set(RuntimeData::Gas, _gas);
|
set(RuntimeData::Gas, _gas);
|
||||||
set(RuntimeData::Address, fromAddress(_ext.myAddress));
|
set(RuntimeData::Address, fromAddress(_ext.myAddress));
|
||||||
|
|
@ -101,6 +102,11 @@ bytesConstRef Runtime::getReturnData() const
|
||||||
return {m_memory.data() + offset, size};
|
return {m_memory.data() + offset, size};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Runtime::outputLogs() const
|
||||||
|
{
|
||||||
|
return m_outputLogs;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
RuntimeManager::RuntimeManager(llvm::IRBuilder<>& _builder): CompilerHelper(_builder)
|
RuntimeManager::RuntimeManager(llvm::IRBuilder<>& _builder): CompilerHelper(_builder)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,7 @@ using MemoryImpl = bytes;
|
||||||
class Runtime
|
class Runtime
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Runtime(u256 _gas, ExtVMFace& _ext, jmp_buf _jmpBuf);
|
Runtime(u256 _gas, ExtVMFace& _ext, jmp_buf _jmpBuf, bool _outputLogs);
|
||||||
|
|
||||||
Runtime(const Runtime&) = delete;
|
Runtime(const Runtime&) = delete;
|
||||||
void operator=(const Runtime&) = delete;
|
void operator=(const Runtime&) = delete;
|
||||||
|
|
@ -77,6 +77,7 @@ public:
|
||||||
u256 getGas() const;
|
u256 getGas() const;
|
||||||
bytesConstRef getReturnData() const;
|
bytesConstRef getReturnData() const;
|
||||||
decltype(&jmp_buf{}[0]) getJmpBuf() { return m_data.jmpBuf; }
|
decltype(&jmp_buf{}[0]) getJmpBuf() { return m_data.jmpBuf; }
|
||||||
|
bool outputLogs() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void set(RuntimeData::Index _index, u256 _value);
|
void set(RuntimeData::Index _index, u256 _value);
|
||||||
|
|
@ -86,6 +87,7 @@ private:
|
||||||
StackImpl m_stack;
|
StackImpl m_stack;
|
||||||
MemoryImpl m_memory;
|
MemoryImpl m_memory;
|
||||||
ExtVMFace& m_ext;
|
ExtVMFace& m_ext;
|
||||||
|
bool m_outputLogs; ///< write LOG statements to console
|
||||||
};
|
};
|
||||||
|
|
||||||
class RuntimeManager: public CompilerHelper
|
class RuntimeManager: public CompilerHelper
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue