Browse Source

Working longjmp solution

[#80660432]
cl-refactor
Paweł Bylica 10 years ago
parent
commit
ec2013d5c9
  1. 14
      evmcc/Compiler.cpp
  2. 16
      evmcc/ExecutionEngine.cpp
  3. 9
      evmcc/GasMeter.cpp
  4. 2
      evmcc/GasMeter.h

14
evmcc/Compiler.cpp

@ -199,22 +199,12 @@ std::unique_ptr<llvm::Module> Compiler::compile(const dev::bytes& bytecode)
createBasicBlocks(bytecode); createBasicBlocks(bytecode);
// Prepare jump buffer
auto jmpBufStorageTy = llvm::ArrayType::get(Type::Byte, 2048);
auto jmpBufStorage = new llvm::GlobalVariable(*module, jmpBufStorageTy, false, llvm::GlobalVariable::PrivateLinkage, llvm::ConstantAggregateZero::get(jmpBufStorageTy), "jmpBuf");
jmpBufStorage->setAlignment(16);
auto jmpBuf = builder.CreateConstInBoundsGEP2_32(jmpBufStorage, 0, 0);
// Init runtime structures. // Init runtime structures.
GasMeter gasMeter(builder, module.get(), jmpBuf); GasMeter gasMeter(builder, module.get());
Memory memory(builder, module.get(), gasMeter); Memory memory(builder, module.get(), gasMeter);
Ext ext(builder, module.get()); Ext ext(builder, module.get());
// Create exception landing with setjmp and jump to first instruction builder.CreateBr(basicBlocks.begin()->second);
auto setjmpFunc = llvm::Intrinsic::getDeclaration(module.get(), llvm::Intrinsic::eh_sjlj_setjmp);
auto setjmpRet = builder.CreateCall(setjmpFunc, jmpBuf);
auto isNormalFlow = builder.CreateICmpEQ(setjmpRet, builder.getInt32(0));
builder.CreateCondBr(isNormalFlow, basicBlocks.begin()->second, m_outOfGasBlock->llvm());
for (auto basicBlockPairIt = basicBlocks.begin(); basicBlockPairIt != basicBlocks.end(); ++basicBlockPairIt) for (auto basicBlockPairIt = basicBlocks.begin(); basicBlockPairIt != basicBlocks.end(); ++basicBlockPairIt)
{ {

16
evmcc/ExecutionEngine.cpp

@ -1,6 +1,8 @@
#include "ExecutionEngine.h" #include "ExecutionEngine.h"
#include <csetjmp>
#include <llvm/IR/LLVMContext.h> #include <llvm/IR/LLVMContext.h>
#include <llvm/IR/Module.h> #include <llvm/IR/Module.h>
#include <llvm/ADT/Triple.h> #include <llvm/ADT/Triple.h>
@ -27,6 +29,8 @@ ExecutionEngine::ExecutionEngine()
} }
extern "C" { EXPORT std::jmp_buf* rt_jmpBuf; }
int ExecutionEngine::run(std::unique_ptr<llvm::Module> _module) int ExecutionEngine::run(std::unique_ptr<llvm::Module> _module)
{ {
@ -101,17 +105,17 @@ int ExecutionEngine::run(std::unique_ptr<llvm::Module> _module)
exit(1); exit(1);
} }
ReturnCode returnCode; ReturnCode returnCode;
try std::jmp_buf buf;
auto r = setjmp(buf);
if (r == 0)
{ {
rt_jmpBuf = &buf;
auto result = exec->runFunction(entryFunc, {}); auto result = exec->runFunction(entryFunc, {});
returnCode = static_cast<ReturnCode>(result.IntVal.getZExtValue()); returnCode = static_cast<ReturnCode>(result.IntVal.getZExtValue());
} }
catch (const dev::eth::OutOfGas&) else
{ returnCode = static_cast<ReturnCode>(r);
returnCode = ReturnCode::OutOfGas;
}
gas = static_cast<decltype(gas)>(Runtime::getGas()); gas = static_cast<decltype(gas)>(Runtime::getGas());

9
evmcc/GasMeter.cpp

@ -78,7 +78,7 @@ bool isCostBlockEnd(Instruction _inst)
} }
GasMeter::GasMeter(llvm::IRBuilder<>& _builder, llvm::Module* _module, llvm::Value* _jmpBuf) : GasMeter::GasMeter(llvm::IRBuilder<>& _builder, llvm::Module* _module) :
m_builder(_builder) m_builder(_builder)
{ {
m_gas = new llvm::GlobalVariable(*_module, Type::i256, false, llvm::GlobalVariable::ExternalLinkage, nullptr, "gas"); m_gas = new llvm::GlobalVariable(*_module, Type::i256, false, llvm::GlobalVariable::ExternalLinkage, nullptr, "gas");
@ -102,8 +102,11 @@ GasMeter::GasMeter(llvm::IRBuilder<>& _builder, llvm::Module* _module, llvm::Val
m_builder.SetInsertPoint(outOfGasBB); m_builder.SetInsertPoint(outOfGasBB);
auto longjmpFunc = llvm::Intrinsic::getDeclaration(_module, llvm::Intrinsic::eh_sjlj_longjmp); //auto longjmpFunc = llvm::Intrinsic::getDeclaration(_module, llvm::Intrinsic::eh_sjlj_longjmp);
m_builder.CreateCall(longjmpFunc, _jmpBuf); auto extJmpBuf = new llvm::GlobalVariable(*_module, Type::BytePtr, false, llvm::GlobalVariable::ExternalLinkage, nullptr, "rt_jmpBuf");
llvm::Type* args[] = {Type::BytePtr, m_builder.getInt32Ty()};
auto longjmpNative = llvm::Function::Create(llvm::FunctionType::get(Type::Void, args, false), llvm::Function::ExternalLinkage, "longjmp", _module);
m_builder.CreateCall2(longjmpNative, m_builder.CreateLoad(extJmpBuf), Constant::get(ReturnCode::OutOfGas));
m_builder.CreateUnreachable(); m_builder.CreateUnreachable();
m_builder.SetInsertPoint(updateBB); m_builder.SetInsertPoint(updateBB);

2
evmcc/GasMeter.h

@ -11,7 +11,7 @@ namespace evmcc
class GasMeter class GasMeter
{ {
public: public:
GasMeter(llvm::IRBuilder<>& _builder, llvm::Module* _module, llvm::Value* _jmpBuf); GasMeter(llvm::IRBuilder<>& _builder, llvm::Module* _module);
GasMeter(const GasMeter&) = delete; GasMeter(const GasMeter&) = delete;
void operator=(GasMeter) = delete; void operator=(GasMeter) = delete;

Loading…
Cancel
Save