Browse Source

Remove global privite pointers to runtime instance and runtime data

cl-refactor
Paweł Bylica 10 years ago
parent
commit
f8ffdfa30c
  1. 16
      libevmjit/Ext.cpp
  2. 18
      libevmjit/GasMeter.cpp
  3. 34
      libevmjit/Memory.cpp
  4. 2
      libevmjit/Memory.h
  5. 41
      libevmjit/RuntimeManager.cpp
  6. 7
      libevmjit/RuntimeManager.h

16
libevmjit/Ext.cpp

@ -69,7 +69,7 @@ Ext::Ext(RuntimeManager& _runtimeManager, Memory& _memoryMan):
llvm::Value* Ext::sload(llvm::Value* _index) llvm::Value* Ext::sload(llvm::Value* _index)
{ {
m_builder.CreateStore(_index, m_args[0]); m_builder.CreateStore(_index, m_args[0]);
m_builder.CreateCall3(m_sload, getRuntimeManager().getEnv(), m_args[0], m_args[1]); // Uses native endianness m_builder.CreateCall3(m_sload, getRuntimeManager().getEnvPtr(), m_args[0], m_args[1]); // Uses native endianness
return m_builder.CreateLoad(m_args[1]); return m_builder.CreateLoad(m_args[1]);
} }
@ -77,7 +77,7 @@ void Ext::sstore(llvm::Value* _index, llvm::Value* _value)
{ {
m_builder.CreateStore(_index, m_args[0]); m_builder.CreateStore(_index, m_args[0]);
m_builder.CreateStore(_value, m_args[1]); m_builder.CreateStore(_value, m_args[1]);
m_builder.CreateCall3(m_sstore, getRuntimeManager().getEnv(), m_args[0], m_args[1]); // Uses native endianness m_builder.CreateCall3(m_sstore, getRuntimeManager().getEnvPtr(), m_args[0], m_args[1]); // Uses native endianness
} }
llvm::Value* Ext::calldataload(llvm::Value* _index) llvm::Value* Ext::calldataload(llvm::Value* _index)
@ -92,7 +92,7 @@ llvm::Value* Ext::balance(llvm::Value* _address)
{ {
auto address = Endianness::toBE(m_builder, _address); auto address = Endianness::toBE(m_builder, _address);
m_builder.CreateStore(address, m_args[0]); m_builder.CreateStore(address, m_args[0]);
m_builder.CreateCall3(m_balance, getRuntimeManager().getEnv(), m_args[0], m_args[1]); m_builder.CreateCall3(m_balance, getRuntimeManager().getEnvPtr(), m_args[0], m_args[1]);
return m_builder.CreateLoad(m_args[1]); return m_builder.CreateLoad(m_args[1]);
} }
@ -100,7 +100,7 @@ void Ext::suicide(llvm::Value* _address)
{ {
auto address = Endianness::toBE(m_builder, _address); auto address = Endianness::toBE(m_builder, _address);
m_builder.CreateStore(address, m_args[0]); m_builder.CreateStore(address, m_args[0]);
m_builder.CreateCall2(m_suicide, getRuntimeManager().getEnv(), m_args[0]); m_builder.CreateCall2(m_suicide, getRuntimeManager().getEnvPtr(), m_args[0]);
} }
llvm::Value* Ext::create(llvm::Value*& _gas, llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* _initSize) llvm::Value* Ext::create(llvm::Value*& _gas, llvm::Value* _endowment, llvm::Value* _initOff, llvm::Value* _initSize)
@ -109,7 +109,7 @@ llvm::Value* Ext::create(llvm::Value*& _gas, llvm::Value* _endowment, llvm::Valu
m_builder.CreateStore(_endowment, m_arg2); m_builder.CreateStore(_endowment, m_arg2);
auto begin = m_memoryMan.getBytePtr(_initOff); auto begin = m_memoryMan.getBytePtr(_initOff);
auto size = m_builder.CreateTrunc(_initSize, Type::Size, "size"); auto size = m_builder.CreateTrunc(_initSize, Type::Size, "size");
createCall(m_create, getRuntimeManager().getEnv(), m_args[0], m_arg2, begin, size, m_args[1]); createCall(m_create, getRuntimeManager().getEnvPtr(), m_args[0], m_arg2, begin, size, m_args[1]);
_gas = m_builder.CreateLoad(m_args[0]); // Return gas _gas = m_builder.CreateLoad(m_args[0]); // Return gas
llvm::Value* address = m_builder.CreateLoad(m_args[1]); llvm::Value* address = m_builder.CreateLoad(m_args[1]);
address = Endianness::toNative(m_builder, address); address = Endianness::toNative(m_builder, address);
@ -128,7 +128,7 @@ llvm::Value* Ext::call(llvm::Value*& _gas, llvm::Value* _receiveAddress, llvm::V
auto outSize = m_builder.CreateTrunc(_outSize, Type::Size, "out.size"); auto outSize = m_builder.CreateTrunc(_outSize, Type::Size, "out.size");
auto codeAddress = Endianness::toBE(m_builder, _codeAddress); auto codeAddress = Endianness::toBE(m_builder, _codeAddress);
m_builder.CreateStore(codeAddress, m_arg8); m_builder.CreateStore(codeAddress, m_arg8);
auto ret = createCall(m_call, getRuntimeManager().getEnv(), m_args[0], m_arg2, m_arg3, inBeg, inSize, outBeg, outSize, m_arg8); auto ret = createCall(m_call, getRuntimeManager().getEnvPtr(), m_args[0], m_arg2, m_arg3, inBeg, inSize, outBeg, outSize, m_arg8);
_gas = m_builder.CreateLoad(m_args[0]); // Return gas _gas = m_builder.CreateLoad(m_args[0]); // Return gas
return m_builder.CreateZExt(ret, Type::Word, "ret"); return m_builder.CreateZExt(ret, Type::Word, "ret");
} }
@ -147,7 +147,7 @@ MemoryRef Ext::getExtCode(llvm::Value* _addr)
{ {
auto addr = Endianness::toBE(m_builder, _addr); auto addr = Endianness::toBE(m_builder, _addr);
m_builder.CreateStore(addr, m_args[0]); m_builder.CreateStore(addr, m_args[0]);
auto code = createCall(m_getExtCode, getRuntimeManager().getEnv(), m_args[0], m_size); auto code = createCall(m_getExtCode, getRuntimeManager().getEnvPtr(), m_args[0], m_size);
auto codeSize = m_builder.CreateLoad(m_size); auto codeSize = m_builder.CreateLoad(m_size);
auto codeSize256 = m_builder.CreateZExt(codeSize, Type::Word); auto codeSize256 = m_builder.CreateZExt(codeSize, Type::Word);
return {code, codeSize256}; return {code, codeSize256};
@ -157,7 +157,7 @@ void Ext::log(llvm::Value* _memIdx, llvm::Value* _numBytes, std::array<llvm::Val
{ {
auto begin = m_memoryMan.getBytePtr(_memIdx); auto begin = m_memoryMan.getBytePtr(_memIdx);
auto size = m_builder.CreateTrunc(_numBytes, Type::Size, "size"); auto size = m_builder.CreateTrunc(_numBytes, Type::Size, "size");
llvm::Value* args[] = {getRuntimeManager().getEnv(), begin, size, m_arg2, m_arg3, m_arg4, m_arg5}; llvm::Value* args[] = {getRuntimeManager().getEnvPtr(), begin, size, m_arg2, m_arg3, m_arg4, m_arg5};
auto topicArgPtr = &args[3]; auto topicArgPtr = &args[3];
for (auto&& topic : _topics) for (auto&& topic : _topics)

18
libevmjit/GasMeter.cpp

@ -86,7 +86,8 @@ GasMeter::GasMeter(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager)
{ {
auto module = getModule(); auto module = getModule();
m_gasCheckFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Void, Type::Word, false), llvm::Function::PrivateLinkage, "gas.check", module); llvm::Type* gasCheckArgs[] = {Type::RuntimePtr, Type::Word};
m_gasCheckFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Void, gasCheckArgs, false), llvm::Function::PrivateLinkage, "gas.check", module);
InsertPointGuard guard(m_builder); InsertPointGuard guard(m_builder);
auto checkBB = llvm::BasicBlock::Create(_builder.getContext(), "Check", m_gasCheckFunc); auto checkBB = llvm::BasicBlock::Create(_builder.getContext(), "Check", m_gasCheckFunc);
@ -94,14 +95,17 @@ GasMeter::GasMeter(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager)
auto updateBB = llvm::BasicBlock::Create(_builder.getContext(), "Update", m_gasCheckFunc); auto updateBB = llvm::BasicBlock::Create(_builder.getContext(), "Update", m_gasCheckFunc);
m_builder.SetInsertPoint(checkBB); m_builder.SetInsertPoint(checkBB);
llvm::Value* cost = m_gasCheckFunc->arg_begin(); auto arg = m_gasCheckFunc->arg_begin();
cost->setName("cost"); arg->setName("rt");
++arg;
arg->setName("cost");
auto cost = arg;
auto gas = m_runtimeManager.getGas(); auto gas = m_runtimeManager.getGas();
auto isOutOfGas = m_builder.CreateICmpUGT(cost, gas, "isOutOfGas"); auto isOutOfGas = m_builder.CreateICmpUGT(cost, gas, "isOutOfGas");
m_builder.CreateCondBr(isOutOfGas, outOfGasBB, updateBB); m_builder.CreateCondBr(isOutOfGas, outOfGasBB, updateBB);
m_builder.SetInsertPoint(outOfGasBB); m_builder.SetInsertPoint(outOfGasBB);
_runtimeManager.raiseException(ReturnCode::OutOfGas); m_runtimeManager.raiseException(ReturnCode::OutOfGas);
m_builder.CreateUnreachable(); m_builder.CreateUnreachable();
m_builder.SetInsertPoint(updateBB); m_builder.SetInsertPoint(updateBB);
@ -115,7 +119,7 @@ void GasMeter::count(Instruction _inst)
if (!m_checkCall) if (!m_checkCall)
{ {
// Create gas check call with mocked block cost at begining of current cost-block // Create gas check call with mocked block cost at begining of current cost-block
m_checkCall = m_builder.CreateCall(m_gasCheckFunc, llvm::UndefValue::get(Type::Word)); m_checkCall = createCall(m_gasCheckFunc, m_runtimeManager.getRuntimePtr(), llvm::UndefValue::get(Type::Word));
} }
m_blockCost += getStepCost(_inst); m_blockCost += getStepCost(_inst);
@ -123,7 +127,7 @@ void GasMeter::count(Instruction _inst)
void GasMeter::count(llvm::Value* _cost) void GasMeter::count(llvm::Value* _cost)
{ {
createCall(m_gasCheckFunc, _cost); createCall(m_gasCheckFunc, m_runtimeManager.getRuntimePtr(), _cost);
} }
void GasMeter::countExp(llvm::Value* _exponent) void GasMeter::countExp(llvm::Value* _exponent)
@ -193,7 +197,7 @@ void GasMeter::commitCostBlock()
return; return;
} }
m_checkCall->setArgOperand(0, Constant::get(m_blockCost)); // Update block cost in gas check call m_checkCall->setArgOperand(1, Constant::get(m_blockCost)); // Update block cost in gas check call
m_checkCall = nullptr; // End cost-block m_checkCall = nullptr; // End cost-block
m_blockCost = 0; m_blockCost = 0;
} }

34
libevmjit/Memory.cpp

@ -24,7 +24,7 @@ namespace jit
{ {
Memory::Memory(RuntimeManager& _runtimeManager, GasMeter& _gasMeter): Memory::Memory(RuntimeManager& _runtimeManager, GasMeter& _gasMeter):
RuntimeHelper(_runtimeManager), RuntimeHelper(_runtimeManager), // TODO: RuntimeHelper not needed
m_gasMeter(_gasMeter) m_gasMeter(_gasMeter)
{ {
auto module = getModule(); auto module = getModule();
@ -45,17 +45,19 @@ Memory::Memory(RuntimeManager& _runtimeManager, GasMeter& _gasMeter):
attrBuilder.addAttribute(llvm::Attribute::NoAlias).addAttribute(llvm::Attribute::NoCapture).addAttribute(llvm::Attribute::NonNull).addAttribute(llvm::Attribute::ReadOnly); attrBuilder.addAttribute(llvm::Attribute::NoAlias).addAttribute(llvm::Attribute::NoCapture).addAttribute(llvm::Attribute::NonNull).addAttribute(llvm::Attribute::ReadOnly);
m_resize->setAttributes(llvm::AttributeSet::get(m_resize->getContext(), 1, attrBuilder)); m_resize->setAttributes(llvm::AttributeSet::get(m_resize->getContext(), 1, attrBuilder));
m_require = createRequireFunc(_gasMeter, _runtimeManager); m_require = createRequireFunc(_gasMeter);
m_loadWord = createFunc(false, Type::Word, _gasMeter); m_loadWord = createFunc(false, Type::Word, _gasMeter);
m_storeWord = createFunc(true, Type::Word, _gasMeter); m_storeWord = createFunc(true, Type::Word, _gasMeter);
m_storeByte = createFunc(true, Type::Byte, _gasMeter); m_storeByte = createFunc(true, Type::Byte, _gasMeter);
} }
llvm::Function* Memory::createRequireFunc(GasMeter& _gasMeter, RuntimeManager& _runtimeManager) llvm::Function* Memory::createRequireFunc(GasMeter& _gasMeter)
{ {
llvm::Type* argTypes[] = {Type::Word, Type::Word}; llvm::Type* argTypes[] = {Type::RuntimePtr, Type::Word, Type::Word};
auto func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::PrivateLinkage, "mem.require", getModule()); auto func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::PrivateLinkage, "mem.require", getModule());
auto offset = func->arg_begin(); auto rt = func->arg_begin();
rt->setName("rt");
auto offset = rt->getNextNode();
offset->setName("offset"); offset->setName("offset");
auto size = offset->getNextNode(); auto size = offset->getNextNode();
size->setName("size"); size->setName("size");
@ -98,7 +100,7 @@ llvm::Function* Memory::createRequireFunc(GasMeter& _gasMeter, RuntimeManager& _
_gasMeter.countMemory(newWords); _gasMeter.countMemory(newWords);
// Resize // Resize
m_builder.CreateStore(sizeRequired, m_size); m_builder.CreateStore(sizeRequired, m_size);
auto newData = m_builder.CreateCall2(m_resize, _runtimeManager.getRuntimePtr(), m_size, "newData"); auto newData = m_builder.CreateCall2(m_resize, rt, m_size, "newData");
m_builder.CreateStore(newData, m_data); m_builder.CreateStore(newData, m_data);
m_builder.CreateBr(returnBB); m_builder.CreateBr(returnBB);
@ -112,15 +114,18 @@ llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType, GasMet
{ {
auto isWord = _valueType == Type::Word; auto isWord = _valueType == Type::Word;
llvm::Type* storeArgs[] = {Type::Word, _valueType}; llvm::Type* storeArgs[] = {Type::RuntimePtr, Type::Word, _valueType};
llvm::Type* loadArgs[] = {Type::RuntimePtr, Type::Word};
auto name = _isStore ? isWord ? "mstore" : "mstore8" : "mload"; auto name = _isStore ? isWord ? "mstore" : "mstore8" : "mload";
auto funcType = _isStore ? llvm::FunctionType::get(Type::Void, storeArgs, false) : llvm::FunctionType::get(Type::Word, Type::Word, false); auto funcType = _isStore ? llvm::FunctionType::get(Type::Void, storeArgs, false) : llvm::FunctionType::get(Type::Word, loadArgs, false);
auto func = llvm::Function::Create(funcType, llvm::Function::PrivateLinkage, name, getModule()); auto func = llvm::Function::Create(funcType, llvm::Function::PrivateLinkage, name, getModule());
InsertPointGuard guard(m_builder); // Restores insert point at function exit InsertPointGuard guard(m_builder); // Restores insert point at function exit
m_builder.SetInsertPoint(llvm::BasicBlock::Create(func->getContext(), {}, func)); m_builder.SetInsertPoint(llvm::BasicBlock::Create(func->getContext(), {}, func));
llvm::Value* index = func->arg_begin(); auto rt = func->arg_begin();
rt->setName("rt");
auto index = rt->getNextNode();
index->setName("index"); index->setName("index");
auto valueSize = _valueType->getPrimitiveSizeInBits() / 8; auto valueSize = _valueType->getPrimitiveSizeInBits() / 8;
@ -130,7 +135,7 @@ llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType, GasMet
ptr = m_builder.CreateBitCast(ptr, Type::WordPtr, "wordPtr"); ptr = m_builder.CreateBitCast(ptr, Type::WordPtr, "wordPtr");
if (_isStore) if (_isStore)
{ {
llvm::Value* value = ++func->arg_begin(); llvm::Value* value = index->getNextNode();
value->setName("value"); value->setName("value");
if (isWord) if (isWord)
value = Endianness::toBE(m_builder, value); value = Endianness::toBE(m_builder, value);
@ -150,19 +155,18 @@ llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType, GasMet
llvm::Value* Memory::loadWord(llvm::Value* _addr) llvm::Value* Memory::loadWord(llvm::Value* _addr)
{ {
auto value = m_builder.CreateCall(m_loadWord, _addr); return createCall(m_loadWord, getRuntimeManager().getRuntimePtr(), _addr);
return value;
} }
void Memory::storeWord(llvm::Value* _addr, llvm::Value* _word) void Memory::storeWord(llvm::Value* _addr, llvm::Value* _word)
{ {
m_builder.CreateCall2(m_storeWord, _addr, _word); createCall(m_storeWord, getRuntimeManager().getRuntimePtr(), _addr, _word);
} }
void Memory::storeByte(llvm::Value* _addr, llvm::Value* _word) void Memory::storeByte(llvm::Value* _addr, llvm::Value* _word)
{ {
auto byte = m_builder.CreateTrunc(_word, Type::Byte, "byte"); auto byte = m_builder.CreateTrunc(_word, Type::Byte, "byte");
m_builder.CreateCall2(m_storeByte, _addr, byte); createCall(m_storeByte, getRuntimeManager().getRuntimePtr(), _addr, byte);
} }
llvm::Value* Memory::getData() llvm::Value* Memory::getData()
@ -183,7 +187,7 @@ llvm::Value* Memory::getBytePtr(llvm::Value* _index)
void Memory::require(llvm::Value* _offset, llvm::Value* _size) void Memory::require(llvm::Value* _offset, llvm::Value* _size)
{ {
m_builder.CreateCall2(m_require, _offset, _size); createCall(m_require, getRuntimeManager().getRuntimePtr(), _offset, _size);
} }
void Memory::copyBytes(llvm::Value* _srcPtr, llvm::Value* _srcSize, llvm::Value* _srcIdx, void Memory::copyBytes(llvm::Value* _srcPtr, llvm::Value* _srcSize, llvm::Value* _srcIdx,

2
libevmjit/Memory.h

@ -31,7 +31,7 @@ private:
GasMeter& m_gasMeter; GasMeter& m_gasMeter;
llvm::Function* createFunc(bool _isStore, llvm::Type* _type, GasMeter& _gasMeter); llvm::Function* createFunc(bool _isStore, llvm::Type* _type, GasMeter& _gasMeter);
llvm::Function* createRequireFunc(GasMeter& _gasMeter, RuntimeManager& _runtimeManager); llvm::Function* createRequireFunc(GasMeter& _gasMeter);
llvm::GlobalVariable* m_data; llvm::GlobalVariable* m_data;
llvm::GlobalVariable* m_size; llvm::GlobalVariable* m_size;

41
libevmjit/RuntimeManager.cpp

@ -74,43 +74,38 @@ llvm::Twine getName(RuntimeData::Index _index)
RuntimeManager::RuntimeManager(llvm::IRBuilder<>& _builder): CompilerHelper(_builder) RuntimeManager::RuntimeManager(llvm::IRBuilder<>& _builder): CompilerHelper(_builder)
{ {
m_rtPtr = new llvm::GlobalVariable(*getModule(), Type::RuntimePtr, false, llvm::GlobalVariable::PrivateLinkage, llvm::UndefValue::get(Type::RuntimePtr), "rt");
m_dataPtr = new llvm::GlobalVariable(*getModule(), Type::RuntimeDataPtr, false, llvm::GlobalVariable::PrivateLinkage, llvm::UndefValue::get(Type::RuntimeDataPtr), "data");
m_longjmp = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::longjmp); m_longjmp = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::longjmp);
// Export data // Unpack data
auto mainFunc = getMainFunction(); auto rtPtr = getRuntimePtr();
llvm::Value* rtPtr = &mainFunc->getArgumentList().front(); m_dataPtr = m_builder.CreateLoad(m_builder.CreateStructGEP(rtPtr, 0), "data");
m_builder.CreateStore(rtPtr, m_rtPtr); assert(m_dataPtr->getType() == Type::RuntimeDataPtr);
auto dataPtr = m_builder.CreateStructGEP(rtPtr, 0, "dataPtr"); m_envPtr = m_builder.CreateLoad(m_builder.CreateStructGEP(rtPtr, 1), "env");
auto data = m_builder.CreateLoad(dataPtr, "data"); assert(m_envPtr->getType() == Type::EnvPtr);
m_builder.CreateStore(data, m_dataPtr);
auto envPtr = m_builder.CreateStructGEP(rtPtr, 1, "envPtr");
m_env = m_builder.CreateLoad(envPtr, "env");
assert(m_env->getType() == Type::EnvPtr);
} }
llvm::Value* RuntimeManager::getRuntimePtr() llvm::Value* RuntimeManager::getRuntimePtr()
{ {
// FIXME: Data ptr // Expect first argument of a function to be a pointer to Runtime
//if (auto mainFunc = getMainFunction()) auto func = m_builder.GetInsertBlock()->getParent();
// return mainFunc->arg_begin(); // Runtime is the parameter of main function auto rtPtr = &func->getArgumentList().front();
return m_builder.CreateLoad(m_rtPtr, "rt"); assert(rtPtr->getType() == Type::RuntimePtr);
return rtPtr;
} }
llvm::Value* RuntimeManager::getDataPtr() llvm::Value* RuntimeManager::getDataPtr()
{ {
// FIXME: Data ptr if (getMainFunction())
//if (auto mainFunc = getMainFunction()) return m_dataPtr;
// return mainFunc->arg_begin(); // Runtime is the parameter of main function
return m_builder.CreateLoad(m_dataPtr, "data"); auto rtPtr = getRuntimePtr();
return m_builder.CreateLoad(m_builder.CreateStructGEP(rtPtr, 0), "data");
} }
llvm::Value* RuntimeManager::getEnv() llvm::Value* RuntimeManager::getEnvPtr()
{ {
assert(getMainFunction()); // Available only in main function assert(getMainFunction()); // Available only in main function
return m_env; return m_envPtr;
} }
llvm::Value* RuntimeManager::getPtr(RuntimeData::Index _index) llvm::Value* RuntimeManager::getPtr(RuntimeData::Index _index)

7
libevmjit/RuntimeManager.h

@ -19,7 +19,7 @@ public:
llvm::Value* getRuntimePtr(); llvm::Value* getRuntimePtr();
llvm::Value* getDataPtr(); llvm::Value* getDataPtr();
llvm::Value* getEnv(); llvm::Value* getEnvPtr(); // TODO: Can we make it const?
llvm::Value* get(RuntimeData::Index _index); llvm::Value* get(RuntimeData::Index _index);
llvm::Value* get(Instruction _inst); llvm::Value* get(Instruction _inst);
@ -40,10 +40,9 @@ private:
void set(RuntimeData::Index _index, llvm::Value* _value); void set(RuntimeData::Index _index, llvm::Value* _value);
llvm::Value* getJmpBuf(); llvm::Value* getJmpBuf();
llvm::GlobalVariable* m_rtPtr = nullptr;
llvm::GlobalVariable* m_dataPtr = nullptr;
llvm::Function* m_longjmp = nullptr; llvm::Function* m_longjmp = nullptr;
llvm::Value* m_env = nullptr; llvm::Value* m_dataPtr = nullptr;
llvm::Value* m_envPtr = nullptr;
}; };
} }

Loading…
Cancel
Save