Browse Source

Correct usage of LLVM builtin setjmp/longjmp. External setjmp was eliminated, hopefully Windows will be happier now.

cl-refactor
Paweł Bylica 10 years ago
parent
commit
5f4bda5cef
  1. 43
      evmjit/libevmjit/Compiler.cpp
  2. 3
      evmjit/libevmjit/ExecStats.cpp
  3. 17
      evmjit/libevmjit/ExecutionEngine.cpp
  4. 2
      evmjit/libevmjit/GasMeter.cpp
  5. 3
      evmjit/libevmjit/Runtime.cpp
  6. 10
      evmjit/libevmjit/Runtime.h
  7. 20
      evmjit/libevmjit/RuntimeManager.cpp
  8. 9
      evmjit/libevmjit/RuntimeManager.h
  9. 26
      evmjit/libevmjit/Stack.cpp

43
evmjit/libevmjit/Compiler.cpp

@ -15,6 +15,7 @@
#include <llvm/IR/CFG.h>
#include <llvm/IR/Module.h>
#include <llvm/IR/IntrinsicInst.h>
#include <llvm/IR/MDBuilder.h>
#include <llvm/PassManager.h>
#include <llvm/Transforms/Scalar.h>
#include "preprocessor/llvm_includes_end.h"
@ -89,9 +90,6 @@ void Compiler::createBasicBlocks(code_iterator _codeBegin, code_iterator _codeEn
begin = next;
}
}
// TODO: Create Stop basic block on demand
m_stopBB = llvm::BasicBlock::Create(m_mainFunc->getContext(), "Stop", m_mainFunc);
}
llvm::BasicBlock* Compiler::getJumpTableBlock()
@ -134,21 +132,40 @@ std::unique_ptr<llvm::Module> Compiler::compile(code_iterator _begin, code_itera
m_mainFunc = llvm::Function::Create(mainFuncType, llvm::Function::ExternalLinkage, _id, module.get());
m_mainFunc->getArgumentList().front().setName("rt");
// Create the basic blocks.
auto entryBlock = llvm::BasicBlock::Create(m_builder.getContext(), "entry", m_mainFunc);
// Create entry basic block
auto entryBlock = llvm::BasicBlock::Create(m_builder.getContext(), {}, m_mainFunc);
m_builder.SetInsertPoint(entryBlock);
auto jmpBufWords = m_builder.CreateAlloca(Type::BytePtr, m_builder.getInt64(3), "jmpBuf.words");
auto frameaddress = llvm::Intrinsic::getDeclaration(module.get(), llvm::Intrinsic::frameaddress);
auto fp = m_builder.CreateCall(frameaddress, m_builder.getInt32(0), "fp");
m_builder.CreateStore(fp, jmpBufWords);
auto stacksave = llvm::Intrinsic::getDeclaration(module.get(), llvm::Intrinsic::stacksave);
auto sp = m_builder.CreateCall(stacksave, "sp");
auto jmpBufSp = m_builder.CreateConstInBoundsGEP1_64(jmpBufWords, 2, "jmpBuf.sp");
m_builder.CreateStore(sp, jmpBufSp);
auto setjmp = llvm::Intrinsic::getDeclaration(module.get(), llvm::Intrinsic::eh_sjlj_setjmp);
auto jmpBuf = m_builder.CreateBitCast(jmpBufWords, Type::BytePtr, "jmpBuf");
auto r = m_builder.CreateCall(setjmp, jmpBuf);
auto normalFlow = m_builder.CreateICmpEQ(r, m_builder.getInt32(0));
createBasicBlocks(_begin, _end);
// Init runtime structures.
RuntimeManager runtimeManager(m_builder, _begin, _end);
RuntimeManager runtimeManager(m_builder, jmpBuf, _begin, _end);
GasMeter gasMeter(m_builder, runtimeManager);
Memory memory(runtimeManager, gasMeter);
Ext ext(runtimeManager, memory);
Stack stack(m_builder, runtimeManager);
Arith256 arith(m_builder);
m_builder.CreateBr(m_basicBlocks.empty() ? m_stopBB : m_basicBlocks.begin()->second.llvm());
// TODO: Create Stop basic block on demand
m_stopBB = llvm::BasicBlock::Create(m_mainFunc->getContext(), "Stop", m_mainFunc);
auto abortBB = llvm::BasicBlock::Create(m_mainFunc->getContext(), "Abort", m_mainFunc);
auto firstBB = m_basicBlocks.empty() ? m_stopBB : m_basicBlocks.begin()->second.llvm();
auto expectTrue = llvm::MDBuilder{m_builder.getContext()}.createBranchWeights(1, 0);
m_builder.CreateCondBr(normalFlow, firstBB, abortBB, expectTrue);
for (auto basicBlockPairIt = m_basicBlocks.begin(); basicBlockPairIt != m_basicBlocks.end(); ++basicBlockPairIt)
{
@ -164,6 +181,9 @@ std::unique_ptr<llvm::Module> Compiler::compile(code_iterator _begin, code_itera
m_builder.SetInsertPoint(m_stopBB);
m_builder.CreateRet(Constant::get(ReturnCode::Stop));
m_builder.SetInsertPoint(abortBB);
m_builder.CreateRet(Constant::get(ReturnCode::OutOfGas));
removeDeadBlocks();
// Link jump table target index
@ -825,12 +845,9 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, RuntimeManager& _runti
break;
}
default: // Invalid instruction - runtime exception
{
// TODO: Replace with return statement
_runtimeManager.raiseException(ReturnCode::BadInstruction);
}
default: // Invalid instruction - abort
m_builder.CreateRet(Constant::get(ReturnCode::BadInstruction));
it = _basicBlock.end() - 1; // finish block compilation
}
}

3
evmjit/libevmjit/ExecStats.cpp

@ -44,7 +44,8 @@ struct StatsAgg
void output(char const* _name, std::ostream& _os)
{
auto avg = tot / count;
_os << std::setw(12) << std::left << _name
_os << std::setfill(' ')
<< std::setw(12) << std::left << _name
<< std::setw(10) << std::right << std::chrono::duration_cast<unit>(tot).count()
<< std::setw(10) << std::right << std::chrono::duration_cast<unit>(avg).count()
<< std::setw(10) << std::right << std::chrono::duration_cast<unit>(min).count()

17
evmjit/libevmjit/ExecutionEngine.cpp

@ -30,21 +30,6 @@ namespace
{
typedef ReturnCode(*EntryFuncPtr)(Runtime*);
ReturnCode runEntryFunc(EntryFuncPtr _mainFunc, Runtime* _runtime)
{
// That function uses long jumps to handle "execeptions".
// Do not create any non-POD objects here
ReturnCode returnCode{};
auto sj = setjmp(_runtime->getJmpBuf());
if (sj == 0)
returnCode = _mainFunc(_runtime);
else
returnCode = static_cast<ReturnCode>(sj);
return returnCode;
}
std::string codeHash(i256 const& _hash)
{
static const auto size = sizeof(_hash);
@ -162,7 +147,7 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env)
assert(entryFuncPtr); //TODO: Replace it with safe exception
listener->stateChanged(ExecState::Execution);
auto returnCode = runEntryFunc(entryFuncPtr, &runtime);
auto returnCode = entryFuncPtr(&runtime);
listener->stateChanged(ExecState::Return);
if (returnCode == ReturnCode::Return)

2
evmjit/libevmjit/GasMeter.cpp

@ -104,7 +104,7 @@ GasMeter::GasMeter(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager)
m_builder.CreateCondBr(isOutOfGas, outOfGasBB, updateBB);
m_builder.SetInsertPoint(outOfGasBB);
m_runtimeManager.raiseException(ReturnCode::OutOfGas);
m_runtimeManager.abort();
m_builder.CreateUnreachable();
m_builder.SetInsertPoint(updateBB);

3
evmjit/libevmjit/Runtime.cpp

@ -10,8 +10,7 @@ namespace jit
Runtime::Runtime(RuntimeData* _data, Env* _env) :
m_data(*_data),
m_env(*_env),
m_currJmpBuf(m_jmpBuf)
m_env(*_env)
{}
bytes_ref Runtime::getReturnData() const

10
evmjit/libevmjit/Runtime.h

@ -1,6 +1,5 @@
#pragma once
#include "RuntimeData.h"
#include <csetjmp>
namespace dev
{
@ -11,7 +10,6 @@ namespace jit
using StackImpl = std::vector<i256>;
using MemoryImpl = bytes;
using jmp_buf_ref = decltype(&std::jmp_buf{}[0]);
class Runtime
{
@ -26,15 +24,13 @@ public:
Env* getEnvPtr() { return &m_env; }
bytes_ref getReturnData() const;
jmp_buf_ref getJmpBuf() { return m_jmpBuf; }
private:
RuntimeData& m_data; ///< Pointer to data. Expected by compiled contract.
Env& m_env; ///< Pointer to environment proxy. Expected by compiled contract.
jmp_buf_ref m_currJmpBuf; ///< Pointer to jump buffer. Expected by compiled contract.
RuntimeData& m_data; ///< Pointer to data. Expected by compiled contract.
Env& m_env; ///< Pointer to environment proxy. Expected by compiled contract.
void* m_currJmpBuf = nullptr; ///< Pointer to jump buffer. Expected by compiled contract.
byte* m_memoryData = nullptr;
i256 m_memorySize;
std::jmp_buf m_jmpBuf;
StackImpl m_stack;
MemoryImpl m_memory;
};

20
evmjit/libevmjit/RuntimeManager.cpp

@ -83,12 +83,17 @@ llvm::Twine getName(RuntimeData::Index _index)
}
}
RuntimeManager::RuntimeManager(llvm::IRBuilder<>& _builder, code_iterator _codeBegin, code_iterator _codeEnd):
RuntimeManager::RuntimeManager(llvm::IRBuilder<>& _builder, llvm::Value* _jmpBuf, code_iterator _codeBegin, code_iterator _codeEnd):
CompilerHelper(_builder),
m_jmpBuf(_jmpBuf),
m_codeBegin(_codeBegin),
m_codeEnd(_codeEnd)
{
m_longjmp = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::longjmp);
m_longjmp = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::eh_sjlj_longjmp);
// save jmpBuf to be used in helper functions
auto ptr = m_builder.CreateStructGEP(getRuntimePtr(), 2);
m_builder.CreateStore(m_jmpBuf, ptr, "jmpBufExt");
// Unpack data
auto rtPtr = getRuntimePtr();
@ -160,9 +165,10 @@ void RuntimeManager::registerSuicide(llvm::Value* _balanceAddress)
set(RuntimeData::SuicideDestAddress, _balanceAddress);
}
void RuntimeManager::raiseException(ReturnCode _returnCode)
void RuntimeManager::abort(llvm::Value* _jmpBuf)
{
m_builder.CreateCall2(m_longjmp, getJmpBuf(), Constant::get(_returnCode));
auto longjmp = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::eh_sjlj_longjmp);
createCall(longjmp, {_jmpBuf});
}
llvm::Value* RuntimeManager::get(Instruction _inst)
@ -207,10 +213,10 @@ llvm::Value* RuntimeManager::getCallDataSize()
return getBuilder().CreateZExt(value, Type::Word);
}
llvm::Value* RuntimeManager::getJmpBuf()
llvm::Value* RuntimeManager::getJmpBufExt()
{
auto ptr = getBuilder().CreateStructGEP(getRuntimePtr(), 2, "jmpbufPtr");
return getBuilder().CreateLoad(ptr, "jmpbuf");
auto ptr = getBuilder().CreateStructGEP(getRuntimePtr(), 2);
return getBuilder().CreateLoad(ptr, "jmpBufExt");
}
llvm::Value* RuntimeManager::getGas()

9
evmjit/libevmjit/RuntimeManager.h

@ -14,7 +14,7 @@ namespace jit
class RuntimeManager: public CompilerHelper
{
public:
RuntimeManager(llvm::IRBuilder<>& _builder, code_iterator _codeBegin, code_iterator _codeEnd);
RuntimeManager(llvm::IRBuilder<>& _builder, llvm::Value* _jmpBuf, code_iterator _codeBegin, code_iterator _codeEnd);
llvm::Value* getRuntimePtr();
llvm::Value* getDataPtr();
@ -28,12 +28,14 @@ public:
llvm::Value* getCode();
llvm::Value* getCodeSize();
llvm::Value* getCallDataSize();
llvm::Value* getJmpBuf() { return m_jmpBuf; }
void setGas(llvm::Value* _gas);
void registerReturnData(llvm::Value* _index, llvm::Value* _size);
void registerSuicide(llvm::Value* _balanceAddress);
void raiseException(ReturnCode _returnCode);
void abort(llvm::Value* _jmpBuf);
void abort() { abort(getJmpBufExt()); }
static llvm::StructType* getRuntimeType();
static llvm::StructType* getRuntimeDataType();
@ -41,9 +43,10 @@ public:
private:
llvm::Value* getPtr(RuntimeData::Index _index);
void set(RuntimeData::Index _index, llvm::Value* _value);
llvm::Value* getJmpBuf();
llvm::Value* getJmpBufExt();
llvm::Function* m_longjmp = nullptr;
llvm::Value* const m_jmpBuf;
llvm::Value* m_dataPtr = nullptr;
llvm::Value* m_envPtr = nullptr;

26
evmjit/libevmjit/Stack.cpp

@ -34,14 +34,17 @@ llvm::Function* Stack::getPopFunc()
auto& func = m_pop;
if (!func)
{
llvm::Type* argTypes[] = {Type::RuntimePtr, Type::Size};
llvm::Type* argTypes[] = {Type::RuntimePtr, Type::Size, Type::BytePtr};
func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::ExternalLinkage, "stack.pop", getModule());
auto extPopFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Bool, argTypes, false), llvm::Function::ExternalLinkage, "stack_pop", getModule());
llvm::Type* extArgTypes[] = {Type::RuntimePtr, Type::Size};
auto extPopFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Bool, extArgTypes, false), llvm::Function::ExternalLinkage, "stack_pop", getModule());
auto rt = &func->getArgumentList().front();
rt->setName("rt");
auto index = rt->getNextNode();
index->setName("index");
auto jmpBuf = index->getNextNode();
jmpBuf->setName("jmpBuf");
InsertPointGuard guard{m_builder};
auto entryBB = llvm::BasicBlock::Create(m_builder.getContext(), {}, func);
@ -50,10 +53,10 @@ llvm::Function* Stack::getPopFunc()
m_builder.SetInsertPoint(entryBB);
auto ok = createCall(extPopFunc, {rt, index});
m_builder.CreateCondBr(ok, returnBB, underflowBB);
m_builder.CreateCondBr(ok, returnBB, underflowBB); //TODO: Add branch weight
m_builder.SetInsertPoint(underflowBB);
m_runtimeManager.raiseException(ReturnCode::StackTooSmall);
m_runtimeManager.abort(jmpBuf);
m_builder.CreateUnreachable();
m_builder.SetInsertPoint(returnBB);
@ -67,14 +70,17 @@ llvm::Function* Stack::getGetFunc()
auto& func = m_get;
if (!func)
{
llvm::Type* argTypes[] = {Type::RuntimePtr, Type::Size};
llvm::Type* argTypes[] = {Type::RuntimePtr, Type::Size, Type::BytePtr};
func = llvm::Function::Create(llvm::FunctionType::get(Type::WordPtr, argTypes, false), llvm::Function::ExternalLinkage, "stack.get", getModule());
auto extGetFunc = llvm::Function::Create(llvm::FunctionType::get(Type::WordPtr, argTypes, false), llvm::Function::ExternalLinkage, "stack_get", getModule());
llvm::Type* extArgTypes[] = {Type::RuntimePtr, Type::Size};
auto extGetFunc = llvm::Function::Create(llvm::FunctionType::get(Type::WordPtr, extArgTypes, false), llvm::Function::ExternalLinkage, "stack_get", getModule());
auto rt = &func->getArgumentList().front();
rt->setName("rt");
auto index = rt->getNextNode();
index->setName("index");
auto jmpBuf = index->getNextNode();
jmpBuf->setName("jmpBuf");
InsertPointGuard guard{m_builder};
auto entryBB = llvm::BasicBlock::Create(m_builder.getContext(), {}, func);
@ -84,10 +90,10 @@ llvm::Function* Stack::getGetFunc()
m_builder.SetInsertPoint(entryBB);
auto valuePtr = createCall(extGetFunc, {rt, index});
auto ok = m_builder.CreateICmpNE(valuePtr, llvm::ConstantPointerNull::get(Type::WordPtr));
m_builder.CreateCondBr(ok, returnBB, underflowBB);
m_builder.CreateCondBr(ok, returnBB, underflowBB); //TODO: Add branch weight
m_builder.SetInsertPoint(underflowBB);
m_runtimeManager.raiseException(ReturnCode::StackTooSmall);
m_runtimeManager.abort(jmpBuf);
m_builder.CreateUnreachable();
m_builder.SetInsertPoint(returnBB);
@ -98,7 +104,7 @@ llvm::Function* Stack::getGetFunc()
llvm::Value* Stack::get(size_t _index)
{
auto valuePtr = createCall(getGetFunc(), {m_runtimeManager.getRuntimePtr(), m_builder.getInt64(_index)});
auto valuePtr = createCall(getGetFunc(), {m_runtimeManager.getRuntimePtr(), m_builder.getInt64(_index), m_runtimeManager.getJmpBuf()});
return m_builder.CreateLoad(valuePtr);
}
@ -110,7 +116,7 @@ void Stack::set(size_t _index, llvm::Value* _value)
void Stack::pop(size_t _count)
{
createCall(getPopFunc(), {m_runtimeManager.getRuntimePtr(), m_builder.getInt64(_count)});
createCall(getPopFunc(), {m_runtimeManager.getRuntimePtr(), m_builder.getInt64(_count), m_runtimeManager.getJmpBuf()});
}
void Stack::push(llvm::Value* _value)

Loading…
Cancel
Save